Skip to content

Commit

Permalink
Draft mode that skips (potentially) expensive parts of the build proc…
Browse files Browse the repository at this point in the history
…ess (#1836)

When passing `draft=true` to `makedocs` a draft version of the
documentation is built. 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, `at-example`,
`at-repl`, `at-eval`, and `at-setup` blocks. Draft mode can be disabled (or
enabled) on a per-page basis by setting `Draft = true` in an `at-meta`
block.
  • Loading branch information
fredrikekre authored Jun 3, 2022
1 parent fc80f3b commit 051bb4a
Show file tree
Hide file tree
Showing 8 changed files with 86 additions and 2 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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])

Expand Down Expand Up @@ -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
<!-- end of issue link definitions -->

[julia-38079]: https://github.com/JuliaLang/julia/issues/38079
Expand Down
1 change: 1 addition & 0 deletions docs/src/man/syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down
9 changes: 9 additions & 0 deletions src/DocTests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
6 changes: 6 additions & 0 deletions src/Documenter.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down
5 changes: 4 additions & 1 deletion src/Documents.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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

"""
Expand Down Expand Up @@ -304,6 +305,7 @@ function Document(plugins = nothing;
authors :: AbstractString = "",
version :: AbstractString = "",
highlightsig::Bool = true,
draft::Bool = false,
others...
)

Expand Down Expand Up @@ -338,7 +340,8 @@ function Document(plugins = nothing;
sitename,
authors,
version,
highlightsig
highlightsig,
draft,
)
internal = Internal(
Utilities.assetsdir(),
Expand Down
38 changes: 38 additions & 0 deletions src/Expanders.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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.
# ------------------
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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 <name>' 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)

Expand Down
8 changes: 8 additions & 0 deletions src/Utilities/Utilities.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
19 changes: 18 additions & 1 deletion test/examples/make.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down Expand Up @@ -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")
Expand Down

0 comments on commit 051bb4a

Please sign in to comment.