Skip to content

Commit 5e4636a

Browse files
committed
Write inventory files
1 parent aac2ea9 commit 5e4636a

10 files changed

Lines changed: 208 additions & 1 deletion

File tree

Project.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ version = "1.2.1"
66
ANSIColoredPrinters = "a4c015fc-c6ff-483c-b24f-f7ea428134e9"
77
AbstractTrees = "1520ce14-60c1-5f80-bbc7-55ef81b5835c"
88
Base64 = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
9+
CodecZlib = "944b1d66-785c-5afd-91f1-9de20f533193"
910
Dates = "ade2ca70-3891-5945-98fb-dc099432e06a"
1011
DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
1112
Downloads = "f43a241f-c20a-4ad4-852c-f6b1247861c6"
@@ -29,6 +30,7 @@ Unicode = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5"
2930
ANSIColoredPrinters = "0.0.1"
3031
AbstractTrees = "0.4"
3132
Base64 = "1.6"
33+
CodecZlib = "0.7"
3234
Dates = "1.6"
3335
DocStringExtensions = "0.4, 0.5, 0.6, 0.7, 0.8, 0.9"
3436
Downloads = "1.4"

docs/src/lib/internals/writers.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Modules = [
88
Documenter.LaTeXWriter,
99
]
1010
Filter = t -> t !== asset
11-
Pages = ["writers.jl", "html/HTMLWriter.jl", "html/RD.jl", "latex/LaTeXWriter.jl"]
11+
Pages = ["writers.jl", "html/HTMLWriter.jl", "html/RD.jl", "html/write_inventory.jl", "latex/LaTeXWriter.jl"]
1212
```
1313
```@docs
1414
Documenter.Plugin

src/html/HTMLWriter.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ using MarkdownAST: MarkdownAST, Node
4646
import JSON
4747
import Base64
4848
import SHA
49+
using CodecZlib
4950

5051
import ..Documenter
5152
using Documenter: NavNode
@@ -587,6 +588,7 @@ function prepare_prerendering(prerender, node, highlightjs, highlights)
587588
end
588589

589590
include("RD.jl")
591+
include("write_inventory.jl")
590592

591593
struct SearchRecord
592594
src :: String
@@ -787,6 +789,8 @@ function render(doc::Documenter.Document, settings::HTML=HTML())
787789
println(io, json_jsescape(ctx.search_index), "\n}")
788790
end
789791

792+
write_inventory(doc, ctx)
793+
790794
generate_siteinfo_json(doc.user.build)
791795
end
792796

