diff --git a/CHANGELOG.md b/CHANGELOG.md index 8751f5c996..6d0370ffd3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ ## Version `v0.27.19` +* ![Enhancement][badge-enhancement] Documenter can now build draft version of HTML documentation by passing `draft=true` to `makedocs`. Draft mode skips potentially expensive parts of the building process and can be useful to get faster feedback when writing documentation. Draft mode currently skips doctests, `@example`-, `@repl`-, `@eval`-, and `@setup`-blocks. Draft mode can be disabled (or enabled) on a per-page basis by setting `Draft = true` in an `@meta` block. ([#1836][github-1836]) * ![Enhancement][badge-enhancement] On the HTML search page, pressing enter no longer causes the page to refresh (and therefore does not trigger the slow search index rebuild). ([#1728][github-1728], [#1833][github-1833], [#1834][github-1834]) * ![Enhancement][badge-enhancement] For the `edit_link` keyword to `HTML()`, Documenter automatically tries to figure out if the remote default branch is `main`, `master`, or something else. It will print a warning if it is unable to reliably determine either `edit_link` or `devbranch` (for `deploydocs`). ([#1827][github-1827], [#1829][github-1829]) @@ -1052,6 +1053,7 @@ [github-1829]: https://github.com/JuliaDocs/Documenter.jl/pull/1829 [github-1833]: https://github.com/JuliaDocs/Documenter.jl/pull/1833 [github-1834]: https://github.com/JuliaDocs/Documenter.jl/pull/1834 +[github-1836]: https://github.com/JuliaDocs/Documenter.jl/pull/1836 [julia-38079]: https://github.com/JuliaLang/julia/issues/38079 diff --git a/docs/src/man/syntax.md b/docs/src/man/syntax.md index 53ebfdad6d..77f1b0f2f5 100644 --- a/docs/src/man/syntax.md +++ b/docs/src/man/syntax.md @@ -257,6 +257,7 @@ page. Currently recognised keys: - `EditURL`: link to where the page can be edited. This defaults to the `.md` page itself, but if the source is something else (for example if the `.md` page is generated as part of the doc build) this can be set, either as a local link, or an absolute url. +- `Draft`: boolean for overriding the global draft mode for the page. Example: diff --git a/src/DocTests.jl b/src/DocTests.jl index c24ac384a2..5cf3412e43 100644 --- a/src/DocTests.jl +++ b/src/DocTests.jl @@ -47,9 +47,18 @@ function doctest(blueprint::Documents.DocumentBlueprint, doc::Documents.Document @debug "Running doctests." # find all the doctest blocks in the pages for (src, page) in blueprint.pages + if Utilities.is_draft(doc, page) + @debug "Skipping page-doctests in draft mode" page.source + continue + end doctest(page, doc) end + if Utilities.is_draft(doc) + @debug "Skipping docstring-doctests in draft mode" + return + end + # find all the doctest block in all the docstrings (within specified modules) for mod in blueprint.modules for (binding, multidoc) in DocSystem.getmeta(mod) diff --git a/src/Documenter.jl b/src/Documenter.jl index 6dde3264f3..63e63597c1 100644 --- a/src/Documenter.jl +++ b/src/Documenter.jl @@ -84,6 +84,7 @@ export Deps, makedocs, deploydocs, hide, doctest, DocMeta, asset, highlightsig = true, sitename = "", expandfirst = [], + draft = false, ) Combines markdown files and inline docstrings into an interlinked document. @@ -188,6 +189,11 @@ is enabled by default. before the others. Documenter normally evaluates the files in the alphabetic order of their file paths relative to `src`, but `expandfirst` allows some pages to be prioritized. +**`draft`** can be set to `true` to build a draft version of the document. In draft mode +some potentially time-consuming steps are skipped (e.g. running `@example` blocks), which is +useful when iterating on the documentation. This setting can also be configured per-page +by setting `Draft = true` in an `@meta` block. + For example, if you have `foo.md` and `bar.md`, `bar.md` would normally be evaluated before `foo.md`. But with `expandfirst = ["foo.md"]`, you can force `foo.md` to be evaluated first. diff --git a/src/Documents.jl b/src/Documents.jl index 12f86affb2..fb8b24ba09 100644 --- a/src/Documents.jl +++ b/src/Documents.jl @@ -249,6 +249,7 @@ struct User authors :: String version :: String # version string used in the version selector by default highlightsig::Bool # assume leading unlabeled code blocks in docstrings to be Julia. + draft :: Bool end """ @@ -304,6 +305,7 @@ function Document(plugins = nothing; authors :: AbstractString = "", version :: AbstractString = "", highlightsig::Bool = true, + draft::Bool = false, others... ) @@ -338,7 +340,8 @@ function Document(plugins = nothing; sitename, authors, version, - highlightsig + highlightsig, + draft, ) internal = Internal( Utilities.assetsdir(), diff --git a/src/Expanders.jl b/src/Expanders.jl index d09b8d64e3..bd48d26d7d 100644 --- a/src/Expanders.jl +++ b/src/Expanders.jl @@ -53,6 +53,14 @@ function pagecheck(page) end end +# Draft output code block +function create_draft_result(x; blocktype="code") + content = [] + push!(content, Markdown.Code("julia", x.code)) + push!(content, Dict{MIME,Any}(MIME"text/plain"() => "<< $(blocktype)-block not executed in draft mode >>")) + return Documents.MultiOutput(content) +end + # Expander Pipeline. # ------------------ @@ -514,6 +522,12 @@ end # ----- function Selectors.runner(::Type{EvalBlocks}, x, page, doc) + # Bail early if in draft mode + if Utilities.is_draft(doc, page) + @debug "Skipping evaluation of @eval block in draft mode:\n$(x.code)" + page.mapping[x] = create_draft_result(x; blocktype="@eval") + return + end sandbox = Module(:EvalBlockSandbox) lines = Utilities.find_block_in_file(x.code, page.source) linenumbernode = LineNumberNode(lines === nothing ? 0 : lines.first, @@ -571,6 +585,14 @@ function Selectors.runner(::Type{ExampleBlocks}, x, page, doc) matched = match(r"^@example(?:\s+([^\s;]+))?\s*(;.*)?$", x.language) matched === nothing && error("invalid '@example' syntax: $(x.language)") name, kwargs = matched.captures + + # Bail early if in draft mode + if Utilities.is_draft(doc, page) + @debug "Skipping evaluation of @example block in draft mode:\n$(x.code)" + page.mapping[x] = create_draft_result(x; blocktype="@example") + return + end + # The sandboxed module -- either a new one or a cached one from this page. mod = Utilities.get_sandbox_module!(page.globals.meta, "atexample", name) sym = nameof(mod) @@ -663,6 +685,14 @@ function Selectors.runner(::Type{REPLBlocks}, x, page, doc) matched = match(r"^@repl(?:\s+([^\s;]+))?\s*(;.*)?$", x.language) matched === nothing && error("invalid '@repl' syntax: $(x.language)") name, kwargs = matched.captures + + # Bail early if in draft mode + if Utilities.is_draft(doc, page) + @debug "Skipping evaluation of @repl block in draft mode:\n$(x.code)" + page.mapping[x] = create_draft_result(x; blocktype="@repl") + return + end + # The sandboxed module -- either a new one or a cached one from this page. mod = Utilities.get_sandbox_module!(page.globals.meta, "atexample", name) @@ -726,6 +756,14 @@ function Selectors.runner(::Type{SetupBlocks}, x, page, doc) matched = match(r"^@setup(?:\s+([^\s;]+))?\s*$", x.language) matched === nothing && error("invalid '@setup ' syntax: $(x.language)") name = matched[1] + + # Bail early if in draft mode + if Utilities.is_draft(doc, page) + @debug "Skipping evaluation of @setup block in draft mode:\n$(x.code)" + page.mapping[x] = create_draft_result(x; blocktype="@setup") + return + end + # The sandboxed module -- either a new one or a cached one from this page. mod = Utilities.get_sandbox_module!(page.globals.meta, "atexample", name) diff --git a/src/Utilities/Utilities.jl b/src/Utilities/Utilities.jl index c5187b9277..2b08372bc1 100644 --- a/src/Utilities/Utilities.jl +++ b/src/Utilities/Utilities.jl @@ -834,6 +834,14 @@ function git_remote_head_branch(varname, root; remotename = "origin", fallback = end end +# Check global draft setting +is_draft(doc) = doc.user.draft +# Check if the page is built with draft mode +function is_draft(doc, page)::Bool + # Check both Draft and draft from @meta block + return get(page.globals.meta, :Draft, get(page.globals.meta, :draft, is_draft(doc))) +end + include("DOM.jl") include("MDFlatten.jl") include("TextDiff.jl") diff --git a/test/examples/make.jl b/test/examples/make.jl index 5a6882eafb..78a8672197 100644 --- a/test/examples/make.jl +++ b/test/examples/make.jl @@ -19,7 +19,7 @@ EXAMPLE_BUILDS = if haskey(ENV, "DOCUMENTER_TEST_EXAMPLES") split(ENV["DOCUMENTER_TEST_EXAMPLES"]) else ["markdown", "html", "html-mathjax2-custom", "html-mathjax3", "html-mathjax3-custom", - "html-local"] + "html-local", "html-draft"] end # Modules `Mod` and `AutoDocs` @@ -342,6 +342,23 @@ else nothing end +# HTML: draft mode +examples_html_local_doc = if "html-draft" in EXAMPLE_BUILDS + @info("Building mock package docs: HTMLWriter / draft build") + @quietly makedocs( + debug = true, + draft = true, + root = examples_root, + build = "builds/html-draft", + sitename = "Documenter example (draft)", + pages = htmlbuild_pages, + ) +else + @info "Skipping build: HTML/draft" + @debug "Controlling variables:" EXAMPLE_BUILDS get(ENV, "DOCUMENTER_TEST_EXAMPLES", nothing) + nothing +end + # Markdown examples_markdown_doc = if "markdown" in EXAMPLE_BUILDS @info("Building mock package docs: MarkdownWriter")