From d883312fad2e97fd49beb3de27f2a4536b466ec5 Mon Sep 17 00:00:00 2001 From: Thibaut Lienart Date: Mon, 27 May 2019 12:21:24 +1000 Subject: [PATCH 1/4] servedocs: kw for extra files --- src/utils.jl | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/utils.jl b/src/utils.jl index 3aa1fb9..7ff9fc7 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -38,12 +38,14 @@ function servedocs_callback(fp::AbstractString, vwf::Vector{WatchedFile}, makejl end """ - scan_docs!(dw::SimpleWatcher) + scan_docs!(dw::SimpleWatcher, files=String[]) Scans the `docs/` folder in order to recover the path to all files that have to be watched and add -those files to `dw.watchedfiles`. The function returns the path to `docs/make.jl`. +those files to `dw.watchedfiles`. The function returns the path to `docs/make.jl`. A list of +file paths can also be given for files that should be watched in addition to the content of +`docs/src`. This is useful in the context of Literate.jl. """ -function scan_docs!(dw::SimpleWatcher) +function scan_docs!(dw::SimpleWatcher, files::Vector{String}=String[]) src = joinpath("docs", "src") if !(isdir("docs") && isdir(src)) @error "I didn't find a docs/ or docs/src/ folder." @@ -56,26 +58,31 @@ function scan_docs!(dw::SimpleWatcher) push!(dw.watchedfiles, WatchedFile(joinpath(root, file))) end end + for fpath ∈ files + isfile(fpath) && push!(dw.watchedfiles, WatchedFile(fpath)) + end return makejl end """ - servedocs(; verbose=false) + servedocs(; verbose=false, files=[]) Can be used when developing a package to run the `docs/make.jl` file from Documenter.jl and then serve the `docs/build` folder with LiveServer.jl. This function assumes you are in the directory `[MyPackage].jl` with a subfolder `docs`. -* `verbose` is a boolean switch to make the server print information about file changes and connections. +* `verbose` is a boolean switch to make the server print information about file changes and +connections. +* `files` is a vector of file paths that can be watched in addition of the content of `docs/src`. """ -function servedocs(; verbose::Bool=false) +function servedocs(; verbose::Bool=false, files::Vector{String}=String[]) # Custom file watcher: it's the standard `SimpleWatcher` but with a custom callback. docwatcher = SimpleWatcher() set_callback!(docwatcher, fp->servedocs_callback(fp, docwatcher.watchedfiles, makejl)) - makejl = scan_docs!(docwatcher) + makejl = scan_docs!(docwatcher, files) - # trigger a first pass of Documenter + # trigger a first pass of Documenter (or Literate) Main.include(makejl) # note the `docs/build` exists here given that if we're here it means the documenter From fec308e76d37dfd7dad6fc77193d2d332980c086 Mon Sep 17 00:00:00 2001 From: Thibaut Lienart Date: Mon, 27 May 2019 12:28:35 +1000 Subject: [PATCH 2/4] servedocs: tests for kw for extra files --- test/utils.jl | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/utils.jl b/test/utils.jl index 285be4a..1840a1d 100644 --- a/test/utils.jl +++ b/test/utils.jl @@ -60,14 +60,18 @@ end write(joinpath("docs", "src", "index2.md"), "Random file") write(joinpath("docs", "make.jl"), "1+1") + mkdir("alternate") + write(joinpath("alternate", "blah.md"), "1+1") + dw = LS.SimpleWatcher() - makejl = LS.scan_docs!(dw) + makejl = LS.scan_docs!(dw, [joinpath("alternate", "blah.md")]) @test makejl == joinpath("docs", "make.jl") - @test length(dw.watchedfiles) == 3 # index, index2, make + @test length(dw.watchedfiles) == 4 # index, index2, blah.md make @test endswith(dw.watchedfiles[1].path, "make.jl") @test endswith(dw.watchedfiles[2].path, "index.md") @test endswith(dw.watchedfiles[3].path, "index2.md") + @test endswith(dw.watchedfiles[4].path, "blah.md") cd(bk) end From d5ef1b288deaeb3ad4e3f9e615d856eaea90687c Mon Sep 17 00:00:00 2001 From: Thibaut Lienart Date: Mon, 27 May 2019 16:46:32 +1000 Subject: [PATCH 3/4] adds a few things to play nice with Literate + full example in docs --- docs/make.jl | 3 +- docs/src/assets/testlit.png | Bin 0 -> 35172 bytes docs/src/assets/testlit2.png | Bin 0 -> 34338 bytes docs/src/index.md | 2 + docs/src/lib/internals.md | 2 +- docs/src/man/ls+lit.md | 170 +++++++++++++++++++++++++++++++++++ src/utils.jl | 109 ++++++++++++++-------- test/utils.jl | 35 ++++---- 8 files changed, 263 insertions(+), 58 deletions(-) create mode 100644 docs/src/assets/testlit.png create mode 100644 docs/src/assets/testlit2.png create mode 100644 docs/src/man/ls+lit.md diff --git a/docs/make.jl b/docs/make.jl index e4bdc7b..d195787 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -14,7 +14,8 @@ makedocs( "Home" => "index.md", "Manual" => [ "Functionalities" => "man/functionalities.md", - "Extending LiveServer" => "man/extending_ls.md" + "Extending LiveServer" => "man/extending_ls.md", + "LiveServer + Literate" => "man/ls+lit.md" ], "Library" => [ "Public" => "lib/public.md", diff --git a/docs/src/assets/testlit.png b/docs/src/assets/testlit.png new file mode 100644 index 0000000000000000000000000000000000000000..e45c7e5ba42ece125530733cc5fd7c1fa4cf7836 GIT binary patch literal 35172 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 z
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 literal 0 HcmV?d00001 diff --git a/docs/src/index.md b/docs/src/index.md index 50b14e9..aa69043 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -49,6 +49,8 @@ julia> servedocs() Open a browser and go to `http://localhost:8000/` to see your docs being rendered; try modifying files (e.g. `docs/index.md`) and watch the changes being rendered in the browser. +You can also use LiveServer with both Documenter and [Literate.jl](https://github.com/fredrikekre/Literate.jl). +This is explained [here](man/ls+lit.md). ## How it works diff --git a/docs/src/lib/internals.md b/docs/src/lib/internals.md index 62c9059..56290c0 100644 --- a/docs/src/lib/internals.md +++ b/docs/src/lib/internals.md @@ -70,7 +70,7 @@ LiveServer.update_and_close_viewers! #### Helper functions associated with `servedocs` ```@docs -LiveServer.servedocs_callback +LiveServer.servedocs_callback! LiveServer.scan_docs! ``` diff --git a/docs/src/man/ls+lit.md b/docs/src/man/ls+lit.md new file mode 100644 index 0000000..e69c5a6 --- /dev/null +++ b/docs/src/man/ls+lit.md @@ -0,0 +1,170 @@ +# LiveServer + Literate + +(_Thanks to [Fredrik Ekre](https://github.com/fredrikekre) and [Benoit Pasquier](https://github.com/briochemc) for their input; a lot of this section is drawn from an early prototype suggested by Fredrik._) + +You've likely already seen how LiveServer could be used along with Documenter to have live updating documentation (see [`servedocs`](/man/functionalities/#servedocs-1) if not). + +It is also easy to use LiveServer with both Documenter and [Literate.jl](https://github.com/fredrikekre/Literate.jl), a package for literate programming written by Fredrik Ekre that can convert julia script files into markdown. +This can be particularly convenient for documentation pages with a lot of code examples. + +Only two steps are required to have this working (assuming you have already added Literate to your environment): + +1. pick a folder structure +1. modify the `docs/make.jl` file to contain a line calling Literate + +### Folder structure + +There are effectively two recommended ways, pick whichever one you prefer. +In the first case, the script files `.jl` to be compiled by Literate are at the _same location_ as the output file so that you would have: + +``` +docs +└── src + ├── index.jl + └── index.md +``` + +if you're happy with this, then you can jump to the [next step](#Modifying-the-make-file-1) to change the make file. + +However you may not be happy with this, in particular if you have lots of such files and a mix of files which are generated by `Literate` and some which aren't, then typically you might prefer to keep all scripts in a separate folder. +You would just have to make sure that the output is properly redirected to `docs/src`. +Your folder structure would then look something like: + +``` +docs +├── lit +│   └── index.jl +└── src + └── index.md +``` + +The only thing you have to do in this case is to specify to `servedocs` where the "literate folder" is; this is a keyword argument and for the example above we would have: + +```julia +servedocs(literate=joinpath("docs", "lit")) +``` + +### Modifying the make file + +The only thing you have to do here is add a few lines to specify which files should be compiled by `Literate`. +Assuming you have taken the second path in the situation above, your `make.jl` file should look like: + +```julia +using Documenter, Literate + +src = joinpath(@__DIR__, "src") +lit = joinpath(@__DIR__, "lit") + +for (root, _, files) ∈ walkdir(lit), file ∈ files + splitext(file)[2] == ".jl" || continue + ipath = joinpath(root, file) + opath = splitdir(replace(ipath, lit=>src))[1] + Literate.markdown(ipath, opath) +end + +makedocs( + sitename = "Test", + modules = [Test], + pages = ["Home" => "index.md"] + ) +``` + +If you were happy with the `.jl` and `.md` files being in the same location, simply replace the `lit = ` line by + +```julia +lit = src +``` + +What the for loop does is simple: it loops over the files in the folder where it's likely to encounter `.jl` files and for those it encounters: + +1. it retrieves the path to the file (`ipath`) +1. it constructs the output path in `docs/src` (`opath`) +1. it compiles the file `ipath` and saves the output at `opath` + +## Complete example + +Here's a step-by-step example to get started which should help put all the pieces together. + +Let's start by creating a dummy repo + +```julia-repl +pkg> generate testlit +julia> cd("testlit") +pkg> activate testlit +pkg> add Documenter Literate LiveServer +pkg> dev . +``` + +add a `docs/` folder with the appropriate structure so that the `testlit` folder ends up like + +``` +. +├── Manifest.toml +├── Project.toml +├── docs +│   ├── literate +│   │   └── man +│   │   └── pg1.jl +│   ├── make.jl +│   └── src +│   ├── index.md +│   └── man +└── src + └── testlit.jl +``` + +where the file `pg1.jl` contains + +```julia +# # Test literate + +# We can include some code like so: + +f(x) = x^5 +f(5) +``` + +the file `index.md` contains + +``` +# Test + +A link to the [other page](/man/pg1.md) +``` + +and the file `make.jl` contains + +```julia +using Documenter, Literate + +src = joinpath(@__DIR__, "src") +lit = joinpath(@__DIR__, "literate") + +for (root, _, files) ∈ walkdir(lit), file ∈ files + splitext(file)[2] == ".jl" || continue + ipath = joinpath(root, file) + opath = splitdir(replace(ipath, lit=>src))[1] + Literate.markdown(ipath, opath) +end + +makedocs( + sitename = "testlit", + modules = [testlit], + pages = ["Home" => "index.md", + "Other page" => "man/pg1.md"] + ) +``` + +Now `cd("testlit/")` and do + +```julia-repl +julia> servedocs(literate=joinpath("docs", "literate")) +``` + +if you navigate to `localhost:8000` you should end up with + +![](/assets/testlit.png) + +if you modify `testlit/docs/literate/man/pg1.jl` for instance writing `f(4)` it will be applied directly: + +![](/assets/testlit2.png) diff --git a/src/utils.jl b/src/utils.jl index 7ff9fc7..f3432c5 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -1,5 +1,5 @@ """ - servedocs_callback(filepath, watchedfiles, path2makejl) + servedocs_callback!(docwatcher, filepath, path2makejl, literate) Custom callback used in [`servedocs`](@ref) triggered when the file corresponding to `filepath` is changed. If that file is `docs/make.jl`, the callback will check whether any new files have @@ -9,43 +9,31 @@ Otherwise, if the modified file is in `docs/src` or is `docs/make.jl`, a pass of triggered to regenerate the documents, subsequently the LiveServer will render the produced pages in `docs/build`. """ -function servedocs_callback(fp::AbstractString, vwf::Vector{WatchedFile}, makejl::AbstractString) - ismakejl = (fp == makejl) - # if the file that was changed is the `make.jl` file, - # assume that maybe new files are referenced and so refresh the - # vector of watched files as a result. - if ismakejl - watchedpaths = (wf.path for wf ∈ vwf) - for (root, _, files) ∈ walkdir(joinpath("docs", "src")), file ∈ files - fpath = joinpath(root, file) - fpath ∈ watchedpaths || push!(vwf, WatchedFile(fpath)) - end - # check if any file that was watched has died - deadfiles = Int[] - for (i, wf) ∈ enumerate(vwf) - isfile(wf.path) || push!(deadfiles, i) - end - deleteat!(vwf, deadfiles) +function servedocs_callback!(dw::SimpleWatcher, fp::AbstractString, makejl::AbstractString, + literate::String="") + # if the file that was changed is the `make.jl` file, assume that maybe new files are # referenced and so refresh the vector of watched files as a result. + if fp == makejl + # it's easier to start from scratch (takes negligible time) + empty!(dw.watchedfiles) + scan_docs!(dw, literate) end - # only trigger for changes appearing in `docs/src` otherwise a loop gets triggered - # changes from docs/src create change in docs/build which trigger a pass which - # regenerates files in docs/build etc... - if ismakejl || occursin(joinpath("docs", "src"), fp) + if splitext(fp)[2] ∈ (".md", ".jl") Main.include(makejl) file_changed_callback(fp) end return nothing end + """ - scan_docs!(dw::SimpleWatcher, files=String[]) + scan_docs!(dw::SimpleWatcher, literate="") Scans the `docs/` folder in order to recover the path to all files that have to be watched and add those files to `dw.watchedfiles`. The function returns the path to `docs/make.jl`. A list of -file paths can also be given for files that should be watched in addition to the content of -`docs/src`. This is useful in the context of Literate.jl. +folders and file paths can also be given for files that should be watched in addition to the +content of `docs/src`. """ -function scan_docs!(dw::SimpleWatcher, files::Vector{String}=String[]) +function scan_docs!(dw::SimpleWatcher, literate::String="") src = joinpath("docs", "src") if !(isdir("docs") && isdir(src)) @error "I didn't find a docs/ or docs/src/ folder." @@ -53,19 +41,59 @@ function scan_docs!(dw::SimpleWatcher, files::Vector{String}=String[]) makejl = joinpath("docs", "make.jl") push!(dw.watchedfiles, WatchedFile(makejl)) if isdir("docs") - # add all files in `docs/src` to watched files - for (root, _, files) ∈ walkdir(joinpath("docs", "src")), file ∈ files - push!(dw.watchedfiles, WatchedFile(joinpath(root, file))) - end + # add all files in `docs/src` to watched files + for (root, _, files) ∈ walkdir(joinpath("docs", "src")), file ∈ files + push!(dw.watchedfiles, WatchedFile(joinpath(root, file))) + end end - for fpath ∈ files - isfile(fpath) && push!(dw.watchedfiles, WatchedFile(fpath)) + if !isempty(literate) + isdir(literate) || @error "I didn't find the provided literate folder $literate." + for (root, _, files) ∈ walkdir(literate), file ∈ files + push!(dw.watchedfiles, WatchedFile(joinpath(root, file))) + end end + + # When using literate.jl, we should only watch the source file otherwise we would double + # trigger: first when the script.jl is modified then again when the script.md is created + # which would cause an infinite loop if both `script.jl` and `script.md` are watched. + # So here we remove from the watchlist all files.md that have a files.jl with the same path. + remove = Int[] + if isempty(literate) + # assumption is that the scripts are in `docs/src/...` and that the generated markdown + # goes in exactly the same spot so for instance: + # docs + # └── src + # ├── index.jl + # └── index.md + for wf ∈ dw.watchedfiles + spath = splitext(wf.path) + spath[2] == ".jl" || continue + k = findfirst(e -> splitext(e.path) == (spath[1], ".md"), dw.watchedfiles) + isnothing(k) || push!(remove, k) + end + else + # assumption is that the scripts are in `literate/` and that the generated markdown goes + # in `docs/src` with the same relative paths so for instance: + # docs + # ├── lit + # │   └── index.jl + # └── src + # └── index.md + for (root, _, files) ∈ walkdir(literate), file ∈ files + spath = splitext(joinpath(root, file)) + spath[2] == ".jl" || continue + path = replace(spath[1], Regex("^$literate") => joinpath("docs", "src")) + k = findfirst(e -> splitext(e.path) == (path, ".md"), dw.watchedfiles) + isnothing(k) || push!(remove, k) + end + end + deleteat!(dw.watchedfiles, remove) return makejl end + """ - servedocs(; verbose=false, files=[]) + servedocs(; verbose=false, literate="") Can be used when developing a package to run the `docs/make.jl` file from Documenter.jl and then serve the `docs/build` folder with LiveServer.jl. This function assumes you are in the @@ -73,25 +101,27 @@ directory `[MyPackage].jl` with a subfolder `docs`. * `verbose` is a boolean switch to make the server print information about file changes and connections. -* `files` is a vector of file paths that can be watched in addition of the content of `docs/src`. +* `literate` is the path to the folder containing the literate scripts, if left empty, it will be +assumed that they are in `docs/src`. """ -function servedocs(; verbose::Bool=false, files::Vector{String}=String[]) +function servedocs(; verbose::Bool=false, literate::String="") # Custom file watcher: it's the standard `SimpleWatcher` but with a custom callback. docwatcher = SimpleWatcher() - set_callback!(docwatcher, fp->servedocs_callback(fp, docwatcher.watchedfiles, makejl)) + set_callback!(docwatcher, fp->servedocs_callback!(docwatcher, fp, makejl, literate)) - makejl = scan_docs!(docwatcher, files) + # Retrieve files to watch + makejl = scan_docs!(docwatcher, literate) - # trigger a first pass of Documenter (or Literate) + # trigger a first pass of Documenter (& possibly Literate) Main.include(makejl) # note the `docs/build` exists here given that if we're here it means the documenter # pass did not error and therefore that a docs/build has been generated. serve(docwatcher, dir=joinpath("docs", "build"), verbose=verbose) - return nothing end + # # Miscellaneous utils # @@ -103,6 +133,7 @@ Set the verbosity of LiveServer to either `true` (showing messages upon events) """ setverbose(b::Bool) = (VERBOSE.x = b) + """ example() diff --git a/test/utils.jl b/test/utils.jl index 1840a1d..a64836b 100644 --- a/test/utils.jl +++ b/test/utils.jl @@ -21,30 +21,32 @@ @test readmake() == 1 # callback function - vwf = Vector{LS.WatchedFile}() + dw = LS.SimpleWatcher() + + LS.servedocs_callback!(dw, makejl, makejl) - LS.servedocs_callback(makejl, vwf, makejl) + @test length(dw.watchedfiles) == 3 + @test dw.watchedfiles[1].path == joinpath("docs", "make.jl") + @test dw.watchedfiles[2].path == joinpath("docs", "src", "index.md") + @test dw.watchedfiles[3].path == joinpath("docs", "src", "index2.md") - @test length(vwf) == 2 - @test vwf[1].path == joinpath("docs", "src", "index.md") - @test vwf[2].path == joinpath("docs", "src", "index2.md") @test readmake() == 2 # let's now remove `index2.md` rm(joinpath("docs", "src", "index2.md")) - LS.servedocs_callback(makejl, vwf, makejl) + LS.servedocs_callback!(dw, makejl, makejl) # the file has been removed - @test length(vwf) == 1 + @test length(dw.watchedfiles) == 2 @test readmake() == 3 # let's check there's an appropriate trigger for index - LS.servedocs_callback(joinpath("docs", "src", "index.md"), vwf, makejl) - @test length(vwf) == 1 + LS.servedocs_callback!(dw, joinpath("docs", "src", "index.md"), makejl) + @test length(dw.watchedfiles) == 2 @test readmake() == 4 # but a random should not trigger - LS.servedocs_callback("whatever", vwf, makejl) + LS.servedocs_callback!(dw, "whatever", makejl) @test readmake() == 4 cd(bk) @@ -60,18 +62,17 @@ end write(joinpath("docs", "src", "index2.md"), "Random file") write(joinpath("docs", "make.jl"), "1+1") - mkdir("alternate") - write(joinpath("alternate", "blah.md"), "1+1") + mkdir(joinpath("docs", "lit")) + write(joinpath("docs", "lit", "index.jl"), "1+1") dw = LS.SimpleWatcher() - makejl = LS.scan_docs!(dw, [joinpath("alternate", "blah.md")]) + makejl = LS.scan_docs!(dw, joinpath("docs", "lit")) @test makejl == joinpath("docs", "make.jl") - @test length(dw.watchedfiles) == 4 # index, index2, blah.md make + @test length(dw.watchedfiles) == 3 # index.jl, index2.md, make.jl @test endswith(dw.watchedfiles[1].path, "make.jl") - @test endswith(dw.watchedfiles[2].path, "index.md") - @test endswith(dw.watchedfiles[3].path, "index2.md") - @test endswith(dw.watchedfiles[4].path, "blah.md") + @test endswith(dw.watchedfiles[2].path, "index2.md") + @test endswith(dw.watchedfiles[3].path, "index.jl") cd(bk) end From b72627876ab0dd2a0c8156b6485b75c7fe0c19af Mon Sep 17 00:00:00 2001 From: Thibaut Lienart Date: Mon, 27 May 2019 16:53:49 +1000 Subject: [PATCH 4/4] fixing isnothing for compat with 1.0 --- src/utils.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils.jl b/src/utils.jl index f3432c5..5b43e17 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -69,7 +69,7 @@ function scan_docs!(dw::SimpleWatcher, literate::String="") spath = splitext(wf.path) spath[2] == ".jl" || continue k = findfirst(e -> splitext(e.path) == (spath[1], ".md"), dw.watchedfiles) - isnothing(k) || push!(remove, k) + k === nothing || push!(remove, k) end else # assumption is that the scripts are in `literate/` and that the generated markdown goes @@ -84,7 +84,7 @@ function scan_docs!(dw::SimpleWatcher, literate::String="") spath[2] == ".jl" || continue path = replace(spath[1], Regex("^$literate") => joinpath("docs", "src")) k = findfirst(e -> splitext(e.path) == (path, ".md"), dw.watchedfiles) - isnothing(k) || push!(remove, k) + k === nothing || push!(remove, k) end end deleteat!(dw.watchedfiles, remove)