explico 0.11.1 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1292 -1
- package/README.md +91 -13
- package/dist/compiler/astro.d.ts +11 -4
- package/dist/compiler/astro.js +48 -15
- package/dist/compiler/cli.d.ts +27 -12
- package/dist/compiler/cli.js +96 -25
- package/dist/compiler/collections.d.ts +33 -2
- package/dist/compiler/collections.js +91 -19
- package/dist/compiler/content-schema.d.ts +31 -0
- package/dist/compiler/content-schema.js +82 -0
- package/dist/compiler/content-schemas.d.ts +422 -0
- package/dist/compiler/content-schemas.js +229 -0
- package/dist/compiler/course-config.d.ts +1 -1
- package/dist/compiler/course-config.js +30 -2
- package/dist/compiler/exports/combined-html.d.ts +97 -0
- package/dist/compiler/exports/combined-html.js +492 -0
- package/dist/compiler/exports/download-index.d.ts +9 -0
- package/dist/compiler/exports/download-index.js +33 -0
- package/dist/compiler/exports/export-chapters.d.ts +98 -0
- package/dist/compiler/exports/export-chapters.js +164 -0
- package/dist/compiler/exports/export-pages.d.ts +48 -0
- package/dist/compiler/exports/export-pages.js +22 -0
- package/dist/compiler/exports/html-tree.d.ts +22 -0
- package/dist/compiler/exports/html-tree.js +47 -0
- package/dist/compiler/exports/latex/capture.d.ts +106 -0
- package/dist/compiler/exports/latex/capture.js +435 -0
- package/dist/compiler/exports/latex/compile.d.ts +73 -0
- package/dist/compiler/exports/latex/compile.js +115 -0
- package/dist/compiler/exports/latex/document.d.ts +102 -0
- package/dist/compiler/exports/latex/document.js +349 -0
- package/dist/compiler/exports/latex/explico.cls +415 -0
- package/dist/compiler/exports/latex/numbering.d.ts +18 -0
- package/dist/compiler/exports/latex/numbering.js +57 -0
- package/dist/compiler/exports/latex/serialize.d.ts +112 -0
- package/dist/compiler/exports/latex/serialize.js +606 -0
- package/dist/compiler/exports/latex-export.d.ts +44 -0
- package/dist/compiler/exports/latex-export.js +169 -0
- package/dist/compiler/exports/markdown/serialize.d.ts +51 -0
- package/dist/compiler/exports/markdown/serialize.js +527 -0
- package/dist/compiler/exports/markdown-export.d.ts +39 -0
- package/dist/compiler/exports/markdown-export.js +240 -0
- package/dist/compiler/exports/standalone-html.d.ts +15 -5
- package/dist/compiler/exports/standalone-html.js +23 -51
- package/dist/compiler/exports/static-tree.d.ts +253 -0
- package/dist/compiler/exports/static-tree.js +625 -0
- package/dist/compiler/exports/zip.d.ts +16 -0
- package/dist/compiler/exports/zip.js +72 -0
- package/dist/compiler/lesson-derivation.d.ts +8 -2
- package/dist/compiler/lesson-derivation.js +6 -7
- package/dist/compiler/manifest.d.ts +115 -8
- package/dist/compiler/manifest.js +221 -39
- package/dist/compiler/render-diagnostics.d.ts +65 -0
- package/dist/compiler/render-diagnostics.js +56 -0
- package/dist/compiler/resolution-report.d.ts +3 -1
- package/dist/{course-config-Dsnri9Tk.d.ts → course-config-rRtME5UV.d.ts} +56 -13
- package/dist/curriculum/validation.d.ts +9 -3
- package/dist/curriculum/validation.js +35 -17
- package/dist/reference/base-abbreviations.d.mts +2 -2
- package/dist/reference/base-abbreviations.mjs +2 -2
- package/dist/reference/base-operators.d.mts +8 -2
- package/dist/reference/base-operators.mjs +8 -10
- package/dist/reference/base-roman-labels.d.mts +4 -3
- package/dist/reference/base-roman-labels.mjs +4 -3
- package/dist/reference/citation-format.d.mts +35 -0
- package/dist/reference/citation-format.mjs +74 -0
- package/dist/reference/consistency.d.ts +5 -9
- package/dist/reference/consistency.js +34 -38
- package/dist/reference/curriculum-alignment.js +3 -24
- package/dist/reference/derived-entries.d.ts +45 -0
- package/dist/reference/derived-entries.js +50 -0
- package/dist/reference/derived-notation.d.mts +125 -0
- package/dist/reference/derived-notation.mjs +121 -0
- package/dist/reference/diagram-fit.d.ts +45 -0
- package/dist/reference/diagram-fit.js +54 -0
- package/dist/reference/diagram-layout.d.ts +59 -10
- package/dist/reference/diagram-layout.js +85 -24
- package/dist/reference/diagrams-validate.d.ts +1 -1
- package/dist/reference/equations-validate.d.ts +1 -1
- package/dist/reference/equations-validate.js +26 -1
- package/dist/reference/equations.d.mts +27 -0
- package/dist/reference/equations.mjs +120 -22
- package/dist/reference/examples-validate.d.ts +1 -1
- package/dist/reference/figure-fit.d.ts +70 -0
- package/dist/reference/figure-fit.js +60 -0
- package/dist/reference/figure-pictures.d.ts +27 -0
- package/dist/reference/figure-pictures.js +49 -0
- package/dist/reference/figure-symbols.d.ts +32 -0
- package/dist/reference/figure-symbols.js +55 -0
- package/dist/reference/figures-validate.d.ts +1 -1
- package/dist/reference/gate-abbreviations.d.ts +1 -1
- package/dist/reference/gate-abbreviations.js +1 -1
- package/dist/reference/gate-course-rules.d.ts +4 -3
- package/dist/reference/gate-course-rules.js +9 -4
- package/dist/reference/gate-heading-length.d.ts +2 -0
- package/dist/reference/gate-heading-length.js +7 -5
- package/dist/reference/gate-heading-structure.js +26 -0
- package/dist/reference/gate-indices.d.ts +35 -0
- package/dist/reference/gate-indices.js +299 -0
- package/dist/reference/gate-math.d.ts +32 -2
- package/dist/reference/gate-math.js +68 -12
- package/dist/reference/gate-mdx-expression.d.ts +17 -0
- package/dist/reference/gate-mdx-expression.js +29 -0
- package/dist/reference/gate-non-chapter-pages.d.ts +39 -0
- package/dist/reference/gate-non-chapter-pages.js +156 -0
- package/dist/reference/gate-part-pages.d.ts +4 -2
- package/dist/reference/gate-part-pages.js +2 -1
- package/dist/reference/gate-prop-text.d.ts +28 -0
- package/dist/reference/gate-prop-text.js +106 -0
- package/dist/reference/gate-prose-notation.d.ts +3 -1
- package/dist/reference/gate-prose-notation.js +4 -2
- package/dist/reference/gate-retired-keys.d.ts +35 -0
- package/dist/reference/gate-retired-keys.js +58 -0
- package/dist/reference/gloss.d.ts +2 -0
- package/dist/reference/katex-measure.d.ts +17 -0
- package/dist/reference/katex-measure.js +223 -0
- package/dist/reference/keyed-float-validate.js +12 -0
- package/dist/reference/keyed-jsx-floats.d.mts +2 -2
- package/dist/reference/keyed-jsx-floats.mjs +11 -14
- package/dist/reference/lab-katex-validate.d.ts +43 -0
- package/dist/reference/lab-katex-validate.js +96 -0
- package/dist/reference/lab-math-scope.d.ts +1 -0
- package/dist/reference/lab-math-scope.js +13 -2
- package/dist/reference/lint-ignore.js +1 -1
- package/dist/reference/math-glyphs.d.mts +94 -2
- package/dist/reference/math-glyphs.mjs +851 -46
- package/dist/reference/mixed-content.d.ts +8 -3
- package/dist/reference/mixed-content.js +4 -2
- package/dist/reference/page-notation.d.ts +39 -7
- package/dist/reference/page-notation.js +62 -10
- package/dist/reference/raw-floats.mjs +37 -13
- package/dist/reference/references.d.ts +11 -1
- package/dist/reference/references.js +6 -0
- package/dist/reference/registry.js +115 -11
- package/dist/reference/rehype-fail-katex-errors.d.mts +9 -0
- package/dist/reference/rehype-fail-katex-errors.mjs +19 -0
- package/dist/reference/rehype-heading-anchors.mjs +11 -1
- package/dist/reference/remark-citation.mjs +0 -0
- package/dist/reference/remark-notation.mjs +275 -23
- package/dist/reference/render-lab-math.d.ts +13 -2
- package/dist/reference/render-lab-math.js +18 -6
- package/dist/reference/sections-validate.d.ts +28 -3
- package/dist/reference/sections-validate.js +31 -4
- package/dist/reference/sections.d.mts +24 -6
- package/dist/reference/sections.mjs +92 -17
- package/dist/reference/tables-validate.d.ts +1 -1
- package/dist/reference/tables-validate.js +24 -1
- package/dist/reference/text-measure.d.ts +10 -0
- package/dist/reference/text-measure.js +41 -0
- package/dist/reference/text-widths.d.ts +10 -0
- package/dist/reference/text-widths.js +1238 -0
- package/dist/reference/types.d.ts +64 -8
- package/dist/rules/catalog.js +223 -32
- package/dist/rules/in-effect.d.ts +1 -1
- package/dist/rules/rules.schema.json +100 -27
- package/dist/rules/settings.d.ts +1 -1
- package/dist/rules/settings.js +7 -0
- package/dist/session/PreferenceStore.d.ts +18 -1
- package/dist/session/PreferenceStore.js +29 -1
- package/docs/authoring/README.md +33 -21
- package/docs/authoring/agents.md +38 -7
- package/docs/authoring/components.md +115 -10
- package/docs/authoring/migrating.md +878 -0
- package/docs/authoring/notation.md +285 -30
- package/docs/authoring/retired.md +1 -0
- package/docs/authoring/structure-rules.md +84 -45
- package/docs/authoring/structure.md +67 -2
- package/docs/authoring/visualizations.md +167 -25
- package/package.json +12 -7
- package/src/compiler/astro.ts +72 -21
- package/src/compiler/cli.ts +143 -35
- package/src/compiler/collections.ts +158 -27
- package/src/compiler/content-schema.ts +108 -0
- package/src/compiler/content-schemas.ts +391 -0
- package/src/compiler/course-config.ts +86 -15
- package/src/compiler/exports/combined-html.ts +669 -0
- package/src/compiler/exports/download-index.ts +36 -0
- package/src/compiler/exports/export-chapters.ts +233 -0
- package/src/compiler/exports/export-pages.ts +44 -0
- package/src/compiler/exports/html-tree.ts +62 -0
- package/src/compiler/exports/latex/capture.ts +651 -0
- package/src/compiler/exports/latex/compile.ts +168 -0
- package/src/compiler/exports/latex/document.ts +479 -0
- package/src/compiler/exports/latex/explico.cls +415 -0
- package/src/compiler/exports/latex/numbering.ts +74 -0
- package/src/compiler/exports/latex/serialize.ts +787 -0
- package/src/compiler/exports/latex/texlive-packages.txt +76 -0
- package/src/compiler/exports/latex-export.ts +255 -0
- package/src/compiler/exports/markdown/serialize.ts +632 -0
- package/src/compiler/exports/markdown-export.ts +329 -0
- package/src/compiler/exports/standalone-html.ts +39 -70
- package/src/compiler/exports/static-tree.ts +944 -0
- package/src/compiler/exports/zip.ts +88 -0
- package/src/compiler/lesson-derivation.ts +13 -8
- package/src/compiler/manifest.ts +387 -40
- package/src/compiler/render-diagnostics.ts +111 -0
- package/src/components/CourseContents.astro +6 -0
- package/src/components/HoverPanel.astro +204 -6
- package/src/components/PartOverview.astro +18 -9
- package/src/components/abbreviation/AbbreviationGlossary.astro +6 -2
- package/src/components/abbreviation/AbbreviationLayer.astro +21 -12
- package/src/components/assessments/AssessmentRunner.tsx +7 -1
- package/src/components/assessments/AssessmentSet.astro +14 -1
- package/src/components/block-heading.ts +38 -0
- package/src/components/card-arrow.ts +18 -4
- package/src/components/card-carry.ts +406 -0
- package/src/components/card-drag.ts +1 -30
- package/src/components/card-fetch.ts +87 -0
- package/src/components/card-manager.ts +1222 -38
- package/src/components/card-memory.ts +5 -1
- package/src/components/card-placement.ts +211 -13
- package/src/components/card-side.ts +281 -31
- package/src/components/citation/CitationLayer.astro +45 -40
- package/src/components/diagram/Diagram.astro +123 -44
- package/src/components/disclosure/print-as-shown.ts +42 -6
- package/src/components/figure/Figure.astro +17 -1
- package/src/components/figure/FloatCaption.astro +4 -17
- package/src/components/figure/figure-state.ts +26 -17
- package/src/components/float-toolbar.ts +274 -0
- package/src/components/memo/Memo.astro +21 -10
- package/src/components/memo/ShortNote.astro +4 -0
- package/src/components/notation/NotationGlossary.astro +22 -17
- package/src/components/notation/NotationLayer.astro +300 -79
- package/src/components/notation/NotationMath.astro +8 -1
- package/src/components/notation/render-notation-math.ts +51 -5
- package/src/components/readable-text.ts +25 -0
- package/src/components/reference/FloatRefLayer.astro +162 -89
- package/src/components/starlight/HeadingAnchorEnhancer.astro +13 -8
- package/src/components/starlight/KeyedFloatEnhancer.astro +28 -9
- package/src/components/starlight/LayoutPageSidebar.astro +17 -3
- package/src/components/starlight/LayoutSocialIcons.astro +79 -29
- package/src/components/starlight/LessonExportActions.astro +384 -310
- package/src/components/starlight/LessonFooter.astro +66 -8
- package/src/components/starlight/PrintController.astro +28 -0
- package/src/components/starlight/TextSizeControl.astro +137 -0
- package/src/components/starlight/print-controller.ts +380 -0
- package/src/components/starlight/section-summary.ts +13 -5
- package/src/components/table/Table.astro +14 -22
- package/src/components/table/table-truncation.ts +15 -0
- package/src/content-config.ts +20 -312
- package/src/curriculum/validation.ts +72 -24
- package/src/reference/base-abbreviations.mjs +2 -2
- package/src/reference/base-operators.mjs +8 -10
- package/src/reference/base-roman-labels.mjs +4 -3
- package/src/reference/citation-format.mjs +74 -0
- package/src/reference/consistency.ts +47 -61
- package/src/reference/curriculum-alignment.ts +4 -41
- package/src/reference/derived-entries.ts +68 -0
- package/src/reference/derived-notation.mjs +121 -0
- package/src/reference/diagram-fit.ts +104 -0
- package/src/reference/diagram-layout.ts +182 -51
- package/src/reference/diagrams-validate.ts +2 -1
- package/src/reference/equations-validate.ts +41 -2
- package/src/reference/equations.mjs +120 -22
- package/src/reference/examples-validate.ts +1 -0
- package/src/reference/figure-fit.ts +139 -0
- package/src/reference/figure-pictures.ts +96 -0
- package/src/reference/figure-symbols.ts +117 -0
- package/src/reference/figures-validate.ts +2 -1
- package/src/reference/gate-abbreviations.ts +1 -1
- package/src/reference/gate-course-rules.ts +22 -7
- package/src/reference/gate-heading-length.ts +25 -7
- package/src/reference/gate-heading-structure.ts +40 -1
- package/src/reference/gate-indices.ts +470 -0
- package/src/reference/gate-math.ts +102 -13
- package/src/reference/gate-mdx-expression.ts +45 -0
- package/src/reference/gate-non-chapter-pages.ts +241 -0
- package/src/reference/gate-part-pages.ts +1 -1
- package/src/reference/gate-prop-text.ts +145 -0
- package/src/reference/gate-prose-notation.ts +19 -5
- package/src/reference/gate-retired-keys.ts +101 -0
- package/src/reference/gloss.ts +2 -0
- package/src/reference/katex-measure.ts +384 -0
- package/src/reference/keyed-float-validate.ts +22 -0
- package/src/reference/keyed-jsx-floats.mjs +11 -14
- package/src/reference/lab-katex-validate.ts +156 -0
- package/src/reference/lab-math-scope.ts +15 -1
- package/src/reference/lint-ignore.ts +4 -1
- package/src/reference/math-glyphs.mjs +851 -46
- package/src/reference/mixed-content.ts +11 -2
- package/src/reference/page-notation.ts +114 -14
- package/src/reference/raw-floats.mjs +37 -13
- package/src/reference/references.ts +14 -0
- package/src/reference/registry.ts +170 -9
- package/src/reference/rehype-fail-katex-errors.mjs +19 -0
- package/src/reference/rehype-heading-anchors.mjs +11 -1
- package/src/reference/remark-citation.mjs +0 -0
- package/src/reference/remark-notation.mjs +275 -23
- package/src/reference/render-lab-math.ts +40 -5
- package/src/reference/sections-validate.ts +67 -3
- package/src/reference/sections.mjs +92 -17
- package/src/reference/tables-validate.ts +40 -2
- package/src/reference/text-measure.ts +63 -0
- package/src/reference/text-widths.ts +133 -0
- package/src/reference/types.ts +75 -8
- package/src/rules/catalog.ts +241 -31
- package/src/rules/settings.ts +10 -0
- package/src/session/PreferenceStore.ts +53 -0
- package/src/styles/global.css +322 -83
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
%% explico.cls — the book class of a course's LaTeX source.
|
|
2
|
+
%%
|
|
3
|
+
%% explico writes this file next to every LaTeX download, and builds the PDF
|
|
4
|
+
%% it offers from that same folder. Edit it freely in a download: it only sets
|
|
5
|
+
%% the layout and defines the commands the chapter files use.
|
|
6
|
+
%%
|
|
7
|
+
%% Engines: LuaLaTeX (preferred) or pdfLaTeX, TeX Live 2025 or later.
|
|
8
|
+
%%
|
|
9
|
+
%% Numbering follows the course website: parts and chapters are numbered
|
|
10
|
+
%% ‹part›.‹chapter›, sections ‹part›.‹chapter›.‹section›, and equations,
|
|
11
|
+
%% figures, tables, diagrams, worked examples and knowledge checks run per
|
|
12
|
+
%% chapter (‹part›.‹chapter›.‹n›) or, with \ExplicoFloatsByPart, per part
|
|
13
|
+
%% (‹part›.‹n›). LaTeX does the counting; explico checks every number against
|
|
14
|
+
%% the website when it builds the PDF.
|
|
15
|
+
\NeedsTeXFormat{LaTeX2e}
|
|
16
|
+
\ProvidesClass{explico}[2026/10/04 explico course book class]
|
|
17
|
+
|
|
18
|
+
%% `scripts`: the document holds Greek, Cyrillic, CJK or emoji (the exporter
|
|
19
|
+
%% sets it when it does), so LuaLaTeX loads the fallback fonts below.
|
|
20
|
+
\newif\ifexplico@scripts
|
|
21
|
+
\DeclareOption{scripts}{\explico@scriptstrue}
|
|
22
|
+
\DeclareOption*{\PassOptionsToClass{\CurrentOption}{book}}
|
|
23
|
+
\ProcessOptions\relax
|
|
24
|
+
\LoadClass[11pt,oneside,openany]{book}
|
|
25
|
+
|
|
26
|
+
%% --- Engine and fonts ------------------------------------------------------
|
|
27
|
+
\RequirePackage{iftex}
|
|
28
|
+
\RequirePackage{amsmath,amssymb,mathtools}
|
|
29
|
+
%% Rule N17's engine half, as on the website (src/reference/katex-delimiters.mjs):
|
|
30
|
+
%% a negative \delimitershortfall makes every \left...\right pair strictly taller
|
|
31
|
+
%% than its content, so a nest grows outward at each level. TeX's default (5pt)
|
|
32
|
+
%% lets nested pairs round to the same glyph.
|
|
33
|
+
\delimitershortfall=-1pt
|
|
34
|
+
%% Whether a text font sets Greek; if none does, a Greek letter in prose is
|
|
35
|
+
%% set as its math symbol (below, with the other Unicode characters).
|
|
36
|
+
\newif\ifexplico@greek
|
|
37
|
+
\ifPDFTeX
|
|
38
|
+
\RequirePackage[T1]{fontenc}
|
|
39
|
+
\RequirePackage{lmodern}
|
|
40
|
+
\RequirePackage{textcomp}
|
|
41
|
+
\RequirePackage{bm}
|
|
42
|
+
%% A character no pdfTeX font sets (accented Greek, Chinese, an emoji) stays
|
|
43
|
+
%% blank instead of stopping the compile, and the log says so in LuaLaTeX's
|
|
44
|
+
%% words, which the export turns into its warning about blank characters.
|
|
45
|
+
\def\UTFviii@undefined@err#1{%
|
|
46
|
+
\typeout{Missing character: There is no
|
|
47
|
+
\expandafter\UTFviii@splitcsname\string#1\relax\space in font pdftex!}}
|
|
48
|
+
\else
|
|
49
|
+
%% Latin Modern for text and math. unicode-math is also what lets a tagged
|
|
50
|
+
%% PDF carry MathML for every formula (luamml needs it); bm does not work
|
|
51
|
+
%% with it, so \bm becomes \boldsymbol.
|
|
52
|
+
\RequirePackage{unicode-math}
|
|
53
|
+
\providecommand{\bm}{\boldsymbol}
|
|
54
|
+
%% Latin Modern has no Greek, Cyrillic, Chinese, Japanese, Korean or emoji.
|
|
55
|
+
%% With `scripts`, prose in those scripts comes from fallback fonts: for each
|
|
56
|
+
%% script, the first of the fonts below this machine has (CMU Serif, from
|
|
57
|
+
%% TeX Live's cm-unicode, matches Latin Modern). A script none of them
|
|
58
|
+
%% covers stays blank, and the export warns about it.
|
|
59
|
+
\ifexplico@scripts
|
|
60
|
+
\def\explico@fallbacks{}
|
|
61
|
+
\def\explico@fallback#1#2{%
|
|
62
|
+
\let\explico@found\@empty
|
|
63
|
+
\@for\explico@candidate:=#1\do{%
|
|
64
|
+
\ifx\explico@found\@empty
|
|
65
|
+
\IfFontExistsTF{\explico@candidate}{%
|
|
66
|
+
\edef\explico@fallbacks{\explico@fallbacks"\explico@candidate:mode=harf;",}%
|
|
67
|
+
\let\explico@found\explico@candidate}{}%
|
|
68
|
+
\fi}%
|
|
69
|
+
\ifx\explico@found\@empty\else#2\fi}
|
|
70
|
+
\explico@fallback{CMU Serif,Noto Serif,DejaVu Serif,FreeSerif}{\explico@greektrue}
|
|
71
|
+
\explico@fallback{Noto Serif CJK SC,Noto Sans CJK SC,FandolSong,Source Han Serif SC}{}
|
|
72
|
+
\explico@fallback{Noto Color Emoji,Twemoji Mozilla,Symbola}{}
|
|
73
|
+
\ifx\explico@fallbacks\@empty\else
|
|
74
|
+
\directlua{luaotfload.add_fallback("explico", {\explico@fallbacks})}%
|
|
75
|
+
\setmainfont{Latin Modern Roman}[RawFeature={fallback=explico}]%
|
|
76
|
+
\fi
|
|
77
|
+
\fi
|
|
78
|
+
\fi
|
|
79
|
+
\RequirePackage{microtype}
|
|
80
|
+
|
|
81
|
+
%% --- Page and colour --------------------------------------------------------
|
|
82
|
+
\RequirePackage[margin=1in]{geometry}
|
|
83
|
+
\RequirePackage{xcolor}
|
|
84
|
+
\definecolor{explicoaccent}{HTML}{12775C}
|
|
85
|
+
\definecolor{explicoframe}{HTML}{9DB8AD}
|
|
86
|
+
\definecolor{explicoback}{HTML}{F3F8F6}
|
|
87
|
+
\definecolor{explicoasidecaution}{HTML}{B5651D}
|
|
88
|
+
\definecolor{explicoasidecautionback}{HTML}{FBF3EA}
|
|
89
|
+
\definecolor{explicorule}{HTML}{8A9A93}
|
|
90
|
+
|
|
91
|
+
%% --- Floats, tables and captions -------------------------------------------
|
|
92
|
+
\RequirePackage{graphicx}
|
|
93
|
+
\RequirePackage{array,booktabs,tabularx,longtable}
|
|
94
|
+
\RequirePackage[export]{adjustbox}
|
|
95
|
+
\RequirePackage{caption}
|
|
96
|
+
\RequirePackage{newfloat}
|
|
97
|
+
\DeclareFloatingEnvironment[
|
|
98
|
+
name=Diagram,
|
|
99
|
+
listname={List of Diagrams},
|
|
100
|
+
fileext=lod,
|
|
101
|
+
placement=htbp,
|
|
102
|
+
]{diagram}
|
|
103
|
+
%% Tagging names each float type's structures from TeX Live 2026 on, and a
|
|
104
|
+
%% caption in a type it was not told about stops LuaLaTeX. TeX Live 2025 has
|
|
105
|
+
%% no such key and tags every float alike.
|
|
106
|
+
\ExplSyntaxOn
|
|
107
|
+
\keys_if_exist:nnT { __tag/setup } { float/new }
|
|
108
|
+
{ \tagpdfsetup { float/new = diagram } }
|
|
109
|
+
\ExplSyntaxOff
|
|
110
|
+
%% Contents and lists: room for explico's numbers (`2.1`, `2.1.10`), wider
|
|
111
|
+
%% than the book class's one-level chapter numbers.
|
|
112
|
+
\RequirePackage{etoolbox}
|
|
113
|
+
\patchcmd{\l@chapter}{1.5em}{2.6em}{}{}
|
|
114
|
+
\renewcommand*{\l@section}{\@dottedtocline{1}{2.6em}{3.4em}}
|
|
115
|
+
\renewcommand*{\l@subsection}{\@dottedtocline{2}{6.0em}{4.2em}}
|
|
116
|
+
\renewcommand*{\l@figure}{\@dottedtocline{1}{0em}{3.4em}}
|
|
117
|
+
\let\l@table\l@figure
|
|
118
|
+
\let\l@diagram\l@figure
|
|
119
|
+
\captionsetup{font=small,labelsep=quad,format=plain,justification=justified,singlelinecheck=true}
|
|
120
|
+
\captionsetup[table]{position=top}
|
|
121
|
+
%% With \DocumentMetadata, which every export's main.tex has, the kernel's
|
|
122
|
+
%% tagging code sets a caption itself (latex-lab's \@makecaption, installed at
|
|
123
|
+
%% begin document) and none of the \captionsetup above applies. Its caption is
|
|
124
|
+
%% the kernel's: \abovecaptionskip above, \belowcaptionskip below, "Table 2.1:"
|
|
125
|
+
%% before the text. A table's caption stands above the table, so it gets the
|
|
126
|
+
%% same space on both sides, whichever code sets it (the caption package swaps
|
|
127
|
+
%% the two for `position=top`); and the label and the size are the ones the
|
|
128
|
+
%% caption package would give, and the web page shows: "Table 2.1", a quad,
|
|
129
|
+
%% the caption in small type.
|
|
130
|
+
\AtBeginEnvironment{table}{%
|
|
131
|
+
\setlength{\abovecaptionskip}{8pt}\setlength{\belowcaptionskip}{8pt}}
|
|
132
|
+
\ExplSyntaxOn
|
|
133
|
+
\socket_if_exist:nT { caption/label }
|
|
134
|
+
{
|
|
135
|
+
\NewSocketPlug { caption/label } { explico } { #1 \quad }
|
|
136
|
+
\AssignSocketPlug { caption/label } { explico }
|
|
137
|
+
\AddToHookWithArguments { cmd/@makecaption/before } { \small }
|
|
138
|
+
}
|
|
139
|
+
\ExplSyntaxOff
|
|
140
|
+
%% A float set where it stands, inside a memo or a worked example, which a
|
|
141
|
+
%% float cannot leave: the float package's [H]. Tagging then gives the float
|
|
142
|
+
%% its caption, as PDF/UA-2 asks. (TeX Live 2026 tags a minipage as a Div,
|
|
143
|
+
%% which a validator looks through, so a \captionof caption in one sits in
|
|
144
|
+
%% the middle of the box's text.) Without the float package: a minipage whose
|
|
145
|
+
%% \caption is the float's, as \captionof does it.
|
|
146
|
+
\newif\ifexplico@float
|
|
147
|
+
\IfFileExists{float.sty}{\RequirePackage{float}\explico@floattrue}{}
|
|
148
|
+
\ifexplico@float
|
|
149
|
+
\newenvironment{ExplicoHere}[1]{%
|
|
150
|
+
\def\explico@herekind{#1}\begin{#1}[H]\centering
|
|
151
|
+
}{\expandafter\end\expandafter{\explico@herekind}}
|
|
152
|
+
\else
|
|
153
|
+
\newenvironment{ExplicoHere}[1]{%
|
|
154
|
+
\par\medskip\noindent\begin{minipage}{\linewidth}\centering
|
|
155
|
+
\captionsetup{type=#1}%
|
|
156
|
+
}{\end{minipage}\par\medskip}
|
|
157
|
+
\fi
|
|
158
|
+
%% explico's short caption, run in bold before the long one.
|
|
159
|
+
\newcommand*{\ExplicoCaptionTitle}[1]{\textbf{#1}}
|
|
160
|
+
|
|
161
|
+
%% --- Diagrams ---------------------------------------------------------------
|
|
162
|
+
\RequirePackage{tikz}
|
|
163
|
+
\usetikzlibrary{arrows.meta}
|
|
164
|
+
\tikzset{
|
|
165
|
+
explico diagram node/.style={
|
|
166
|
+
draw=explicorule, fill=explicoback, rounded corners=3pt, line width=0.5pt,
|
|
167
|
+
align=center, inner sep=3pt, font=\small,
|
|
168
|
+
},
|
|
169
|
+
explico diagram edge/.style={
|
|
170
|
+
draw=explicorule, line width=0.6pt, -{Stealth[length=5pt,width=4pt]},
|
|
171
|
+
},
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
%% --- Boxes: memos, notes, asides, worked examples, checks ------------------
|
|
175
|
+
\RequirePackage[most]{tcolorbox}
|
|
176
|
+
\tcbset{
|
|
177
|
+
explico/.style={
|
|
178
|
+
enhanced, breakable, colback=explicoback, colframe=explicoframe,
|
|
179
|
+
boxrule=0.5pt, arc=2pt, left=6pt, right=6pt, top=4pt, bottom=4pt,
|
|
180
|
+
fonttitle=\bfseries\small, coltitle=black, colbacktitle=explicoback!60!white,
|
|
181
|
+
titlerule=0.4pt, before skip=10pt plus 2pt, after skip=10pt plus 2pt,
|
|
182
|
+
},
|
|
183
|
+
}
|
|
184
|
+
\RequirePackage{alphalph}
|
|
185
|
+
\RequirePackage{enumitem}
|
|
186
|
+
|
|
187
|
+
%% --- Unicode in text that the default fonts lack ---------------------------
|
|
188
|
+
\RequirePackage{newunicodechar}
|
|
189
|
+
\newunicodechar{°}{\ifmmode^\circ\else\textdegree\fi}
|
|
190
|
+
\newunicodechar{−}{\ensuremath{-}}
|
|
191
|
+
\newunicodechar{×}{\ensuremath{\times}}
|
|
192
|
+
\newunicodechar{±}{\ensuremath{\pm}}
|
|
193
|
+
\newunicodechar{≤}{\ensuremath{\le}}
|
|
194
|
+
\newunicodechar{≥}{\ensuremath{\ge}}
|
|
195
|
+
\newunicodechar{≈}{\ensuremath{\approx}}
|
|
196
|
+
\newunicodechar{≠}{\ensuremath{\neq}}
|
|
197
|
+
\newunicodechar{→}{\ensuremath{\rightarrow}}
|
|
198
|
+
\newunicodechar{←}{\ensuremath{\leftarrow}}
|
|
199
|
+
\newunicodechar{↑}{\ensuremath{\uparrow}}
|
|
200
|
+
\newunicodechar{↓}{\ensuremath{\downarrow}}
|
|
201
|
+
\newunicodechar{⟨}{\ensuremath{\langle}}
|
|
202
|
+
\newunicodechar{⟩}{\ensuremath{\rangle}}
|
|
203
|
+
\newunicodechar{⋮}{\ensuremath{\vdots}}
|
|
204
|
+
\newunicodechar{√}{\ensuremath{\surd}}
|
|
205
|
+
\newunicodechar{∞}{\ensuremath{\infty}}
|
|
206
|
+
\newunicodechar{′}{\ensuremath{'}}
|
|
207
|
+
\newunicodechar{𝒩}{\ensuremath{\mathcal{N}}}
|
|
208
|
+
\newunicodechar{①}{\textcircled{\scriptsize 1}}
|
|
209
|
+
\newunicodechar{②}{\textcircled{\scriptsize 2}}
|
|
210
|
+
\newunicodechar{③}{\textcircled{\scriptsize 3}}
|
|
211
|
+
\newunicodechar{④}{\textcircled{\scriptsize 4}}
|
|
212
|
+
\newunicodechar{⑤}{\textcircled{\scriptsize 5}}
|
|
213
|
+
\newunicodechar{₀}{\textsubscript{0}}
|
|
214
|
+
\newunicodechar{₁}{\textsubscript{1}}
|
|
215
|
+
\newunicodechar{₂}{\textsubscript{2}}
|
|
216
|
+
\newunicodechar{₃}{\textsubscript{3}}
|
|
217
|
+
\newunicodechar{¹}{\textsuperscript{1}}
|
|
218
|
+
\newunicodechar{²}{\textsuperscript{2}}
|
|
219
|
+
\newunicodechar{³}{\textsuperscript{3}}
|
|
220
|
+
%% A Greek letter on its own is a symbol (the polar coordinates ρ and φ in a
|
|
221
|
+
%% caption, which holds no math): it is set as its math symbol. Inside a Greek
|
|
222
|
+
%% word, which the exporter marks \ExplicoGreekWord{…}, it is a letter, set
|
|
223
|
+
%% from the text font's Greek where one is loaded (`scripts`).
|
|
224
|
+
\newif\ifexplico@word
|
|
225
|
+
\DeclareRobustCommand{\ExplicoGreekWord}[1]{{\explico@wordtrue#1}}
|
|
226
|
+
%% Protected, as \ensuremath is: the text of an equation is expanded for its
|
|
227
|
+
%% tagging (alt text, MathML), and an expandable body breaks it there.
|
|
228
|
+
\protected\def\explico@greekletter#1#2{%
|
|
229
|
+
\ifmmode#2\else
|
|
230
|
+
\ifexplico@word
|
|
231
|
+
\ifexplico@greek\char#1\relax\else\ensuremath{#2}\fi
|
|
232
|
+
\else\ensuremath{#2}\fi
|
|
233
|
+
\fi}
|
|
234
|
+
\newunicodechar{α}{\explico@greekletter{"03B1}{\alpha}}
|
|
235
|
+
\newunicodechar{β}{\explico@greekletter{"03B2}{\beta}}
|
|
236
|
+
\newunicodechar{γ}{\explico@greekletter{"03B3}{\gamma}}
|
|
237
|
+
\newunicodechar{δ}{\explico@greekletter{"03B4}{\delta}}
|
|
238
|
+
\newunicodechar{ε}{\explico@greekletter{"03B5}{\varepsilon}}
|
|
239
|
+
\newunicodechar{θ}{\explico@greekletter{"03B8}{\theta}}
|
|
240
|
+
\newunicodechar{λ}{\explico@greekletter{"03BB}{\lambda}}
|
|
241
|
+
\newunicodechar{μ}{\explico@greekletter{"03BC}{\mu}}
|
|
242
|
+
\newunicodechar{π}{\explico@greekletter{"03C0}{\pi}}
|
|
243
|
+
\newunicodechar{ρ}{\explico@greekletter{"03C1}{\rho}}
|
|
244
|
+
\newunicodechar{σ}{\explico@greekletter{"03C3}{\sigma}}
|
|
245
|
+
\newunicodechar{τ}{\explico@greekletter{"03C4}{\tau}}
|
|
246
|
+
\newunicodechar{φ}{\explico@greekletter{"03C6}{\varphi}}
|
|
247
|
+
\newunicodechar{ω}{\explico@greekletter{"03C9}{\omega}}
|
|
248
|
+
\newunicodechar{Γ}{\explico@greekletter{"0393}{\Gamma}}
|
|
249
|
+
\newunicodechar{Δ}{\explico@greekletter{"0394}{\Delta}}
|
|
250
|
+
\newunicodechar{Θ}{\explico@greekletter{"0398}{\Theta}}
|
|
251
|
+
\newunicodechar{Λ}{\explico@greekletter{"039B}{\Lambda}}
|
|
252
|
+
\newunicodechar{Π}{\explico@greekletter{"03A0}{\Pi}}
|
|
253
|
+
\newunicodechar{Σ}{\explico@greekletter{"03A3}{\Sigma}}
|
|
254
|
+
\newunicodechar{Φ}{\explico@greekletter{"03A6}{\Phi}}
|
|
255
|
+
\newunicodechar{Ω}{\explico@greekletter{"03A9}{\Omega}}
|
|
256
|
+
|
|
257
|
+
%% --- Links ------------------------------------------------------------------
|
|
258
|
+
\RequirePackage[colorlinks,linkcolor=explicoaccent,urlcolor=explicoaccent,citecolor=explicoaccent,bookmarksnumbered]{hyperref}
|
|
259
|
+
\pdfstringdefDisableCommands{\let\ExplicoGreekWord\@firstofone}
|
|
260
|
+
|
|
261
|
+
%% --- Numbering --------------------------------------------------------------
|
|
262
|
+
\renewcommand{\thepart}{\arabic{part}}
|
|
263
|
+
\counterwithin*{chapter}{part}
|
|
264
|
+
\renewcommand{\thechapter}{\thepart.\arabic{chapter}}
|
|
265
|
+
\newcounter{explicoexample}
|
|
266
|
+
\newcounter{explicocheck}
|
|
267
|
+
\newcounter{explicomemo}[chapter]
|
|
268
|
+
\renewcommand{\theexplicomemo}{\alphalph{\value{explicomemo}}}
|
|
269
|
+
\counterwithin{equation}{chapter}
|
|
270
|
+
\counterwithin{figure}{chapter}
|
|
271
|
+
\counterwithin{table}{chapter}
|
|
272
|
+
\counterwithin{diagram}{chapter}
|
|
273
|
+
\counterwithin{explicoexample}{chapter}
|
|
274
|
+
\counterwithin{explicocheck}{chapter}
|
|
275
|
+
%% Floats, examples and checks run on across each part's chapters.
|
|
276
|
+
\newcommand{\ExplicoFloatsByPart}{%
|
|
277
|
+
\@for\explico@kind:=equation,figure,table,diagram,explicoexample,explicocheck\do{%
|
|
278
|
+
\expandafter\counterwithout\expandafter{\explico@kind}{chapter}%
|
|
279
|
+
\expandafter\counterwithin\expandafter{\explico@kind}{part}%
|
|
280
|
+
}%
|
|
281
|
+
}
|
|
282
|
+
%% Outline numbering down to explico's `numbering.sections.depth`
|
|
283
|
+
%% (2 = ## … 6 = ######); 1 numbers no sections.
|
|
284
|
+
\newcommand{\ExplicoSectionDepth}[1]{%
|
|
285
|
+
\setcounter{secnumdepth}{\numexpr#1-1\relax}%
|
|
286
|
+
\setcounter{tocdepth}{\numexpr#1-1\relax}%
|
|
287
|
+
}
|
|
288
|
+
\ExplicoSectionDepth{4}
|
|
289
|
+
%% A chapter on its own starts where the course leaves it: part and chapter
|
|
290
|
+
%% number, and how many floats of each kind come earlier in the part.
|
|
291
|
+
%% #1 part, #2 chapter, #3 equations, #4 tables, #5 figures, #6 diagrams,
|
|
292
|
+
%% #7 checks, #8 examples.
|
|
293
|
+
\newcommand{\ExplicoStartChapterAt}[8]{%
|
|
294
|
+
\setcounter{part}{#1}%
|
|
295
|
+
\setcounter{chapter}{\numexpr#2-1\relax}%
|
|
296
|
+
\gdef\explico@offsets{{#3}{#4}{#5}{#6}{#7}{#8}}%
|
|
297
|
+
}
|
|
298
|
+
\gdef\explico@offsets{}
|
|
299
|
+
%% After \chapter, so a chapter's own reset cannot undo them.
|
|
300
|
+
\newcommand{\ExplicoApplyOffsets}{%
|
|
301
|
+
\ifx\explico@offsets\@empty\else
|
|
302
|
+
\expandafter\explico@applyoffsets\explico@offsets
|
|
303
|
+
\gdef\explico@offsets{}%
|
|
304
|
+
\fi
|
|
305
|
+
}
|
|
306
|
+
\newcommand{\explico@applyoffsets}[6]{%
|
|
307
|
+
\setcounter{equation}{#1}\setcounter{table}{#2}\setcounter{figure}{#3}%
|
|
308
|
+
\setcounter{diagram}{#4}\setcounter{explicocheck}{#5}\setcounter{explicoexample}{#6}%
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
%% --- Chapter front line -----------------------------------------------------
|
|
312
|
+
%% Under a chapter's title: where it comes from and where its live version is.
|
|
313
|
+
\newcommand{\ExplicoSource}[3]{%
|
|
314
|
+
\begingroup\small\color{black!65}%
|
|
315
|
+
\noindent From \emph{#1}%
|
|
316
|
+
\if\relax\detokenize{#2}\relax\else, version~#2\fi.%
|
|
317
|
+
\if\relax\detokenize{#3}\relax\else\ Interactive version: \url{#3}\fi
|
|
318
|
+
\par\endgroup\medskip
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
%% --- Books: a part's or the course's PDF ------------------------------------
|
|
322
|
+
%% The title page. #1 title, #2 what it belongs to (empty for the course),
|
|
323
|
+
%% #3 content version, #4 authors, #5 website.
|
|
324
|
+
\newcommand{\ExplicoTitlePage}[5]{%
|
|
325
|
+
%% The title page shares page number i with the contents: no anchor of its own.
|
|
326
|
+
\hypersetup{pageanchor=false}%
|
|
327
|
+
\begin{titlepage}
|
|
328
|
+
\centering
|
|
329
|
+
\vspace*{0.18\textheight}
|
|
330
|
+
{\Huge\bfseries #1\par}
|
|
331
|
+
\if\relax\detokenize{#2}\relax\else\vspace{0.8em}{\Large #2\par}\fi
|
|
332
|
+
\if\relax\detokenize{#4}\relax\else\vspace{2.5em}{\large #4\par}\fi
|
|
333
|
+
\vfill
|
|
334
|
+
{Content version~#3\par}
|
|
335
|
+
\if\relax\detokenize{#5}\relax\else\vspace{0.4em}{\small\url{#5}\par}\fi
|
|
336
|
+
\end{titlepage}%
|
|
337
|
+
\hypersetup{pageanchor=true}%
|
|
338
|
+
}
|
|
339
|
+
%% Under a chapter's title in a book: its live version. The title page names
|
|
340
|
+
%% the course and its version once.
|
|
341
|
+
\newcommand{\ExplicoInteractive}[1]{%
|
|
342
|
+
\begingroup\small\color{black!65}%
|
|
343
|
+
\noindent Interactive version: \url{#1}\par\endgroup\medskip
|
|
344
|
+
}
|
|
345
|
+
%% A part opens on its own page, numbered as on the website.
|
|
346
|
+
\newcommand{\ExplicoPart}[2]{\setcounter{part}{\numexpr#1-1\relax}\part{#2}}
|
|
347
|
+
|
|
348
|
+
%% --- Notation ---------------------------------------------------------------
|
|
349
|
+
%% \explain{key}{tex} and \slot{key}{tex} are explico's markers in math: the
|
|
350
|
+
%% website opens a card for the key; on paper they print their content.
|
|
351
|
+
\providecommand{\explain}[2]{#2}
|
|
352
|
+
\providecommand{\slot}[2]{#2}
|
|
353
|
+
%% \ExplicoNotation{target}{tex}: a formula's symbol that links to its notation entry
|
|
354
|
+
%% (the serializer writes it only where the book has that entry).
|
|
355
|
+
\providecommand{\ExplicoNotation}[2]{\hyperlink{#1}{#2}}
|
|
356
|
+
%% A term in prose with a notation card on the website.
|
|
357
|
+
\newcommand{\ExplicoTerm}[2]{#2}
|
|
358
|
+
|
|
359
|
+
%% --- Cross-references ---------------------------------------------------------
|
|
360
|
+
%% #1 label, #2 text before the number, #3 text after it.
|
|
361
|
+
\newcommand{\ExplicoRef}[3]{\hyperref[#1]{#2\ref*{#1}#3}}
|
|
362
|
+
\newcommand{\ExplicoEqRef}[1]{\hyperref[#1]{(\ref*{#1})}}
|
|
363
|
+
|
|
364
|
+
%% --- Memos --------------------------------------------------------------------
|
|
365
|
+
\newenvironment{ExplicoMemo}[1]{%
|
|
366
|
+
\refstepcounter{explicomemo}%
|
|
367
|
+
\begin{tcolorbox}[explico,title={Memo~\theexplicomemo:\enspace #1}]%
|
|
368
|
+
}{\end{tcolorbox}}
|
|
369
|
+
\newcommand{\ExplicoMemoMark}[1]{\textsuperscript{\hyperref[#1]{\ref*{#1}}}}
|
|
370
|
+
|
|
371
|
+
%% --- Short notes ----------------------------------------------------------------
|
|
372
|
+
\newenvironment{ExplicoNote}[2]{%
|
|
373
|
+
\begin{tcolorbox}[explico,colback=white,title={#2}]%
|
|
374
|
+
\hypertarget{#1}{}%
|
|
375
|
+
}{\end{tcolorbox}}
|
|
376
|
+
\newcommand{\ExplicoNoteMark}[2]{\hyperlink{#1}{#2}}
|
|
377
|
+
|
|
378
|
+
%% --- Starlight asides -------------------------------------------------------------
|
|
379
|
+
\newenvironment{ExplicoAside}[2]{%
|
|
380
|
+
\def\explico@variant{#1}\def\explico@caution{caution}\def\explico@danger{danger}%
|
|
381
|
+
\ifx\explico@variant\explico@caution
|
|
382
|
+
\tcbset{explico/.append style={colframe=explicoasidecaution,colback=explicoasidecautionback}}%
|
|
383
|
+
\else\ifx\explico@variant\explico@danger
|
|
384
|
+
\tcbset{explico/.append style={colframe=explicoasidecaution,colback=explicoasidecautionback}}%
|
|
385
|
+
\fi\fi
|
|
386
|
+
\begin{tcolorbox}[explico,title={#2}]%
|
|
387
|
+
}{\end{tcolorbox}}
|
|
388
|
+
|
|
389
|
+
%% --- Worked examples ---------------------------------------------------------------
|
|
390
|
+
\newenvironment{ExplicoExamples}[1]{%
|
|
391
|
+
\refstepcounter{explicoexample}%
|
|
392
|
+
\begin{tcolorbox}[explico,title={Example~\theexplicoexample:\enspace #1}]%
|
|
393
|
+
}{\end{tcolorbox}}
|
|
394
|
+
\newcommand{\ExplicoExample}[1]{\par\medskip\noindent\textbf{#1}\par\nopagebreak\smallskip}
|
|
395
|
+
|
|
396
|
+
%% --- Knowledge checks -----------------------------------------------------------
|
|
397
|
+
\newenvironment{ExplicoCheck}[1]{%
|
|
398
|
+
\refstepcounter{explicocheck}%
|
|
399
|
+
\begin{tcolorbox}[explico,colback=white,title={Knowledge check~\theexplicocheck:\enspace #1}]%
|
|
400
|
+
}{\end{tcolorbox}}
|
|
401
|
+
\newcommand{\ExplicoCheckAnswerNote}[1]{\par\smallskip{\small\itshape Answers: \hyperlink{#1}{end of the chapter}.}\par}
|
|
402
|
+
|
|
403
|
+
%% --- References ---------------------------------------------------------------------
|
|
404
|
+
%% The chapter's reference list, numbered as on the website.
|
|
405
|
+
\newenvironment{ExplicoReferences}[1]{%
|
|
406
|
+
\section*{References}%
|
|
407
|
+
\list{\@biblabel{\@arabic\c@enumiv}}{%
|
|
408
|
+
\settowidth\labelwidth{\@biblabel{#1}}%
|
|
409
|
+
\leftmargin\labelwidth\advance\leftmargin\labelsep
|
|
410
|
+
\@openbib@code\usecounter{enumiv}\let\p@enumiv\@empty
|
|
411
|
+
\renewcommand\theenumiv{\@arabic\c@enumiv}}%
|
|
412
|
+
\sloppy\clubpenalty4000\@clubpenalty\clubpenalty\widowpenalty4000\sfcode`\.\@m
|
|
413
|
+
}{\def\@noitemerr{\@latex@warning{Empty `ExplicoReferences' environment}}\endlist}
|
|
414
|
+
|
|
415
|
+
\endinput
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { StaticPage } from '../static-tree.js';
|
|
2
|
+
import '../html-tree.js';
|
|
3
|
+
import 'parse5';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The LaTeX source counts its own numbers (`\label`, `\ref`), so an edited
|
|
7
|
+
* download renumbers itself. When explico compiles the source unchanged,
|
|
8
|
+
* every number LaTeX prints must be the number the website prints: this
|
|
9
|
+
* module reads both and lists any disagreement, which fails the build.
|
|
10
|
+
*/
|
|
11
|
+
/** The number the website gives each labelled anchor of a page, by LaTeX label. */
|
|
12
|
+
declare function websiteNumbers(page: StaticPage, chapterNumber: string): Map<string, string>;
|
|
13
|
+
/** `\newlabel{label}{{number}{page}…}` lines of a LaTeX `.aux` file. */
|
|
14
|
+
declare function auxLabels(aux: string): Map<string, string>;
|
|
15
|
+
/** Every label whose LaTeX number differs from the website's, or that LaTeX never set. */
|
|
16
|
+
declare function numberingMismatches(website: ReadonlyMap<string, string>, latex: ReadonlyMap<string, string>): string[];
|
|
17
|
+
|
|
18
|
+
export { auxLabels, numberingMismatches, websiteNumbers };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { labelOf } from "./serialize.js";
|
|
2
|
+
function websiteNumbers(page, chapterNumber) {
|
|
3
|
+
const numbers = /* @__PURE__ */ new Map([[labelOf(page.route, "_top"), chapterNumber]]);
|
|
4
|
+
const add = (anchor, number) => {
|
|
5
|
+
if (anchor && number) numbers.set(labelOf(page.route, anchor), number);
|
|
6
|
+
};
|
|
7
|
+
const visit = (blocks) => {
|
|
8
|
+
for (const block of blocks) {
|
|
9
|
+
switch (block.kind) {
|
|
10
|
+
case "heading":
|
|
11
|
+
add(block.anchor, block.number);
|
|
12
|
+
break;
|
|
13
|
+
case "equation":
|
|
14
|
+
case "figure":
|
|
15
|
+
case "table":
|
|
16
|
+
case "diagram":
|
|
17
|
+
case "examples":
|
|
18
|
+
case "check":
|
|
19
|
+
add(block.anchor, block.number);
|
|
20
|
+
break;
|
|
21
|
+
case "memo":
|
|
22
|
+
add(block.anchor, block.label);
|
|
23
|
+
break;
|
|
24
|
+
default:
|
|
25
|
+
break;
|
|
26
|
+
}
|
|
27
|
+
if (block.kind === "list") block.items.forEach(visit);
|
|
28
|
+
if (block.kind === "examples") block.items.forEach((item) => visit(item.children));
|
|
29
|
+
if ("children" in block && block.kind !== "paragraph" && block.kind !== "heading" && Array.isArray(block.children)) {
|
|
30
|
+
visit(block.children);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
visit(page.blocks);
|
|
35
|
+
return numbers;
|
|
36
|
+
}
|
|
37
|
+
function auxLabels(aux) {
|
|
38
|
+
const labels = /* @__PURE__ */ new Map();
|
|
39
|
+
for (const match of aux.matchAll(/^\\newlabel\{([^}]*)\}\{\{([^}]*)\}/gmu)) {
|
|
40
|
+
labels.set(match[1], match[2]);
|
|
41
|
+
}
|
|
42
|
+
return labels;
|
|
43
|
+
}
|
|
44
|
+
function numberingMismatches(website, latex) {
|
|
45
|
+
const problems = [];
|
|
46
|
+
for (const [label, expected] of website) {
|
|
47
|
+
const actual = latex.get(label);
|
|
48
|
+
if (actual === void 0) problems.push(`${label}: no number in LaTeX (website: ${expected})`);
|
|
49
|
+
else if (actual !== expected) problems.push(`${label}: LaTeX ${actual}, website ${expected}`);
|
|
50
|
+
}
|
|
51
|
+
return problems;
|
|
52
|
+
}
|
|
53
|
+
export {
|
|
54
|
+
auxLabels,
|
|
55
|
+
numberingMismatches,
|
|
56
|
+
websiteNumbers
|
|
57
|
+
};
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { ContentSegment } from '../../../reference/mixed-content.js';
|
|
2
|
+
import { NotationEntry, StaticPage, DiagramGeometry, Inline } from '../static-tree.js';
|
|
3
|
+
import '../../../reference/gate-math.js';
|
|
4
|
+
import '../../../reference/types.js';
|
|
5
|
+
import '../html-tree.js';
|
|
6
|
+
import 'parse5';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Serialize explico's static reading tree to the LaTeX of one chapter, written
|
|
10
|
+
* against `explico.cls`. The output is source a person can read and edit:
|
|
11
|
+
* explico's blocks are named environments, cross-references are `\ref`s to
|
|
12
|
+
* labels, and numbers are LaTeX's own (checked against the website after
|
|
13
|
+
* compiling, see `numbering.ts`).
|
|
14
|
+
*/
|
|
15
|
+
/** What the serializer needs to know beyond the page itself. */
|
|
16
|
+
interface ChapterContext {
|
|
17
|
+
readonly page: StaticPage;
|
|
18
|
+
/** Routes of every page in this document; a reference to one becomes a `\ref`. */
|
|
19
|
+
readonly documentRoutes: ReadonlySet<string>;
|
|
20
|
+
/** Published course root, for links that leave the document. */
|
|
21
|
+
readonly canonicalBaseUrl?: string;
|
|
22
|
+
/** Picture files written for this chapter, by float anchor (`fig-…`), relative to the document. */
|
|
23
|
+
readonly pictures: ReadonlyMap<string, string>;
|
|
24
|
+
/** Answers of this chapter's checks, by assessment id, in authored order. */
|
|
25
|
+
readonly checkItems: ReadonlyMap<string, readonly CheckItem[]>;
|
|
26
|
+
/** Course title, version and the chapter's live URL for the front line. */
|
|
27
|
+
readonly source?: {
|
|
28
|
+
readonly course: string;
|
|
29
|
+
readonly version?: string;
|
|
30
|
+
readonly url?: string;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* A chapter of a part's or the course's book: its citation keys gain the
|
|
34
|
+
* chapter (`projectiles/projectile-range/openstax`), since each chapter
|
|
35
|
+
* keeps its own reference list numbered as on its page; its notation is in
|
|
36
|
+
* the book's appendix, not after the chapter; and under its title is only
|
|
37
|
+
* the link to its live version, the title page naming the course.
|
|
38
|
+
*/
|
|
39
|
+
readonly inBook?: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Keys with an entry in the document's notation appendix, so a formula's
|
|
42
|
+
* `\explain{key}{…}` can link to it. Absent for a chapter's own document,
|
|
43
|
+
* which has no appendix: its markers print their TeX, as the class does.
|
|
44
|
+
*/
|
|
45
|
+
readonly notationTargets?: ReadonlySet<string>;
|
|
46
|
+
}
|
|
47
|
+
interface CheckItem {
|
|
48
|
+
readonly itemId: string;
|
|
49
|
+
readonly type: 'single-choice' | 'numeric';
|
|
50
|
+
readonly promptSegments: readonly ContentSegment[];
|
|
51
|
+
readonly explanationSegments: readonly ContentSegment[];
|
|
52
|
+
readonly options?: readonly {
|
|
53
|
+
readonly id: string;
|
|
54
|
+
readonly label: string;
|
|
55
|
+
/** The label as text and math (manifest v30); without it, the label is text. */
|
|
56
|
+
readonly labelSegments?: readonly ContentSegment[];
|
|
57
|
+
}[];
|
|
58
|
+
readonly correctOptionId?: string;
|
|
59
|
+
readonly answer?: {
|
|
60
|
+
readonly value: number;
|
|
61
|
+
readonly tolerance: number;
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/** A LaTeX label for an anchor on a page: unique across a whole book. */
|
|
65
|
+
declare function labelOf(route: string, anchor: string): string;
|
|
66
|
+
declare function escapeText(text: string): string;
|
|
67
|
+
/**
|
|
68
|
+
* Rewrites each `\explain{key}{tex}` whose key `linkTo` names as
|
|
69
|
+
* `\ExplicoNotation{target}{tex}`, a link to the notation entry; any other
|
|
70
|
+
* marker stays, and the class prints its TeX. Brace-aware, so a body with
|
|
71
|
+
* nested groups is kept whole. A link cannot hold another, so the outermost
|
|
72
|
+
* linked marker wins: `\dot{x}` links to the time derivative, and the markers
|
|
73
|
+
* inside it print their TeX.
|
|
74
|
+
*/
|
|
75
|
+
declare function linkExplains(tex: string, linkTo: (key: string) => string | undefined): string;
|
|
76
|
+
/**
|
|
77
|
+
* explico's `<Diagram>` in TikZ, from the layout Dagre gave it at build time:
|
|
78
|
+
* the same boxes and edges as the website, with LaTeX setting the text and the
|
|
79
|
+
* math. Coordinates are scaled to the text width; type keeps its size.
|
|
80
|
+
*/
|
|
81
|
+
declare function diagramTikz(geometry: DiagramGeometry, writer: {
|
|
82
|
+
inlines(inlines: readonly Inline[]): string;
|
|
83
|
+
}): string;
|
|
84
|
+
/** The LaTeX of one chapter: `\chapter`, its body, references, notation and answers. */
|
|
85
|
+
declare function serializeChapter(context: ChapterContext): string;
|
|
86
|
+
/**
|
|
87
|
+
* A part's opener in a book: `\ExplicoPart`, numbered as on the website, then
|
|
88
|
+
* the text of the part's own page (its introduction, scope and objectives).
|
|
89
|
+
*/
|
|
90
|
+
declare function serializePartOpener(context: ChapterContext, part: {
|
|
91
|
+
readonly ordinal: number;
|
|
92
|
+
readonly label: string;
|
|
93
|
+
}): string;
|
|
94
|
+
/** A symbol in a book's notation appendix: its entry, the page that defines it, and the chapter it is local to. */
|
|
95
|
+
interface AppendixNotation {
|
|
96
|
+
readonly entry: NotationEntry;
|
|
97
|
+
readonly page: StaticPage;
|
|
98
|
+
/** `2.2` for a symbol only one chapter defines; none for a shared one. */
|
|
99
|
+
readonly chapter?: string;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* The book's notation appendix: every symbol its chapters use, in the order
|
|
103
|
+
* they first appear, each with its meaning, units and defining formula.
|
|
104
|
+
*/
|
|
105
|
+
declare function serializeNotationAppendix(entries: readonly AppendixNotation[], context: Omit<ChapterContext, 'page'>): string;
|
|
106
|
+
/** The book's abbreviation appendix: each abbreviation and what it stands for. */
|
|
107
|
+
declare function serializeAbbreviationAppendix(abbreviations: readonly {
|
|
108
|
+
readonly abbr: string;
|
|
109
|
+
readonly expansion: string;
|
|
110
|
+
}[]): string;
|
|
111
|
+
|
|
112
|
+
export { type AppendixNotation, type ChapterContext, type CheckItem, diagramTikz, escapeText, labelOf, linkExplains, serializeAbbreviationAppendix, serializeChapter, serializeNotationAppendix, serializePartOpener };
|