generator-latex-template 2026.10.13 → 2026.10.16
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/README.md +12 -153
- package/generators/app/CLAUDE.md +4 -2
- package/generators/app/index.js +111 -5
- package/generators/app/options.js +62 -49
- package/generators/app/templates/.github/dependabot.yml +3 -0
- package/generators/app/templates/.github/workflows/check.yml +42 -18
- package/generators/app/templates/.vscode/extensions.json +3 -2
- package/generators/app/templates/Dockerfile.dante +1 -8
- package/generators/app/templates/Makefile +59 -22
- package/generators/app/templates/README.en.md +393 -368
- package/generators/app/templates/Texlivefile +17 -1
- package/generators/app/templates/abbreviations.example.en.tex +1 -1
- package/generators/app/templates/authorarchive.preamble.en.tex +15 -0
- package/generators/app/templates/docs/latex-setup.md +2 -1
- package/generators/app/templates/docs/thesis-checklist.md +1 -1
- package/generators/app/templates/dot.aspell.de.pws +14 -1
- package/generators/app/templates/dot.aspell.en.pws +14 -1
- package/generators/app/templates/dot.dockerignore +1 -1
- package/generators/app/templates/dot.gitignore +10 -11
- package/generators/app/templates/dot.textidote +6 -0
- package/generators/app/templates/dot.textidote.replacements +40 -0
- package/generators/app/templates/dot.textlintrc.json +10 -2
- package/generators/app/templates/embedfile.preamble.en.tex +3 -4
- package/generators/app/templates/floats.example.de.tex +1 -1
- package/generators/app/templates/floats.example.en.tex +1 -1
- package/generators/app/templates/font.preamble.en.tex +12 -8
- package/generators/app/templates/latexmkrc +13 -2
- package/generators/app/templates/localSettings.yaml +4 -0
- package/generators/app/templates/logos/README.md +10 -0
- package/generators/app/templates/logos/thu-logo.png +0 -0
- package/generators/app/templates/logos/uhh-logo.pdf +0 -0
- package/generators/app/templates/main.de.tex +121 -65
- package/generators/app/templates/main.en.tex +124 -68
- package/generators/app/templates/mermaid.example.en.tex +69 -0
- package/generators/app/templates/minted.example.en.tex +1 -1
- package/generators/app/templates/mwe-main.de.tex +3 -2
- package/generators/app/templates/mwe-main.en.tex +3 -2
- package/generators/app/templates/paralist.example.en.tex +3 -3
- package/generators/app/templates/plantuml.example.en.tex +77 -21
- package/generators/app/templates/puppeteer.json +3 -0
- package/generators/app/templates/scientific-thesis-cover.preamble.de.tex +3 -3
- package/generators/app/templates/scientific-thesis-cover.preamble.en.tex +3 -3
- package/generators/app/templates/subfig.example.en.tex +1 -1
- package/generators/app/templates/tables.example.en.tex +19 -0
- package/generators/app/templates/thesis-additions.examples.en.tex +3 -3
- package/generators/app/templates/tikzuml.example.en.tex +74 -38
- package/generators/app/templates/todos.example.en.tex +1 -1
- package/generators/app/templates/uml.example.en.tex +81 -0
- package/generators/app/templates/uml.mermaid.preamble.en.tex +54 -0
- package/generators/app/templates/uml.plantuml.preamble.en.tex +24 -4
- package/generators/app/templates/uml.preamble.en.tex +14 -0
- package/generators/app/templates/vscode.settings.json +20 -11
- package/generators/app/templates/xcolor.preamble.de.tex +4 -0
- package/generators/app/templates/zref-clever.example.en.tex +1 -1
- package/generators/app/templates/zref-vario.example.en.tex +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,20 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
> Generates latex templates (e.g., for thesis, workshops, conferences, IEEEtran, LNCS, ...) out of "micro-templates"
|
|
4
4
|
|
|
5
|
-
## Talks and papers
|
|
6
|
-
|
|
7
|
-
- Paper: [Oliver Kopp - The LaTeX template generator: How micro-templates reduce template maintenance effort](https://tug.org/TUGboat/tb44-2/tb137kopp-microtemplates.html)
|
|
8
|
-
- Talk: [Oliver Kopp - The LaTeX Template Generator - DANTE Herbsttagung 2019](https://github.com/dante-ev/Vortraege_Tagungen/blob/master/2019-Herbst/Oliver%20Kopp%20-%20The%20LaTeX%20Template%20Generator%20-%20dante2019-herbst.pdf) - a talk on the motivation, user experience, and the contribution
|
|
9
|
-
|
|
10
5
|
## Background information
|
|
11
6
|
|
|
12
|
-
|
|
7
|
+
LaTeX templates abound.
|
|
13
8
|
All of them make use of certain packages such as [hyperref], [listings], or [minted].
|
|
14
9
|
The packages have to be a) included in the `.tex` file somehow and b) configured.
|
|
15
10
|
Moreover, some packages offer interfaces (such as new commands or new environments) to users.
|
|
16
11
|
Minimal examples help to understand how a package works.
|
|
17
12
|
|
|
18
|
-
The aim of the repository is to provide for each common
|
|
13
|
+
The aim of the repository is to provide for each common LaTeX package
|
|
19
14
|
|
|
20
15
|
1. Configuration
|
|
21
16
|
2. Usage example
|
|
@@ -30,7 +25,7 @@ and a generation into templates:
|
|
|
30
25
|
|
|
31
26
|
Besides the paper and thesis document classes, the generator offers a **minimal Markdown quick start**, selectable as the `mwe` document class — for people who want a fast start with writing rather than a full thesis with all the tricks.
|
|
32
27
|
|
|
33
|
-
-
|
|
28
|
+
- You write the content in **Markdown** inside a `\begin{markdown} … \end{markdown}` block in `main.tex` (via the [`markdown`](https://ctan.org/pkg/markdown) package): `#` becomes a chapter, `##` a section; citations (`[@key]`), footnotes, task lists, pipe tables, and images work out of the box.
|
|
34
29
|
- It compiles with **LuaLaTeX + biber** (the `markdown` package needs Lua; the bibliography uses biblatex).
|
|
35
30
|
- [`zref-clever`](https://ctan.org/pkg/zref-clever) turns the Markdown `{#id}` identifiers into smart `\zcref` cross-references that print the type name (e.g. "Figure 1.1" / "Abbildung 1.1").
|
|
36
31
|
- It generates a single minimal `main.tex` — no thesis scaffolding, abbreviations, or `commands.tex` — hides the paper/thesis-only prompts, and ships a trimmed, quick-start README.
|
|
@@ -44,7 +39,7 @@ yo latex-template --documentclass=mwe --lang=en
|
|
|
44
39
|
### Precondition for the generator
|
|
45
40
|
|
|
46
41
|
One has to install [Node.js](https://nodejs.org/en/) version 18 (or later) to get this generator running.
|
|
47
|
-
For simple installation,
|
|
42
|
+
For a simple installation, head to <https://nodejs.org/> and follow the installation instructions.
|
|
48
43
|
|
|
49
44
|
### Using the generator
|
|
50
45
|
|
|
@@ -92,162 +87,26 @@ You can use the magic of `git` to prevent that:
|
|
|
92
87
|
|
|
93
88
|
## Resources
|
|
94
89
|
|
|
90
|
+
- Paper: [Oliver Kopp - The LaTeX template generator: How micro-templates reduce template maintenance effort](https://tug.org/TUGboat/tb44-2/tb137kopp-microtemplates.html)
|
|
91
|
+
- Talk: [Oliver Kopp - The LaTeX Template Generator - DANTE Herbsttagung 2019](https://github.com/dante-ev/Vortraege_Tagungen/blob/master/2019-Herbst/Oliver%20Kopp%20-%20The%20LaTeX%20Template%20Generator%20-%20dante2019-herbst.pdf) - a talk on the motivation, user experience, and the contribution
|
|
95
92
|
- [IEEE](https://latextemplates.github.io/ieee-enhanced/) - example: [paper-conference-minted.tex](https://github.com/latextemplates/ieee-enhanced/blob/main/paper-conference-minted.tex)
|
|
96
93
|
- [LNCS](https://latextemplates.github.io/lncs-enhanced/) - example: [paper.tex](https://github.com/latextemplates/lncs-enhanced/blob/main/paper.tex)
|
|
97
94
|
- [scientific-thesis-template](https://latextemplates.github.io/scientific-thesis-template/) - example: [latexhints-english.tex](https://github.com/latextemplates/scientific-thesis-template/blob/main/latexhints-english.tex)
|
|
98
95
|
- [alpenwasser/TeX](https://github.com/alpenwasser/TeX)
|
|
99
96
|
|
|
100
|
-
##
|
|
101
|
-
|
|
102
|
-
In the long run, the contents of the `paper.tex` (and similar) files in repositories of the [latextemplates](https://latextemplates.github.io/) organization should be generated automatically.
|
|
103
|
-
|
|
104
|
-
## Development hints
|
|
105
|
-
|
|
106
|
-
- Templating language: <https://ejs.co/>
|
|
107
|
-
- Conditional questions: <https://stackoverflow.com/a/18706640/873282>.
|
|
108
|
-
- Types of prompts: <https://github.com/SBoudrias/Inquirer.js#prompt-types>
|
|
109
|
-
- E.g., [Question](https://github.com/SBoudrias/Inquirer.js#question)
|
|
110
|
-
- Add a new question
|
|
111
|
-
- Also adapt `__tests__/app.js`
|
|
112
|
-
- Execute tests with `npm test` (runs ESLint, then the tests via Node's built-in test runner). A bare run is `node --test`.
|
|
113
|
-
- Update NPM dependencies
|
|
114
|
-
- `npx npm-update-all`. See [FreeCodeCamp](https://www.freecodecamp.org/news/10-npm-tricks-that-will-make-you-a-pro-a945982afb25/) for more details.
|
|
115
|
-
- `npx npm-check-updates -u`. [[Source](https://www.carlrippon.com/upgrading-npm-dependencies/)]
|
|
116
|
-
- See <https://github.com/yeoman/generator/releases> for changes in the generator.
|
|
117
|
-
- Generate `package-lock.json` only: `npm i --package-lock-only`
|
|
118
|
-
- When one encounters `Cannot find module 'yeoman-generator'`, please update the npm dependencies.
|
|
119
|
-
That error occurred when using version `4.13.0` and `5.4.2` was available.
|
|
120
|
-
- In case of the error "Error: EACCES, permission denied '/root/.config/configstore/insight-yo.json'", one needs to execute `chmod g+rwx /root /root/.config /root/.config/configstore`
|
|
121
|
-
- Check GitHub actions
|
|
122
|
-
- Use [actionlint](https://github.com/rhysd/actionlint#readme)
|
|
123
|
-
- Use [vs.code GitHub actions plugin](https://marketplace.visualstudio.com/items?itemName=cschleiden.vscode-github-actions)
|
|
124
|
-
- Use [act](https://github.com/nektos/act) for checking: `act --rm --platform ubuntu-latest=fwilhe2/act-runner:latest -W .github/workflows/check-ieee-conference-a4-pdflatex-bibtex-2023-true.yml`
|
|
125
|
-
- When adding a new package use `DEPP` (see above) or execute following steps:
|
|
126
|
-
1. execute `npx` with `--generatereitzig` (in a clean directory)
|
|
127
|
-
2. run `pdflatex`
|
|
128
|
-
3. run `{repository-root}/generate-texlivefile.sh`
|
|
129
|
-
4. copy `Texlivefile` to the root of the `{repository-root}/generators/app/templates`
|
|
130
|
-
5. adapt `Texlivefile` as required
|
|
131
|
-
- When issues with the template occur: `npx ejs-lint main.en.tex`
|
|
132
|
-
- Cancel workflows:
|
|
133
|
-
- `gh run list -L 100 --json databaseId -s queued -R latextemplates/generator-latex-template | jq -r '.[] | .databaseId' | awk '{gsub(/\\r\\n/,RS)} 1' | while read -r run_id; do gh run cancel "$run_id" -R latextemplates/generator-latex-template || true; done`
|
|
134
|
-
- `gh run list -L 100 --json databaseId -s in_progress -R latextemplates/generator-latex-template | jq -r '.[] | .databaseId' | awk '{gsub(/\\r\\n/,RS)} 1' | while read -r run_id; do gh run cancel "$run_id" -R latextemplates/generator-latex-template || true; done`
|
|
135
|
-
- Update submodule of "derived" templates (LNCS, ...): `scripts/spread-updates.sh`. It also links the generator's `refine-ltg` PR in the description of each template's "Update LTG" PR.
|
|
136
|
-
- Keep the `refine-ltg` PR description current: it links every issue the cycle fixes (the same `[repo#N]` links as the CHANGELOG).
|
|
137
|
-
- Sort `dot.aspell.en.pws`: `cat dot.aspell.en.pws | (sed -u 1q; sort) | sponge dot.aspell.en.pws` <!-- hint by https://stackoverflow.com/a/56151840/873282 -->
|
|
138
|
-
|
|
139
|
-
### Testing
|
|
140
|
-
|
|
141
|
-
- All workflows test `overleaf=no` - and (nearly) all possible combinations.
|
|
142
|
-
- All `*-refined` repositories test with `overleaf=true` - and only the typical settings for the template.
|
|
143
|
-
- `refine-ltg` is the development branch for the template generator; only a small set of workflows enabled there due to load during testing.
|
|
144
|
-
- `update-ltg` is the development branch at each `*-refined` template.
|
|
145
|
-
|
|
146
|
-
### Test locally
|
|
147
|
-
|
|
148
|
-
- Create empty directory ("target directory")
|
|
149
|
-
- Change to the target directory
|
|
150
|
-
- Run `npx yo <path-to-git-repository>/generators/app/index.js`. Background: Starting from 5.0.0 on, [one needs to specify the full path to index.js](https://github.com/yeoman/yo/issues/797#issuecomment-2541794625).
|
|
151
|
-
- Windows: `npx yo c:\git-repositories\latextemplates\generator-latex-template\generators\app\index.js`
|
|
152
|
-
|
|
153
|
-
#### Linux
|
|
154
|
-
|
|
155
|
-
Parameters can be set using command line
|
|
156
|
-
|
|
157
|
-
- LNCS: `npx yo /tmp/repo/generators/app/index.js --documentclass=lncs --papersize=a4 --latexcompiler=pdflatex --bibtextool=bibtex --texlive=2026 --docker=false --lang=en --font=default --listings=listings --enquotes=csquotes --tweakouterquote=babel --todo=pdfcomment --examples=true --howtotext=true`
|
|
158
|
-
|
|
159
|
-
#### Windows
|
|
160
|
-
|
|
161
|
-
Parameters can be set using command line
|
|
162
|
-
|
|
163
|
-
- IEEE template (with pdflatex and bibtex): `npx yo c:\git-repositories\latextemplates\generator-latex-template\generators\app\index.js --overleaf=false --documentclass=ieee --ieeevariant=conference --papersize=a4 --latexcompiler=pdflatex --bibtextool=bibtex --texlive=2026 --docker=reitzig --lang=en --font=default --listings=listings --enquotes=csquotes --tweakouterquote=babel --todo=pdfcomment --examples=true --howtotext=true`
|
|
164
|
-
- LNCS template (with pdflatex and bibtex): `npx yo c:\git-repositories\latextemplates\generator-latex-template\generators\app\index.js --overleaf=false --documentclass=lncs ---papersize=a4 --latexcompiler=pdflatex --bibtextool=bibtex --texlive=2026 --docker=false --lang=en --font=default --listings=listings --enquotes=csquotes --tweakouterquote=babel --todo=pdfcomment --examples=true --howtotext=true`
|
|
165
|
-
- Scientific Thesis template: `npx yo c:\git-repositories\latextemplates\generator-latex-template\generators\app\index.js --overleaf=false --documentclass=scientific-thesis --papersize=a4 --latexcompiler=pdflatex --bibtextool=bibtex --texlive=2026 --lang=en --font=default --listings=listings --enquotes=csquotes --tweakouterquote=babel --todo=pdfcomment --examples=true --howtotext=true`
|
|
166
|
-
- USTUTT template: `npx yo c:\git-repositories\latextemplates\generator-latex-template\generators\app\index.js --overleaf=false --documentclass=ustutt --papersize=a5 --latexcompiler=lualatex --bibtextool=biblatex --texlive=2026 --lang=en --font=default --listings=listings --enquotes=csquotes --tweakouterquote=babel --todo=todonotes --examples=true --howtotext=true` -- `todonotes` is the preferred TODO package here.
|
|
167
|
-
|
|
168
|
-
<!-- markdownlint-disable-next-line MD004 -->
|
|
169
|
-
* Run `latexmk` to build the PDF
|
|
170
|
-
|
|
171
|
-
##### Using DEPP
|
|
172
|
-
|
|
173
|
-
To fire up a TeX Live installation and use the [Dependency Printer for TeX Live](https://gitlab.com/islandoftex/texmf/depp) to refine `Texlivefile`, execute following steps:
|
|
174
|
-
|
|
175
|
-
```cmd
|
|
176
|
-
docker run -it --rm -v c:\temp\ltg:/ltg registry.gitlab.com/islandoftex/images/texlive:latest
|
|
177
|
-
```
|
|
97
|
+
## Contributing
|
|
178
98
|
|
|
179
|
-
|
|
180
|
-
cd /tmp
|
|
181
|
-
git clone https://gitlab.com/islandoftex/texmf/depp.git
|
|
182
|
-
cd depp
|
|
183
|
-
l3build install
|
|
184
|
-
cd /ltg
|
|
185
|
-
# edit paper.tex and add `\RequirePackage[dependency-file=Texlivefile]{depp}`
|
|
186
|
-
lualatex/pdflatex paper
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
##### Running reitzig
|
|
190
|
-
|
|
191
|
-
1. `docker build --progress=plain -t reitzig -f Dockerfile .`
|
|
192
|
-
2. `docker run -it --rm -v c:\temp\ltg:/work/src -v c:\temp\ltg-out:/work/out reitzig work latexmk`
|
|
193
|
-
|
|
194
|
-
### Useful snippets
|
|
195
|
-
|
|
196
|
-
```ejs
|
|
197
|
-
<% if (howtotext) { -%>
|
|
198
|
-
<% } else { -%>
|
|
199
|
-
<% } -%>
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
```ejs
|
|
203
|
-
<% switch (documentclass) { case "lncs": -%>
|
|
204
|
-
<% break; case "ieee": -%>
|
|
205
|
-
<% break; default: -%>
|
|
206
|
-
<% break; } -%>
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
### Debugging
|
|
210
|
-
|
|
211
|
-
A `launch.json` configured for Windows and Visual Studio Code is included.
|
|
212
|
-
Just press <kbd>F5</kbd> and the generator should run in debug mode.
|
|
213
|
-
|
|
214
|
-
```terminal
|
|
215
|
-
ejslint.cmd c:\git-repositories\latextemplates\generator-latex-template\generators\app\templates\main.en.tex
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
### Releasing a new version
|
|
219
|
-
|
|
220
|
-
> **Cut the release from `main`, never from `refine-ltg`.**
|
|
221
|
-
> Releasing from the dev branch publishes an unmerged tree with a not-yet-finalized CHANGELOG — that is what broke the 2026.6.26 release (a stale `## [2026.6.25]` heading, a missing `[2026.6.26]:` compare link, and an `[Unreleased]:` link that was never bumped).
|
|
222
|
-
> So after the squash-merge, `git switch main && git pull` and confirm `git branch --show-current` prints `main` before doing anything below.
|
|
223
|
-
|
|
224
|
-
1. Once the `refine-ltg` PR is green, **squash-merge** it into `main`, then `git switch main && git pull` (confirm you are on `main`).
|
|
225
|
-
2. Update `CHANGELOG.md`: rename the top `## [Unreleased]` heading to `## [<version>]`, add the matching `[<version>]: …/compare/<prev>...<version>` link definition, and bump `[Unreleased]: …/compare/<version>...main`.
|
|
226
|
-
3. **Verify the CHANGELOG before publishing:**
|
|
227
|
-
- Run heylogs (the same check as CI's `check-changelog.yml`) and get **0 problems**:
|
|
228
|
-
`jbang com.github.nbbrd.heylogs:heylogs-cli:0.18.1:bin check CHANGELOG.md`
|
|
229
|
-
- heylogs **cannot** validate the version links here: our CalVer headings omit the date, so `linkable`/`date-displayed`/`all-h2-contain-a-version` are off in `heylogs.properties` and heylogs skips link-checking a dateless heading. So **also check the links by hand** — the top `## [<version>]` must equal the version `release-it` will publish, and both the `[<version>]:` and the bumped `[Unreleased]:` definitions must be present and point at the right tags. Quick grep:
|
|
230
|
-
`grep -nE '^## \[|^\[Unreleased\]:|^\[<version>\]:' CHANGELOG.md`
|
|
231
|
-
4. Update `package.json`, publish to [npmjs](https://www.npmjs.com/package/generator-latex-template), create GitHub release.
|
|
232
|
-
Use [release-it](https://www.npmjs.com/package/release-it) (do not create a release on GitHub) and [github-release-from-changelog](https://www.npmjs.com/package/github-release-from-changelog).
|
|
233
|
-
|
|
234
|
-
- `npx release-it`
|
|
235
|
-
- Confirm the publish: `npm view generator-latex-template version` must print the new version (2026.10.1 was tagged and released on GitHub but never published to npm).
|
|
236
|
-
- `GITHUB_TOKEN=$(gh auth token) npx github-release-from-changelog` (Git Bash; it needs a GitHub token, which the logged-in `gh` CLI provides)
|
|
237
|
-
5. On `main`, run `scripts/end-new-cycle.sh`, then **squash-merge** each template's "Update LTG" PR once it is green.
|
|
238
|
-
6. Release the templates: `scripts/release-templates.sh <YYYY-MM-DD>` (try `--dry-run` first) finalizes the CHANGELOG of every template with unreleased entries, commits "Release <date>", tags, pushes, and creates the GitHub release with the CHANGELOG section as notes.
|
|
99
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for how to contribute and for development hints, including testing and releasing.
|
|
239
100
|
|
|
240
101
|
## License
|
|
241
102
|
|
|
242
|
-
The code
|
|
243
|
-
See [benbalter/talks#15](https://github.com/benbalter/talks/issues/15#issuecomment-599704662), for
|
|
103
|
+
The code has the license [0BSD](https://choosealicense.com/licenses/0bsd/#), the snippets (both LaTeX and text) 0BSD, too.
|
|
104
|
+
See [benbalter/talks#15](https://github.com/benbalter/talks/issues/15#issuecomment-599704662), for the reasoning why we cannot use [CC0](https://creativecommons.org/share-your-work/public-domain/cc0/).
|
|
244
105
|
|
|
245
|
-
- `generators/app/templates/splncs04nat.bst`
|
|
246
|
-
- `generators/app/templates/logos/`: This directory contains logos, which have special licenses.
|
|
106
|
+
- `generators/app/templates/splncs04nat.bst` comes from [tpavlic/splncs04nat](https://github.com/tpavlic/splncs04nat) and is MIT-licensed.
|
|
107
|
+
- `generators/app/templates/logos/`: This directory contains logos, which have special licenses (see [`logos/README.md`](generators/app/templates/logos/README.md)).
|
|
247
108
|
- `generators/app/templates/figures/ulm-minster.jpg` is [Landappbw 79389 1820 Ulmer Münster Ulm.jpg](https://commons.wikimedia.org/w/index.php?curid=131463041) by wkrauth, dedicated to the public domain under [CC0 1.0](https://creativecommons.org/publicdomain/zero/1.0/).
|
|
248
109
|
|
|
249
110
|
[hyperref]: https://ctan.org/pkg/hyperref
|
|
250
111
|
[listings]: https://ctan.org/pkg/listings
|
|
251
112
|
[minted]: https://ctan.org/pkg/minted
|
|
252
|
-
|
|
253
|
-
<!-- markdownlint-disable-file MD013 MD033 -->
|
package/generators/app/CLAUDE.md
CHANGED
|
@@ -29,7 +29,8 @@ the feature vanishes for some switch combination without any error.
|
|
|
29
29
|
3. **`Texlivefile`** — add the TeX Live package name, guarded (usually
|
|
30
30
|
`githubpublish || <condition>`; `githubpublish` deliberately bundles everything).
|
|
31
31
|
4. **Shell-escape is derived, never hardcoded.** It is the boolean
|
|
32
|
-
`requiresShellEscape` in `index.js` (`
|
|
32
|
+
`requiresShellEscape` in `index.js` (`uml == "plantuml"`, and minted only up to TeX Live 2024:
|
|
33
|
+
minted 3 runs `latexminted`, which TeX Live permits in restricted shell escape).
|
|
33
34
|
Extend that expression if the new package needs `\write18`; the `latexmkrc` and the
|
|
34
35
|
`main.*.tex` editor hints read the flag.
|
|
35
36
|
5. **New user switch?** Decide **prompt vs. plain flag** first:
|
|
@@ -82,6 +83,7 @@ The consequence (and a real footgun): **the blank-line layout of the output is n
|
|
|
82
83
|
layout of the source.** Because `-%>` eats one trailing newline, two adjacent
|
|
83
84
|
`-%>`-terminated blocks/includes render with **no** blank line between them. To get a
|
|
84
85
|
blank line between blocks you need one of:
|
|
86
|
+
|
|
85
87
|
- the first block's file to **end with a trailing blank line** (how most
|
|
86
88
|
`*.preamble.*.tex` separate themselves — e.g. `font.preamble` ends with a blank line
|
|
87
89
|
then `<% } -%>`), **or**
|
|
@@ -111,5 +113,5 @@ formats) catch things a single local `yo` + compile does not. Two that have bitt
|
|
|
111
113
|
language's example must be defined in **both** `abbreviations.en.tex` and
|
|
112
114
|
`abbreviations.de.tex` (the unused one just never appears in that document's list). Making
|
|
113
115
|
`\gls` entries language-exclusive breaks the other language's variant with
|
|
114
|
-
|
|
116
|
+
``Glossary entry `…' has not been defined``. The same single-shared-file logic applies to
|
|
115
117
|
other `this.fs.copy`'d siblings (`commands.tex`, …).
|
package/generators/app/index.js
CHANGED
|
@@ -12,7 +12,11 @@ export default class extends Generator {
|
|
|
12
12
|
this.log(yosay(`Welcome to the ${chalk.red("latex-template")} generator!`));
|
|
13
13
|
|
|
14
14
|
// See "Development hints" in README.md for help on Inquirer.js
|
|
15
|
-
|
|
15
|
+
// yeoman-option-or-prompt mutates the prompts (deletes `when`, replaces `choices`/`default`
|
|
16
|
+
// functions by their result); pass copies so that runs in one process (the tests) stay independent.
|
|
17
|
+
const props = await this._optionOrPrompt(
|
|
18
|
+
options.map((prompt) => ({ ...prompt })),
|
|
19
|
+
);
|
|
16
20
|
|
|
17
21
|
// To access props later use this.props.someAnswer;
|
|
18
22
|
this.props = props;
|
|
@@ -179,10 +183,17 @@ export default class extends Generator {
|
|
|
179
183
|
this.props.Vref = "\\zvref[S]";
|
|
180
184
|
}
|
|
181
185
|
|
|
182
|
-
//
|
|
183
|
-
|
|
186
|
+
// The program that processes the bibliography: biber for biblatex, bibtex otherwise.
|
|
187
|
+
this.props.bibrunner =
|
|
188
|
+
this.props.bibtextool === "biblatex" ? "biber" : "bibtex";
|
|
189
|
+
|
|
190
|
+
// Only the PlantUML UML example needs shell-escape. minted 3 (TeX Live 2025 and later)
|
|
191
|
+
// runs latexminted, which TeX Live permits in restricted shell escape; minted 2
|
|
192
|
+
// (TeX Live 2024) still needs shell-escape.
|
|
184
193
|
this.props.requiresShellEscape =
|
|
185
|
-
this.props.listings == "minted"
|
|
194
|
+
(this.props.listings == "minted" && this.props.texlive < 2025) ||
|
|
195
|
+
this.props.uml == "plantuml" ||
|
|
196
|
+
this.props.uml == "mermaid";
|
|
186
197
|
|
|
187
198
|
// Two-column layouts (IEEE, and the ACM conference/journal formats) cannot use
|
|
188
199
|
// `longtable` ("longtable not in 1-column mode"), so the longtable example must
|
|
@@ -205,6 +216,45 @@ export default class extends Generator {
|
|
|
205
216
|
? "latest"
|
|
206
217
|
: `TL${this.props.texlive}-historic`);
|
|
207
218
|
|
|
219
|
+
// The DANTE e.V. image additionally contains PlantUML (and the Mermaid CLI), needed by
|
|
220
|
+
// --uml=plantuml and --uml=mermaid. Its tags: https://hub.docker.com/r/danteev/texlive/tags
|
|
221
|
+
const danteTags = {
|
|
222
|
+
2021: "2021-D",
|
|
223
|
+
2023: "2023-A",
|
|
224
|
+
2024: "2024-B",
|
|
225
|
+
2025: "2026-B",
|
|
226
|
+
2026: "2026-B",
|
|
227
|
+
};
|
|
228
|
+
this.props.danteImage =
|
|
229
|
+
"danteev/texlive:" + (danteTags[this.props.texlive] ?? "edge");
|
|
230
|
+
|
|
231
|
+
// The image used to compile in Docker (README, Makefile, VS Code settings)
|
|
232
|
+
this.props.dockerImage =
|
|
233
|
+
this.props.docker === "dante"
|
|
234
|
+
? this.props.danteImage
|
|
235
|
+
: this.props.iotImage;
|
|
236
|
+
this.props.dockerCompile =
|
|
237
|
+
this.props.docker === "iot" || this.props.docker === "dante";
|
|
238
|
+
|
|
239
|
+
// The generator options of this template, used in the README to tell how to generate an own
|
|
240
|
+
// copy (e.g., with PlantUML). The options that distinguish the main files of a published
|
|
241
|
+
// template (thesis variant, language, package for source code) are left open, so that the
|
|
242
|
+
// generator asks for them.
|
|
243
|
+
this.props.regenerateOptions = [
|
|
244
|
+
"documentclass",
|
|
245
|
+
"latexcompiler",
|
|
246
|
+
"overleaf",
|
|
247
|
+
"texlive",
|
|
248
|
+
"enquotes",
|
|
249
|
+
"tweakouterquote",
|
|
250
|
+
"todo",
|
|
251
|
+
"examples",
|
|
252
|
+
"howtotext",
|
|
253
|
+
]
|
|
254
|
+
.filter((name) => this.props[name] !== undefined)
|
|
255
|
+
.map((name) => `--${name}=${this.props[name]}`)
|
|
256
|
+
.join(" ");
|
|
257
|
+
|
|
208
258
|
createFeatures(props);
|
|
209
259
|
createHeadingCommands(props);
|
|
210
260
|
createAvailable(props);
|
|
@@ -310,7 +360,7 @@ export default class extends Generator {
|
|
|
310
360
|
);
|
|
311
361
|
this.fs.copyTpl(
|
|
312
362
|
this.templatePath("latexmkrc"),
|
|
313
|
-
this.destinationPath(
|
|
363
|
+
this.destinationPath(".latexmkrc"),
|
|
314
364
|
this.props,
|
|
315
365
|
);
|
|
316
366
|
this.fs.copyTpl(
|
|
@@ -354,6 +404,40 @@ export default class extends Generator {
|
|
|
354
404
|
);
|
|
355
405
|
}
|
|
356
406
|
|
|
407
|
+
// TeXtidote (spelling, grammar, and style; CI job "textidote") reads its options from .textidote.
|
|
408
|
+
// Its dictionary contains the words of both aspell word lists (without their header lines).
|
|
409
|
+
// Both files must not depend on the language: some templates publish both languages into one repository.
|
|
410
|
+
if (this.props.documentclass !== "mwe") {
|
|
411
|
+
this.fs.copy(
|
|
412
|
+
this.templatePath("dot.textidote"),
|
|
413
|
+
this.destinationPath(".textidote"),
|
|
414
|
+
);
|
|
415
|
+
this.fs.copy(
|
|
416
|
+
this.templatePath("dot.textidote.replacements"),
|
|
417
|
+
this.destinationPath(".textidote.replacements"),
|
|
418
|
+
);
|
|
419
|
+
const words = [
|
|
420
|
+
...new Set(
|
|
421
|
+
["en", "de"].flatMap((lang) =>
|
|
422
|
+
this.fs
|
|
423
|
+
.read(this.templatePath(`dot.aspell.${lang}.pws`))
|
|
424
|
+
.split("\n")
|
|
425
|
+
.slice(1)
|
|
426
|
+
.filter((word) => word !== ""),
|
|
427
|
+
),
|
|
428
|
+
),
|
|
429
|
+
]
|
|
430
|
+
.sort((a, b) => a.localeCompare(b, "en"))
|
|
431
|
+
.join("\n");
|
|
432
|
+
// aspell word lists cannot contain hyphenated words
|
|
433
|
+
const hyphenated =
|
|
434
|
+
"zref-clever\nZref-clever\nzref-vario\nZref-vario\npgf-umlsd\nmarkdown-latex-quickstart\n";
|
|
435
|
+
this.fs.write(
|
|
436
|
+
this.destinationPath(".textidote.dict"),
|
|
437
|
+
words + "\n" + hyphenated,
|
|
438
|
+
);
|
|
439
|
+
}
|
|
440
|
+
|
|
357
441
|
if (this.props.documentclass === "lncs") {
|
|
358
442
|
this.fs.copy(
|
|
359
443
|
this.templatePath("splncs04nat.bst"),
|
|
@@ -442,6 +526,20 @@ export default class extends Generator {
|
|
|
442
526
|
);
|
|
443
527
|
}
|
|
444
528
|
|
|
529
|
+
if (this.props.documentclass == "scientific-thesis") {
|
|
530
|
+
const logos = {
|
|
531
|
+
"university-of-hamburg": "uhh-logo.pdf",
|
|
532
|
+
thu: "thu-logo.png",
|
|
533
|
+
};
|
|
534
|
+
const logo = logos[this.props.thesisvariant];
|
|
535
|
+
if (logo) {
|
|
536
|
+
this.fs.copy(
|
|
537
|
+
this.templatePath("logos/" + logo),
|
|
538
|
+
this.destinationPath("figures/" + logo),
|
|
539
|
+
);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
|
|
445
543
|
if (this.props.documentclass == "ustutt") {
|
|
446
544
|
/*
|
|
447
545
|
this.props.documentclass = "ustutt-include";
|
|
@@ -523,6 +621,14 @@ export default class extends Generator {
|
|
|
523
621
|
this.fs.copy(this.templatePath("docs/*"), this.destinationPath("docs/"));
|
|
524
622
|
}
|
|
525
623
|
|
|
624
|
+
if (this.props.uml === "mermaid") {
|
|
625
|
+
// lets the headless Chromium of the Mermaid CLI run without sandbox (see uml.mermaid.preamble.en.tex)
|
|
626
|
+
this.fs.copy(
|
|
627
|
+
this.templatePath("puppeteer.json"),
|
|
628
|
+
this.destinationPath("puppeteer.json"),
|
|
629
|
+
);
|
|
630
|
+
}
|
|
631
|
+
|
|
526
632
|
this.fs.copy(
|
|
527
633
|
this.templatePath(".github/dependabot.yml"),
|
|
528
634
|
this.destinationPath(".github/dependabot.yml"),
|
|
@@ -114,6 +114,10 @@ export const options = [
|
|
|
114
114
|
name: "Universität Hamburg",
|
|
115
115
|
value: "university-of-hamburg",
|
|
116
116
|
},
|
|
117
|
+
{
|
|
118
|
+
name: "Technische Hochschule Ulm",
|
|
119
|
+
value: "thu",
|
|
120
|
+
},
|
|
117
121
|
],
|
|
118
122
|
default: "ustutt",
|
|
119
123
|
},
|
|
@@ -159,28 +163,18 @@ export const options = [
|
|
|
159
163
|
type: "list",
|
|
160
164
|
name: "texlive",
|
|
161
165
|
message: "Which TeXLive compatibility?",
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
}
|
|
175
|
-
return res;
|
|
176
|
-
},
|
|
177
|
-
default(state) {
|
|
178
|
-
if (state.overleaf) {
|
|
179
|
-
return 2024;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
return 2025;
|
|
183
|
-
},
|
|
166
|
+
// Overleaf offers the current TeX Live (select it in the project settings).
|
|
167
|
+
choices: [
|
|
168
|
+
{
|
|
169
|
+
name: "TeXLive 2025",
|
|
170
|
+
value: 2025,
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
name: "TeXLive 2026",
|
|
174
|
+
value: 2026,
|
|
175
|
+
},
|
|
176
|
+
],
|
|
177
|
+
default: 2026,
|
|
184
178
|
},
|
|
185
179
|
{
|
|
186
180
|
type: "list",
|
|
@@ -197,7 +191,7 @@ export const options = [
|
|
|
197
191
|
value: "pdflatex",
|
|
198
192
|
},
|
|
199
193
|
];
|
|
200
|
-
if (state.texlive ==
|
|
194
|
+
if (state.texlive == 2026) {
|
|
201
195
|
res.push({
|
|
202
196
|
name: "pdflatex-dev",
|
|
203
197
|
value: "pdflatex-dev",
|
|
@@ -207,7 +201,7 @@ export const options = [
|
|
|
207
201
|
name: "lualatex",
|
|
208
202
|
value: "lualatex",
|
|
209
203
|
});
|
|
210
|
-
if (state.texlive ==
|
|
204
|
+
if (state.texlive == 2026) {
|
|
211
205
|
res.push({
|
|
212
206
|
name: "lualatex-dev",
|
|
213
207
|
value: "lualatex-dev",
|
|
@@ -254,30 +248,6 @@ export const options = [
|
|
|
254
248
|
}
|
|
255
249
|
},
|
|
256
250
|
},
|
|
257
|
-
{
|
|
258
|
-
type: "list",
|
|
259
|
-
name: "docker",
|
|
260
|
-
message: "Should a Dockerfile be generated?",
|
|
261
|
-
choices: [
|
|
262
|
-
{
|
|
263
|
-
name: "no",
|
|
264
|
-
value: false,
|
|
265
|
-
},
|
|
266
|
-
{
|
|
267
|
-
name: "yes (Island of TeX)",
|
|
268
|
-
value: "iot",
|
|
269
|
-
},
|
|
270
|
-
{
|
|
271
|
-
name: "yes (Reiztig)",
|
|
272
|
-
value: "reitzig",
|
|
273
|
-
},
|
|
274
|
-
{
|
|
275
|
-
name: "yes (DANTE e.V.)",
|
|
276
|
-
value: "dante",
|
|
277
|
-
},
|
|
278
|
-
],
|
|
279
|
-
default: false,
|
|
280
|
-
},
|
|
281
251
|
{
|
|
282
252
|
type: "list",
|
|
283
253
|
name: "lang",
|
|
@@ -484,10 +454,53 @@ export const options = [
|
|
|
484
454
|
value: "tikz-uml",
|
|
485
455
|
},
|
|
486
456
|
{
|
|
487
|
-
name: "PlantUML (needs
|
|
457
|
+
name: "PlantUML (needs --shell-escape, Java, and PlantUML; contained in the Docker image by DANTE e.V.)",
|
|
488
458
|
value: "plantuml",
|
|
489
459
|
},
|
|
460
|
+
{
|
|
461
|
+
name: "Mermaid (needs --shell-escape and the Mermaid CLI; contained in the Docker image by DANTE e.V.)",
|
|
462
|
+
value: "mermaid",
|
|
463
|
+
},
|
|
490
464
|
],
|
|
491
465
|
default: "none",
|
|
492
466
|
},
|
|
467
|
+
{
|
|
468
|
+
type: "list",
|
|
469
|
+
name: "docker",
|
|
470
|
+
message: "Should a Dockerfile be generated?",
|
|
471
|
+
// PlantUML and the Mermaid CLI are contained only in the image by DANTE e.V.
|
|
472
|
+
choices(state) {
|
|
473
|
+
const needsDante = state.uml === "plantuml" || state.uml === "mermaid";
|
|
474
|
+
const res = [
|
|
475
|
+
{
|
|
476
|
+
name: "no",
|
|
477
|
+
value: false,
|
|
478
|
+
},
|
|
479
|
+
];
|
|
480
|
+
if (!needsDante) {
|
|
481
|
+
res.push(
|
|
482
|
+
{
|
|
483
|
+
name: "yes (Island of TeX)",
|
|
484
|
+
value: "iot",
|
|
485
|
+
},
|
|
486
|
+
{
|
|
487
|
+
name: "yes (Reiztig)",
|
|
488
|
+
value: "reitzig",
|
|
489
|
+
},
|
|
490
|
+
);
|
|
491
|
+
}
|
|
492
|
+
res.push({
|
|
493
|
+
name: needsDante
|
|
494
|
+
? "yes (DANTE e.V.; contains PlantUML and the Mermaid CLI)"
|
|
495
|
+
: "yes (DANTE e.V.)",
|
|
496
|
+
value: "dante",
|
|
497
|
+
});
|
|
498
|
+
return res;
|
|
499
|
+
},
|
|
500
|
+
default(state) {
|
|
501
|
+
return state.uml === "plantuml" || state.uml === "mermaid"
|
|
502
|
+
? "dante"
|
|
503
|
+
: false;
|
|
504
|
+
},
|
|
505
|
+
},
|
|
493
506
|
];
|