diff --git a/CHANGELOG.md b/CHANGELOG.md index 1685206dae..966edbe358 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Page category is removed from the search index and now everything is in section category. ([#2762], [#2413]) * Changed the docstring block accordions from a custom implementation to HTML details+summary tag. ([#2772], [#2773]) * Improved the search tokenizer and custom trimmer to improve search results. ([#1457], [#2114], [#2744]) +* Improved several warning/error messages to (more accurately) report the location (filename, line range) in which the warning/error originated. ([#2803]) ### Fixed @@ -2178,6 +2179,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [#2774]: https://github.com/JuliaDocs/Documenter.jl/issues/2774 [#2787]: https://github.com/JuliaDocs/Documenter.jl/issues/2787 [#2792]: https://github.com/JuliaDocs/Documenter.jl/issues/2792 +[#2803]: https://github.com/JuliaDocs/Documenter.jl/issues/2803 [JuliaLang/julia#36953]: https://github.com/JuliaLang/julia/issues/36953 [JuliaLang/julia#38054]: https://github.com/JuliaLang/julia/issues/38054 [JuliaLang/julia#39841]: https://github.com/JuliaLang/julia/issues/39841 diff --git a/src/cross_references.jl b/src/cross_references.jl index 460e24d3ea..cd788f3e8d 100644 --- a/src/cross_references.jl +++ b/src/cross_references.jl @@ -80,7 +80,7 @@ function local_links!(node::MarkdownAST.Node, meta, page, doc) if node.element isa MarkdownAST.Image @docerror( doc, :cross_references, - "invalid local image: path missing in $(Documenter.locrepr(page.source))", + "invalid local image: path missing in $(Documenter.locrepr(doc, page))", link = node ) return @@ -90,7 +90,7 @@ function local_links!(node::MarkdownAST.Node, meta, page, doc) elseif Sys.iswindows() && ':' in path @docerror( doc, :cross_references, - "invalid local link/image: colons not allowed in paths on Windows in $(Documenter.locrepr(page.source))", + "invalid local link/image: colons not allowed in paths on Windows in $(Documenter.locrepr(doc, page))", link = node ) return @@ -101,7 +101,7 @@ function local_links!(node::MarkdownAST.Node, meta, page, doc) if startswith(path, "..") @docerror( doc, :cross_references, - "invalid local link/image: path pointing to a file outside of build directory in $(Documenter.locrepr(page.source))", + "invalid local link/image: path pointing to a file outside of build directory in $(Documenter.locrepr(doc, page))", link = node ) return @@ -116,7 +116,7 @@ function local_links!(node::MarkdownAST.Node, meta, page, doc) if !isempty(fragment) @docerror( doc, :cross_references, - "invalid local image: path contains a fragment in $(Documenter.locrepr(page.source))", + "invalid local image: path contains a fragment in $(Documenter.locrepr(doc, page))", link = node ) end @@ -128,7 +128,7 @@ function local_links!(node::MarkdownAST.Node, meta, page, doc) else @docerror( doc, :cross_references, - "invalid local link/image: file does not exist in $(Documenter.locrepr(page.source))", + "invalid local link/image: file does not exist in $(Documenter.locrepr(doc, page))", link = node ) return @@ -314,7 +314,7 @@ function xref(node::MarkdownAST.Node, meta, page, doc) # finalizer if xref_unresolved(node) md_str = strip(Markdown.plain(_link_node_as_md(node))) - msg = "Cannot resolve @ref for md$(repr(md_str)) in $(Documenter.locrepr(page.source))." + msg = "Cannot resolve @ref for md$(repr(md_str)) in $(Documenter.locrepr(doc, page))." if (length(errors) > 0) msg *= ("\n" * join([string("- ", err) for err in errors], "\n")) end @@ -375,7 +375,7 @@ function namedxref(node::MarkdownAST.Node, slug, meta, page, doc, errors) page = doc.blueprint.pages[pagekey] node.element = Documenter.PageLink(page, anchor_label(anchor)) else - push!(errors, "Header with slug '$slug' is not unique in $(Documenter.locrepr(page.source)).") + push!(errors, "Header with slug '$slug' is not unique in $(Documenter.locrepr(doc, page)).") end return end @@ -396,7 +396,7 @@ function docsxref(node::MarkdownAST.Node, code, meta, page, doc, errors) modules = [Main] end for (attempt, mod) in enumerate(modules) - docref = find_docref(code, mod, page) + docref = find_docref(code, mod, page, doc) if haskey(docref, :error) # We'll bail if the parsing of the docref wasn't successful msg = "Exception trying to find docref for `$code`: $(docref.error)" @@ -432,7 +432,7 @@ function docsxref(node::MarkdownAST.Node, code, meta, page, doc, errors) return end -function find_docref(code, mod, page) +function find_docref(code, mod, page, doc) # Parse the link text and find current module. keyword = Symbol(strip(code)) local ex @@ -443,7 +443,7 @@ function find_docref(code, mod, page) ex = Meta.parse(code) catch err isa(err, Meta.ParseError) || rethrow(err) - return (error = "unable to parse the reference `$code` in $(Documenter.locrepr(page.source)).", exception = nothing) + return (error = "unable to parse the reference `$code` in $(Documenter.locrepr(doc, page)).", exception = nothing) end end @@ -464,7 +464,7 @@ function find_docref(code, mod, page) typesig = Core.eval(mod, Documenter.DocSystem.signature(ex, rstrip(code))) catch err return ( - error = "unable to evaluate the type signature for `$code` in $(Documenter.locrepr(page.source)) in module $(mod)", + error = "unable to evaluate the type signature for `$code` in $(Documenter.locrepr(doc, page)) in module $(mod)", exception = (err, catch_backtrace()), ) end @@ -534,7 +534,7 @@ function issue_xref(node::MarkdownAST.Node, num, meta, page, doc, errors) # Update issue links starting with a hash, but only if our Remote supports it issue_url = isnothing(doc.user.remote) ? nothing : Remotes.issueurl(doc.user.remote, num) if isnothing(issue_url) - push!(errors, "unable to generate issue reference for '[`#$num`](@ref)' in $(Documenter.locrepr(page.source)).") + push!(errors, "unable to generate issue reference for '[`#$num`](@ref)' in $(Documenter.locrepr(doc, page)).") else node.element.destination = issue_url end diff --git a/src/docchecks.jl b/src/docchecks.jl index 0f64573e27..c0318179e2 100644 --- a/src/docchecks.jl +++ b/src/docchecks.jl @@ -138,15 +138,15 @@ function footnotes(doc::Document) for (id, (ids, bodies)) in orphans # Multiple footnote bodies. if bodies > 1 - @docerror(doc, :footnote, "footnote '$id' has $bodies bodies in $(locrepr(page.source)).") + @docerror(doc, :footnote, "footnote '$id' has $bodies bodies in $(locrepr(doc, page)).") end # No footnote references for an id. if ids === 0 - @docerror(doc, :footnote, "unused footnote named '$id' in $(locrepr(page.source)).") + @docerror(doc, :footnote, "unused footnote named '$id' in $(locrepr(doc, page)).") end # No footnote bodies for an id. if bodies === 0 - @docerror(doc, :footnote, "no footnotes found for '$id' in $(locrepr(page.source)).") + @docerror(doc, :footnote, "no footnotes found for '$id' in $(locrepr(doc, page)).") end end end diff --git a/src/expander_pipeline.jl b/src/expander_pipeline.jl index 450076ead5..76aaf37d09 100644 --- a/src/expander_pipeline.jl +++ b/src/expander_pipeline.jl @@ -59,7 +59,7 @@ function expand(doc::Documenter.Document) Selectors.dispatch(Expanders.ExpanderPipeline, node, page, doc) expand_recursively(node, page, doc) end - pagecheck(page) + pagecheck(doc, page) clear_modules!(page.globals.meta) end return @@ -85,10 +85,10 @@ function expand_recursively(node, page, doc) end # run some checks after expanding the page -function pagecheck(page) +function pagecheck(doc, page) # make sure there is no "continued code" lingering around if haskey(page.globals.meta, :ContinuedCode) && !isempty(page.globals.meta[:ContinuedCode]) - @warn "code from a continued @example block unused in $(Documenter.locrepr(page.source))." + @warn "code from a continued @example block unused in $(Documenter.locrepr(doc, page))." end return end @@ -341,7 +341,7 @@ function Selectors.runner(::Type{Expanders.MetaBlocks}, node, page, doc) # we will silently skip for now. if Documenter.isassign(ex) if !(ex.args[1] in (:CurrentModule, :DocTestSetup, :DocTestTeardown, :DocTestFilters, :EditURL, :Description, :Draft, :CollapsedDocStrings, :ShareDefaultModule)) - source = Documenter.locrepr(page.source, lines) + source = Documenter.locrepr(doc, page, lines) @warn( "In $source: `@meta` block has an unsupported " * "keyword argument: $(ex.args[1])", @@ -353,7 +353,7 @@ function Selectors.runner(::Type{Expanders.MetaBlocks}, node, page, doc) @docerror( doc, :meta_block, """ - failed to evaluate `$(strip(str))` in `@meta` block in $(Documenter.locrepr(page.source, lines)) + failed to evaluate `$(strip(str))` in `@meta` block in $(Documenter.locrepr(doc, page, lines)) ```$(x.info) $(x.code) ``` @@ -431,7 +431,7 @@ function Selectors.runner(::Type{Expanders.DocsBlocks}, node, page, doc) @docerror( doc, :docs_block, """ - unable to get the binding for '$(strip(str))' in `@docs` block in $(Documenter.locrepr(page.source, lines)) from expression '$(repr(ex))' in module $(curmod) + unable to get the binding for '$(strip(str))' in `@docs` block in $(Documenter.locrepr(doc, page, lines)) from expression '$(repr(ex))' in module $(curmod) ```$(x.info) $(x.code) ``` @@ -446,7 +446,7 @@ function Selectors.runner(::Type{Expanders.DocsBlocks}, node, page, doc) @docerror( doc, :docs_block, """ - undefined binding '$(binding)' in `@docs` block in $(Documenter.locrepr(page.source, lines)) + undefined binding '$(binding)' in `@docs` block in $(Documenter.locrepr(doc, page, lines)) ```$(x.info) $(x.code) ``` @@ -463,7 +463,7 @@ function Selectors.runner(::Type{Expanders.DocsBlocks}, node, page, doc) @docerror( doc, :docs_block, """ - duplicate docs found for '$(strip(str))' in `@docs` block in $(Documenter.locrepr(page.source, lines)) + duplicate docs found for '$(strip(str))' in `@docs` block in $(Documenter.locrepr(doc, page, lines)) ```$(x.info) $(x.code) ``` $(DocSystem.public_unexported_msg(apistatus)) @@ -486,7 +486,7 @@ function Selectors.runner(::Type{Expanders.DocsBlocks}, node, page, doc) @docerror( doc, :docs_block, """ - no docs found for '$(strip(str))' in `@docs` block in $(Documenter.locrepr(page.source, lines)) + no docs found for '$(strip(str))' in `@docs` block in $(Documenter.locrepr(doc, page, lines)) ```$(x.info) $(x.code) ``` @@ -534,7 +534,7 @@ function Selectors.runner(::Type{Expanders.AutoDocsBlocks}, node, page, doc) elseif ex.args[1] in (:Modules, :Order, :Pages, :Public, :Private) fields[ex.args[1]] = Core.eval(curmod, ex.args[2]) else - source = Documenter.locrepr(page.source, lines) + source = Documenter.locrepr(doc, page, lines) @warn( "In $source: `@autodocs` block has an unsupported " * "keyword argument: $(ex.args[1])", @@ -544,7 +544,7 @@ function Selectors.runner(::Type{Expanders.AutoDocsBlocks}, node, page, doc) @docerror( doc, :autodocs_block, """ - failed to evaluate `$(strip(str))` in `@autodocs` block in $(Documenter.locrepr(page.source, lines)) + failed to evaluate `$(strip(str))` in `@autodocs` block in $(Documenter.locrepr(doc, page, lines)) ```$(x.info) $(x.code) ``` @@ -575,7 +575,7 @@ function Selectors.runner(::Type{Expanders.AutoDocsBlocks}, node, page, doc) @docerror( doc, :autodocs_block, """ - @autodocs ($(Documenter.locrepr(page.source, lines))) encountered a bad docstring binding '$(binding)' + @autodocs ($(Documenter.locrepr(doc, page, lines))) encountered a bad docstring binding '$(binding)' ```$(x.info) $(x.code) ``` @@ -649,7 +649,7 @@ function Selectors.runner(::Type{Expanders.AutoDocsBlocks}, node, page, doc) @docerror( doc, :autodocs_block, """ - duplicate docs found for '$(object.binding)' in $(Documenter.locrepr(page.source, lines)) + duplicate docs found for '$(object.binding)' in $(Documenter.locrepr(doc, page, lines)) ```$(x.info) $(x.code) ``` $(DocSystem.public_unexported_msg(apistatus)) @@ -674,7 +674,7 @@ function Selectors.runner(::Type{Expanders.AutoDocsBlocks}, node, page, doc) @docerror( doc, :autodocs_block, """ - '@autodocs' missing 'Modules = ...' in $(Documenter.locrepr(page.source, lines)) + '@autodocs' missing 'Modules = ...' in $(Documenter.locrepr(doc, page, lines)) ```$(x.info) $(x.code) ``` @@ -715,7 +715,7 @@ function Selectors.runner(::Type{Expanders.EvalBlocks}, node, page, doc) @docerror( doc, :eval_block, """ - failed to evaluate `@eval` block in $(Documenter.locrepr(page.source)) + failed to evaluate `@eval` block in $(Documenter.locrepr(doc, page, lines)) ```$(x.info) $(x.code) ``` @@ -732,7 +732,7 @@ function Selectors.runner(::Type{Expanders.EvalBlocks}, node, page, doc) # objects, like Paragraph. @docerror( doc, :eval_block, """ - Invalid type of object in @eval in $(Documenter.locrepr(page.source)) + Invalid type of object in @eval in $(Documenter.locrepr(doc, page, lines)) ```$(x.info) $(x.code) ``` @@ -864,7 +864,7 @@ function Selectors.runner(::Type{Expanders.ExampleBlocks}, node, page, doc) @docerror( doc, :example_block, """ - failed to run `@example` block in $(Documenter.locrepr(page.source, lines)) + failed to run `@example` block in $(Documenter.locrepr(doc, page, lines)) ```$(x.info) $(x.code) ``` @@ -1015,10 +1015,11 @@ function Selectors.runner(::Type{Expanders.SetupBlocks}, node, page, doc) end catch err bt = Documenter.remove_common_backtrace(catch_backtrace()) + lines = Documenter.find_block_in_file(x.code, page.source) @docerror( doc, :setup_block, """ - failed to run `@setup` block in $(Documenter.locrepr(page.source)) + failed to run `@setup` block in $(Documenter.locrepr(doc, page, lines)) ```$(x.info) $(x.code) ``` diff --git a/src/html/HTMLWriter.jl b/src/html/HTMLWriter.jl index 7aff57f21b..6868a874c3 100644 --- a/src/html/HTMLWriter.jl +++ b/src/html/HTMLWriter.jl @@ -709,6 +709,12 @@ struct DCtx ) = new(dctx.ctx, navnode, droplinks, footnotes) end +function Documenter.locrepr(dctx::DCtx, lines = nothing) + doc = dctx.ctx.doc + page = dctx.navnode.page + return Documenter.locrepr(dctx.ctx.doc, dctx.ctx.page, lines) +end + function SearchRecord(ctx::HTMLContext, navnode; fragment = "", title = nothing, category = "page", text = "") page_title = mdflatten_pagetitle(DCtx(ctx, navnode)) if title === nothing @@ -2477,7 +2483,7 @@ function domify(dctx::DCtx, node::Node, f::MarkdownAST.FootnoteDefinition) # TODO: this could be rearranged such that we push!() the DOM here into .footnotes, rather # than the Node objects. if isnothing(dctx.footnotes) - @error "Invalid nested footnote definition in $(Documenter.locrepr(dctx.navnode.page))" f.id + @error "Invalid nested footnote definition in $(Documenter.locrepr(dctx))" f.id else push!(dctx.footnotes, node) end diff --git a/src/utilities/utilities.jl b/src/utilities/utilities.jl index b1689ccfac..1f52ea2471 100644 --- a/src/utilities/utilities.jl +++ b/src/utilities/utilities.jl @@ -72,14 +72,19 @@ function find_block_in_file(code, file) end # Pretty-printing locations -function locrepr(file, line = nothing) +function locrepr(file::String, lines::Union{Nothing, Pair{Int, Int}} = nothing) basedir = isassigned(original_pwd) ? original_pwd[] : currentdir() file = abspath(file) str = Base.contractuser(relpath(file, basedir)) - line !== nothing && (str = str * ":$(line.first)-$(line.second)") + lines !== nothing && (str = str * ":$(lines.first)-$(lines.second)") return str end +function locrepr(doc, page, lines::Union{Nothing, Pair{Int, Int}} = nothing) + file = joinpath(doc.user.root, page.source) + return locrepr(file, lines) +end + # Directory paths. """