docs: add figures, table captions and a macro chooser
- Figures with numbered captions: SAX stepper, json_view layout and edit stepper, exception map, JSON pointer and patch walkers, QA pipeline, scaling and binary size charts, roadmap lanes, release timeline, integration decision tree and namespace builder - Table captions (nj-table-caption) on 9 pages - Compile times: modules and PCH charts, filesystem section, re-measured Figure 1, links between features/modules.md and compile_times.md - Interactive macro chooser for features/arbitrary_types.md - Link check: exclude URLs that answer the plugin with 400/401/419 or are dead (customers.md) Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
96 files changed
+6737
-69
No files matched your search
@@ -0,0 +1,168 @@
|
||||
"""Draws the exception id map of home/exceptions.md as an inline SVG into docs/images/exception_map.svg.
|
||||
|
||||
The SVG is not an image: the page includes its text with `--8<-- "images/exception_map.svg"`, so it picks up the
|
||||
colours and fonts of the page (see the `nj-fig` rules in docs/css/brand.css and the `nj-exceptions-*` rules in
|
||||
docs/css/fig-exceptions.css). The file holds two drawings of the same map, a wide one and a narrow one for phones;
|
||||
the CSS shows one of them. Every id chip is a link to the `###` section of that id on the page, every family box a
|
||||
link to the family's `##` section.
|
||||
|
||||
Run `python3 scripts/figures/exception_map.py` from docs/mkdocs after changing the drawing or after adding an
|
||||
exception section to home/exceptions.md (the ids are read from the page), and commit the generated file. In SVG text
|
||||
write the word JSON as `J​SON`, otherwise the abbreviation extension wraps it in an <abbr> and the text
|
||||
disappears.
|
||||
"""
|
||||
import html
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
OUT = Path(__file__).resolve().parents[2] / "docs" / "images"
|
||||
PAGE = Path(__file__).resolve().parents[2] / "docs" / "home" / "exceptions.md"
|
||||
P = "nj-exceptions-"
|
||||
|
||||
# family name, id range label, anchor of the family section, extra member
|
||||
FAMILIES = [
|
||||
("parse_error", "1xx", "parse-errors", "byte"),
|
||||
("invalid_iterator", "2xx", "iterator-errors", None),
|
||||
("type_error", "3xx", "type-errors", None),
|
||||
("out_of_range", "4xx", "out-of-range", None),
|
||||
("other_error", "5xx", "further-exceptions", None),
|
||||
]
|
||||
|
||||
# the chips show the id only; naming just some of them was confusing
|
||||
LABELS = {}
|
||||
|
||||
|
||||
GLOSSARY = Path(__file__).resolve().parents[2] / "includes" / "glossary.md"
|
||||
ABBRS = sorted(re.findall(r"^\*\[([^\]]+)\]:", GLOSSARY.read_text(), re.M), key=len, reverse=True)
|
||||
|
||||
|
||||
def noabbr(s):
|
||||
"""Breaks every glossary abbreviation with a zero-width space, so the abbr extension leaves SVG text alone."""
|
||||
for a in ABBRS:
|
||||
s = re.sub(r"(?<![\w&#])%s(?!\w)" % re.escape(a), a[0] + "​" + a[1:], s)
|
||||
return s
|
||||
|
||||
|
||||
def ids_on_page():
|
||||
found = {}
|
||||
for m in re.finditer(r"^### json\.exception\.(\w+)\.(\d+)\s*$", PAGE.read_text(), re.M):
|
||||
found.setdefault(m.group(1), []).append(int(m.group(2)))
|
||||
return found
|
||||
|
||||
|
||||
def text_w(s, size):
|
||||
"""Rough advance width of Inter at the given size (good enough to size chips)."""
|
||||
w = 0.0
|
||||
for c in s:
|
||||
if c in "il.,:;'|![]()":
|
||||
w += 0.28
|
||||
elif c in " ft":
|
||||
w += 0.32
|
||||
elif c in "mwMW":
|
||||
w += 0.85
|
||||
elif c.isupper() or c.isdigit():
|
||||
w += 0.64
|
||||
else:
|
||||
w += 0.55
|
||||
return w * size
|
||||
|
||||
|
||||
def esc(s):
|
||||
return html.escape(s, quote=True).replace("[", "[").replace("]", "]")
|
||||
|
||||
|
||||
MONO = 7.9 # JetBrains Mono advance at 13px
|
||||
CH = 28 # chip height
|
||||
GAP = 6
|
||||
|
||||
|
||||
def chip(x, y, fam, num):
|
||||
label = LABELS.get(num)
|
||||
w = 3 * MONO + 18 + (text_w(label, 12.5) + 10 if label else 0)
|
||||
anchor = "jsonexception%s%d" % (fam, num)
|
||||
aria = "json.exception.%s.%d%s" % (fam, num, (": " + label) if label else "")
|
||||
s = ['<a class="%schip%s" xlink:href="#%s" aria-label="%s">' % (P, " %schip--named" % P if label else "", anchor, esc(aria)),
|
||||
'<rect x="%g" y="%g" width="%g" height="%d" rx="6"/>' % (x, y, w, CH),
|
||||
'<text class="%sid" x="%g" y="%g">%d</text>' % (P, x + 9, y + CH / 2 + 4.5, num)]
|
||||
if label:
|
||||
s.append('<text class="%slabel" x="%g" y="%g">%s</text>' % (P, x + 9 + 3 * MONO + 9, y + CH / 2 + 4.5, noabbr(esc(label))))
|
||||
s.append('</a>')
|
||||
return w, "".join(s)
|
||||
|
||||
|
||||
def flow(fam, nums, x0, x1, y0):
|
||||
"""Places the chips of one family left to right, wrapping at x1. Returns (svg parts, bottom y)."""
|
||||
parts, x, y = [], x0, y0
|
||||
for n in nums:
|
||||
w, _ = chip(0, 0, fam, n)
|
||||
if x > x0 and x + w > x1:
|
||||
x, y = x0, y + CH + GAP
|
||||
_, s = chip(x, y, fam, n)
|
||||
parts.append(s)
|
||||
x += w + GAP
|
||||
return parts, y + CH
|
||||
|
||||
|
||||
def box(x, y, w, h, title, sub, href=None, cls=""):
|
||||
s = []
|
||||
if href:
|
||||
s.append('<a class="%sfam" xlink:href="#%s" aria-label="%s">' % (P, href, esc(title + ", " + sub)))
|
||||
s.append('<rect class="%sbox%s" x="%g" y="%g" width="%g" height="%g" rx="7"/>' % (P, cls, x, y, w, h))
|
||||
s.append('<text class="%sname" x="%g" y="%g">%s</text>' % (P, x + 12, y + 22, noabbr(esc(title))))
|
||||
s.append('<text class="%ssub" x="%g" y="%g">%s</text>' % (P, x + 12, y + 41, noabbr(esc(sub))))
|
||||
if href:
|
||||
s.append('</a>')
|
||||
return "".join(s)
|
||||
|
||||
|
||||
def drawing(W, narrow, suffix):
|
||||
global CH
|
||||
CH = 34 if narrow else 28 # larger touch targets on phones
|
||||
ids = ids_on_page()
|
||||
mid = "nj-exc-tri-" + suffix
|
||||
body = []
|
||||
trunk = 34
|
||||
# std::exception and json::exception
|
||||
body.append(box(12, 12, 190 if narrow else 200, 52, "std::exception", "C++ standard library base"))
|
||||
body.append('<line class="%sedge" x1="%d" y1="%d" x2="%d" y2="%d" marker-end="url(#%s)"/>' % (P, trunk, 104, trunk, 66, mid))
|
||||
body.append(box(12, 104, 250 if narrow else 300, 52, "json::exception", "id, what() \u00b7 catch-all"))
|
||||
y = 196
|
||||
last_branch = y
|
||||
fam_w = W - 64 - 12 if narrow else 214
|
||||
for fam, rng, href, member in FAMILIES:
|
||||
nums = ids[fam]
|
||||
sub = "%s \u00b7 %d ids" % (rng, len(nums)) + (" \u00b7 adds member %s" % member if member else "")
|
||||
body.append('<line class="%sedge" x1="%d" y1="%d" x2="%d" y2="%d"/>' % (P, trunk, y + 26, 64, y + 26))
|
||||
last_branch = y + 26
|
||||
body.append(box(64, y, fam_w, 52, "json::" + fam, sub, href, " %sbox--fam" % P))
|
||||
if narrow:
|
||||
parts, bottom = flow(fam, nums, 64, W - 12, y + 52 + 10)
|
||||
else:
|
||||
parts, bottom = flow(fam, nums, 64 + fam_w + 16, W - 12, y + 12)
|
||||
body += parts
|
||||
y = max(bottom, y + 52) + 26
|
||||
# trunk from json::exception down to the last family, with the inheritance triangle at the top
|
||||
body.insert(0, '<line class="%sedge" x1="%d" y1="%d" x2="%d" y2="%d" marker-end="url(#%s)"/>' % (P, trunk, last_branch, trunk, 158, mid))
|
||||
H = y - 14
|
||||
defs = ('<defs><marker id="%s" viewBox="0 0 12 12" refX="11" refY="6" markerWidth="11" markerHeight="11" orient="auto">'
|
||||
'<path class="%stri" d="M1 1 L11 6 L1 11 z"/></marker></defs>' % (mid, P))
|
||||
tid, did = "nj-exc-map-title-" + suffix, "nj-exc-map-desc-" + suffix
|
||||
total = sum(len(v) for v in ids.values())
|
||||
desc = ("Class tree: std::exception is the base of json::exception, which is the base of the five exception "
|
||||
"families parse_error (ids 1xx), invalid_iterator (2xx), type_error (3xx), out_of_range (4xx) and "
|
||||
"other_error (5xx). Each family lists the ids documented on this page, %d in total; every id links to "
|
||||
"its section." % total)
|
||||
s = ['<svg class="nj-fig %smap %smap--%s" viewBox="0 0 %d %d" aria-labelledby="%s %s" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">'
|
||||
% (P, P, "narrow" if narrow else "wide", W, H, tid, did),
|
||||
'<title id="%s">Exception id map</title>' % tid,
|
||||
'<desc id="%s">%s</desc>' % (did, noabbr(esc(desc))),
|
||||
defs] + body + ['</svg>']
|
||||
return "\n".join(s)
|
||||
|
||||
|
||||
def main():
|
||||
out = drawing(760, False, "w") + "\n" + drawing(360, True, "n") + "\n"
|
||||
(OUT / "exception_map.svg").write_text(out)
|
||||
|
||||
|
||||
main()
|
||||
Reference in new issue
Block a user