Repository navigation
Install dehyph-exptl for pinned German patterns and follow the tinytex hyphenation map #15035
Description
Follow-up to #15027 / #15029. The table of hyphenation names in parse-error.ts is a hand-written copy of the one in tinytex and it is already behind.
tinytex now generates this table from the execute AddHyphen lines of texlive.tlpdb (rstudio/tinytex#517, follow-up to rstudio/tinytex#516). The generated table has 41 entries, the 37 we have plus 4 that map to dehyph-exptl: german-x-latest, ngerman-x-latest, german-x-2024-02-28 and ngerman-x-2024-02-28.
What is missing here
quarto-cli/src/command/render/latexmk/parse-error.ts
Lines 161 to 201 in db1d1c7
| const kHyphenationPackageNames: Record<string, string> = { | |
| ngerman: "german", | |
| swissgerman: "german", | |
| pinyin: "chinese", | |
| ukenglish: "english", | |
| british: "english", | |
| usenglishmax: "english", | |
| bokmal: "norwegian", | |
| norsk: "norwegian", | |
| nynorsk: "norwegian", | |
| schoolfinnish: "finnish", | |
| monogreek: "greek", | |
| ibycus: "ancientgreek", | |
| classiclatin: "latin", | |
| liturgicallatin: "latin", | |
| mongolianlmc: "mongolian", | |
| serbianc: "serbian", | |
| // older names (synonyms in texlive.tlpdb) | |
| amharic: "ethiopic", | |
| geez: "ethiopic", | |
| persian: "farsi", | |
| patois: "french", | |
| francais: "french", | |
| polygreek: "greek", | |
| portuges: "portuguese", | |
| slovene: "slovenian", | |
| espanol: "spanish", | |
| // all of these are in the hyphen-indic package | |
| assamese: "indic", | |
| bengali: "indic", | |
| gujarati: "indic", | |
| hindi: "indic", | |
| kannada: "indic", | |
| malayalam: "indic", | |
| marathi: "indic", | |
| oriya: "indic", | |
| pali: "indic", | |
| panjabi: "indic", | |
| tamil: "indic", | |
| telugu: "indic", | |
| }; |
dehyph-exptlcan't be expressed. The values are suffixes and the package is always built ashyphen-${name}, then checked against^hyphen-[a-z0-9-]+$.
quarto-cli/src/command/render/latexmk/parse-error.ts
Lines 205 to 232 in db1d1c7
| function hyphenationPackageForLanguage(lang: string) { | |
| // Names in language.dat may be in mixed case (e.g. UKenglish) | |
| lang = lang.toLowerCase(); | |
| // It seems some languages have no hyphenation files, so we just filter them out | |
| // e.g. `lang: zh` has no hyphenation files | |
| // https://github.com/quarto-dev/quarto-cli/issues/10291 | |
| const noHyphen = ["chinese-hans", "chinese"]; | |
| if (noHyphen.includes(lang)) { | |
| return; | |
| } | |
| // NOTE Although the names of the corresponding lfd files match those in this list, | |
| // there are some exceptions, particularly in German and Serbian. So, ngerman is | |
| // called here german, which is the name in the CLDR and, actually, the most logical. | |
| // | |
| // See https://ctan.math.utah.edu/ctan/tex-archive/macros/latex/required/babel/base/babel.pdf | |
| const name = Object.hasOwn(kHyphenationPackageNames, lang) | |
| ? kHyphenationPackageNames[lang] | |
| : lang; | |
| const pkg = `hyphen-${name}`; | |
| // The name comes from the log and is passed to tlmgr (through a .bat file | |
| // on Windows), so only keep what looks like a package name (all | |
| // hyphenation names in texlive.tlpdb are lowercase letters, digits and hyphens) | |
| if (/^hyphen-[a-z0-9-]+$/.test(pkg)) { | |
| return pkg; | |
| } | |
| } |
So a log with You haven't defined the language 'ngerman-x-latest' yet gives the non-existent hyphen-ngerman-x-latest.
findMissingHyphenationFilesonly returns one package. The warning regex has nogflag, so with severalPackage babel Warning: No hyphenation patterns were preloadedmessages only the first language is handled.
quarto-cli/src/command/render/latexmk/parse-error.ts
Lines 260 to 281 in db1d1c7
| export function findMissingHyphenationFiles(logText: string) { | |
| const babelWarningRegex = /^Package babel Warning:/m; | |
| const hasWarning = logText.match(babelWarningRegex); | |
| if (hasWarning) { | |
| const languageRegex = /^\(babel\).* language [`'](\S+)[`'].*$/m; | |
| const languageMatch = logText.match(languageRegex); | |
| if (languageMatch) { | |
| return hyphenationPackageForLanguage(languageMatch[1]); | |
| } | |
| } | |
| // Try an alternative way of parsing | |
| const hyphenRulesRegex = | |
| /Package babel Info: Hyphen rules for '(.*?)' set to \\l@nil/m; | |
| const match = logText.match(hyphenRulesRegex); | |
| if (match) { | |
| const language = match[1]; | |
| if (language) { | |
| return hyphenationPackageForLanguage(language); | |
| } | |
| } | |
| } |
-
A language name with a space, like
the language `German (new orthography)'in a(babel)line, doesn't matchlanguage [`'](\S+)[`']. tinytex keeps the first word (german) for those. -
polyglossia is not handled in
src/command/render/latexmk/(tinytex handlesPackage polyglossia Warning: No hyphenation patterns were loaded for ...).
The chinese skip list and the \l@nil fallback exist here only, and tinytex doesn't have them.
Plan
The tinytex daily build now exports the map as hyphen.json inside the regex.tar.gz of the daily release of rstudio/tinytex-releases, next to regex.json (once rstudio/tinytex#517 is merged):
{
"ngerman": "hyphen-german",
"ngerman-x-latest": "dehyph-exptl"
}Values are full package names, only exceptions to hyphen-<name> are listed.
Other ways to share the data that I looked at:
- Our own generator in Deno against
texlive.tlpdb: no dependency on tinytex, but two generators and a new workflow to maintain for the same data. - Fetching
R/hyphen.Rfrom the tinytex repository at build time: it needs parsing R syntax from TypeScript and adds a network dependency to the build. - Keeping two copies by hand: this is what we have now, and the 4
dehyph-exptlentries show that it drifts.
Reusing regex.tar.gz fits the existing setup: verify-tinytex-patterns.yml already downloads it daily from the daily release of rstudio/tinytex-releases. That workflow only opens or comments on an issue (label tinytex-patterns), it never opens a PR, so the table would still be updated by hand after the report. We could also extend it to open a PR with the new table, but the table in parse-error.ts is TypeScript with comments and the test file has its own copy, so I would start with the report only.
Two things to keep in mind: hyphen.json only exists in the release once rstudio/tinytex#517 is merged and the daily build ran, and a change of its format would break the comparison step (which today only reads regex.json with jq).
We could:
- Switch
kHyphenationPackageNamesto full package names, add the 4dehyph-exptlentries, and validate the language name (^[a-z0-9-]+$) instead of the resulting package. - Extend
verify-tinytex-patterns.ymlto also comparehyphen.json, so the existingtinytex-patternsissue tells us when the map changes. Itsjqsteps only readregex.jsontoday. This keeps the table bundled, with no network access at build or run time. - Update the copy of the table in
tests/unit/latexmk/parse-error.test.tsanddev-docs/tinytex-pattern-maintenance.md. - Look at points 2 to 4 above separately, if they turn out to be real.
Still to check
Everything above comes from reading the code, nothing was run yet.
- Reproduce points 2 to 4 with small log samples in a Deno unit test (
tests/unit/latexmk/parse-error.test.ts), and confirm which ones are real with logs produced by babel/polyglossia. - Point 1: confirm that
findMissingHyphenationPackagesreturnshyphen-ngerman-x-latestforYou haven't defined the language 'ngerman-x-latest' yet. - Check that
hyphen.jsonis really in thedailyrelease asset once Generate the hyphenation language map from texlive.tlpdb rstudio/tinytex#517 is merged and the daily build ran, and that the existingregex.tar.gzdownload step still works with the extra file. - Check if the
chinese/chinese-hansskip list is still needed (Quarto v1.5 installs a nonexistent packagehyphen-chinese-hanswhen compiling PDF #10291), and ifpinyin->hyphen-chinesein the generated map interacts with it. - Decide if polyglossia support belongs here or if it is not needed for Quarto's PDF output.
Related: rstudio/tinytex#515, #10291.
Activity
Report a skipped comparison when the TinyTeX download fails
Install dehyph-exptl for pinned German hyphenation pattern (quarto-de…