src/html/write_inventory.jl

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
"""
2+
Generate inventory files for the given [`Documenter.Document`](@ref) and [`HTMLContext`](@ref).
3+
4+
Write the files `objects.inv` and `inventory.toml.gz` to the root of the HTML build
5+
folder. These contain an inventory of all linkable targets in the documentation (pages,
6+
headings, and docstrings).
7+
8+
See [DocInventories](https://juliadocs.org/DocInventories.jl/stable/formats/)
9+
for a description of the file format. The inventory files can be used by
10+
[Intersphinx](https://www.sphinx-doc.org/en/master/usage/extensions/intersphinx.html)
11+
and the [DocumenterInterLinks](https://github.com/JuliaDocs/DocumenterInterLinks.jl/)
12+
plugin to link into the documentation from other projects.
13+
"""
14+
function write_inventory(doc, ctx)
15+
16+
@info "Writing inventory files."
17+
project = doc.user.sitename
18+
version = "" # TODO: https://github.com/JuliaDocs/Documenter.jl/issues/2385
19+
20+
io_inv_header = open(joinpath(doc.user.build, "objects.inv"), "w")
21+
_io_toml = open(joinpath(doc.user.build, "inventory.toml.gz"), "w")
22+
io_toml = GzipCompressorStream(_io_toml)
23+
24+
write(io_toml, "# Documenter inventory version 1\"\n")
25+
_write_toml_val(io_toml, "project", project)
26+
# _write_toml_val(io_toml, "version", version) # TODO (see above)
27+
write(io_toml, "\n")
28+
29+
write(io_inv_header, "# Sphinx inventory version 2\n")
30+
write(io_inv_header, "# Project: $project\n")
31+
write(io_inv_header, "# Version: $version\n")
32+
write(io_inv_header, "# The remainder of this file is compressed using zlib.\n")
33+
io_inv = ZlibCompressorStream(io_inv_header)
34+
35+
domain = "std"
36+
role = "doc"
37+
priority = -1
38+
for navnode in doc.internal.navlist
39+
name = replace(splitext(navnode.page)[1], "\\" => "/")
40+
uri = _get_inventory_uri(doc, ctx, navnode)
41+
dispname = _get_inventory_dispname(doc, ctx, navnode)
42+
line = "$name $domain:$role $priority $uri $dispname\n"
43+
write(io_inv, line)
44+
write(io_toml, "[[$domain.$role]]\n")
45+
_write_toml_val(io_toml, "name", name)
46+
_write_toml_val(io_toml, "uri", uri)
47+
(dispname != "-") && _write_toml_val(io_toml, "dispname", dispname)
48+
end
49+
write(io_toml, "\n")
50+
51+
domain = "std"
52+
role = "label"
53+
priority = -1
54+
for name in keys(doc.internal.headers.map)
55+
anchor = Documenter.anchor(doc.internal.headers, name)
56+
if isnothing(anchor)
57+
# anchor not unique -> exclude from inventory
58+
continue
59+
end
60+
uri = _get_inventory_uri(doc, ctx, name, anchor)
61+
dispname = _get_inventory_dispname(doc, ctx, name, anchor)
62+
line = "$name $domain:$role $priority $uri $dispname\n"
63+
write(io_inv, line)
64+
write(io_toml, "[[$domain.$role]]\n")
65+
_write_toml_val(io_toml, "name", name)
66+
_write_toml_val(io_toml, "uri", uri)
67+
(dispname != "-") && _write_toml_val(io_toml, "dispname", dispname)
68+
end
69+
write(io_toml, "\n")
70+
71+
domain = "jl"
72+
priority = 1
73+
for name in keys(doc.internal.docs.map)
74+
anchor = Documenter.anchor(doc.internal.docs, name)
75+
if isnothing(anchor)
76+
# anchor not unique -> exclude from inventory
77+
continue
78+
end
79+
uri = _get_inventory_uri(doc, ctx, name, anchor)
80+
role = lowercase(Documenter.doccat(anchor.object))
81+
dispname = "-"
82+
line = "$name $domain:$role $priority $uri $dispname\n"
83+
write(io_inv, line)
84+
write(io_toml, "[[$domain.$role]]\n")
85+
_write_toml_val(io_toml, "name", name)
86+
_write_toml_val(io_toml, "uri", uri)
87+
end
88+
89+
close(io_inv)
90+
close(io_inv_header)
91+
close(io_toml)
92+
close(_io_toml)
93+
94+
end
95+
96+
97+
function _write_toml_val(io::IO, name::AbstractString, value::AbstractString)
98+
# Cf. TOML.Internals.Printer.print_toml_escaped, but that's way too
99+
# internal to just use.
100+
write(io, name)
101+
write(io, " = \"")
102+
for c::AbstractChar in value
103+
if !isvalid(c)
104+
msg = "Invalid character $(repr(c)) encountered while writing TOML"
105+
throw(ArgumentError(msg))
106+
end
107+
if c == '\b'
108+
print(io, '\\', 'b')
109+
elseif c == '\t'
110+
print(io, '\\', 't')
111+
elseif c == '\n'
112+
print(io, '\\', 'n')
113+
elseif c == '\f'
114+
print(io, '\\', 'f')
115+
elseif c == '\r'
116+
print(io, '\\', 'r')
117+
elseif c == '"'
118+
print(io, '\\', '"')
119+
elseif c == '\\'
120+
print(io, "\\", '\\')
121+
elseif iscntrl(c)
122+
print(io, "\\u")
123+
print(io, string(UInt32(c), base=16, pad=4))
124+
else
125+
print(io, c)
126+
end
127+
end
128+
write(io, "\"\n")
129+
end
130+
131+
132+
function _write_toml_val(io::IO, name::AbstractString, value::Int64)
133+
write(io, name, " = ", value, "\n")
134+
end
135+
136+
137+
function _get_inventory_uri(doc, ctx, name::AbstractString, anchor::Documenter.Anchor)
138+
filename = relpath(anchor.file, doc.user.build)
139+
page_url = pretty_url(ctx, get_url(ctx, filename))
140+
if Sys.iswindows()
141+
# https://github.com/JuliaDocs/Documenter.jl/issues/2387
142+
page_url = replace(page_url, "\\" => "/")
143+
end
144+
label = _escapeuri(Documenter.anchor_label(anchor))
145+
if label == name
146+
uri = page_url * raw"#$"
147+
else
148+
uri = page_url * "#$label"
149+
end
150+
return uri
151+
end
152+
153+
154+
function _get_inventory_uri(doc, ctx, navnode::Documenter.NavNode)
155+
uri = pretty_url(ctx, get_url(ctx, navnode.page))
156+
if Sys.iswindows()
157+
# https://github.com/JuliaDocs/Documenter.jl/issues/2387
158+
uri = replace(uri, "\\" => "/")
159+
end
160+
return uri
161+
end
162+
163+
164+
function _get_inventory_dispname(doc, ctx, name::AbstractString, anchor::Documenter.Anchor)
165+
dispname = mdflatten(anchor.node)
166+
if dispname == name
167+
dispname = "-"
168+
end
169+
return dispname
170+
end
171+
172+
173+
function _get_inventory_dispname(doc, ctx, navnode::Documenter.NavNode)
174+
dispname = navnode.title_override
175+
if isnothing(dispname)
176+
page = getpage(ctx, navnode)
177+
title_node = pagetitle(page.mdast)
178+
if isnothing(title_node)
179+
dispname = "-"
180+
else
181+
dispname = mdflatten(title_node)
182+
end
183+
end
184+
return dispname
185+
end
186+
187+
188+
@inline _issafe(c::Char) =
189+
c == '-' || c == '.' || c == '_' || (isascii(c) && (isletter(c) || isnumeric(c)))
190+
191+
_utf8_chars(str::AbstractString) = (Char(c) for c in codeunits(str))
192+
193+
_escapeuri(c::Char) = string('%', uppercase(string(Int(c), base=16, pad=2)))
194+
_escapeuri(str::AbstractString) =
195+
join(_issafe(c) ? c : _escapeuri(c) for c in _utf8_chars(str))

test/doctests/stdouts/1.stdout

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@
66
[ Info: Populate: populating indices.
77
[ Info: RenderDocument: rendering document.
88
[ Info: HTMLWriter: rendering HTML pages.
9+
[ Info: Writing inventory files.

test/doctests/stdouts/11.stdout

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@
66
[ Info: Populate: populating indices.
77
[ Info: RenderDocument: rendering document.
88
[ Info: HTMLWriter: rendering HTML pages.
9+
[ Info: Writing inventory files.

test/doctests/stdouts/12.stdout

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,3 +128,4 @@
128128
[ Info: Populate: populating indices.
129129
[ Info: RenderDocument: rendering document.
130130
[ Info: HTMLWriter: rendering HTML pages.
131+
[ Info: Writing inventory files.

test/doctests/stdouts/3.stdout

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@
66
[ Info: Populate: populating indices.
77
[ Info: RenderDocument: rendering document.
88
[ Info: HTMLWriter: rendering HTML pages.
9+
[ Info: Writing inventory files.

test/doctests/stdouts/41.stdout

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@
66
[ Info: Populate: populating indices.
77
[ Info: RenderDocument: rendering document.
88
[ Info: HTMLWriter: rendering HTML pages.
9+
[ Info: Writing inventory files.

test/doctests/stdouts/7.stdout

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@
66
[ Info: Populate: populating indices.
77
[ Info: RenderDocument: rendering document.
88
[ Info: HTMLWriter: rendering HTML pages.
9+
[ Info: Writing inventory files.

0 commit comments

Comments
 (0)