From 8f2ca6efa55e5ab1c8f4523c4281b4c4c2f4af69 Mon Sep 17 00:00:00 2001 From: Harald Schilly Date: Thu, 9 Oct 2025 12:02:33 +0200 Subject: [PATCH] frontend/latex: add more file types to the list of dependencies --- src/packages/frontend/cspell.json | 1 + .../latex-editor/latex-log-parser.ts | 43 ++++++++++++++++--- .../frontend/misc/latex-log-parser.test.ts | 25 ++++++++++- .../frontend/misc/latex-logs/log3.txt | 27 ++++++++++++ 4 files changed, 89 insertions(+), 7 deletions(-) create mode 100644 src/packages/frontend/misc/latex-logs/log3.txt diff --git a/src/packages/frontend/cspell.json b/src/packages/frontend/cspell.json index f393183b970..c02b69240e9 100644 --- a/src/packages/frontend/cspell.json +++ b/src/packages/frontend/cspell.json @@ -46,6 +46,7 @@ "respawns", "revealjs", "Rmarkdown", + "rtex", "rtypes", "Sagemath", "sagetex", diff --git a/src/packages/frontend/frame-editors/latex-editor/latex-log-parser.ts b/src/packages/frontend/frame-editors/latex-editor/latex-log-parser.ts index 467f221439f..4792e9dad6a 100644 --- a/src/packages/frontend/frame-editors/latex-editor/latex-log-parser.ts +++ b/src/packages/frontend/frame-editors/latex-editor/latex-log-parser.ts @@ -23,6 +23,8 @@ import { trimEnd } from "lodash"; import { normalize as path_normalize } from "path"; +import { filename_extension } from "@cocalc/util/misc"; + // Define some constants const LOG_WRAP_LIMIT = 79; const LATEX_WARNING_REGEX = /^LaTeX Warning: (.*)$/; @@ -33,6 +35,26 @@ const LINES_REGEX = /lines? ([0-9]+)/; // This is used to parse the package name from the package warnings const PACKAGE_REGEX = /^(?:Package|Class|Module) (\b.+\b) Warning/; +// Whitelist of text file extensions that can be used with \input{} or \include{} +const ALLOWED_DEP_EXTENSIONS = [ + "bbx", + "bib", + "bst", + "cbx", + "cfg", + "cls", + "def", + "lbx", + "md", + "pgf", + "rnw", + "rtex", + "sty", + "tex", + "tikz", + "txt", +] as const; + class LogText { private lines: string[]; private row: number; @@ -224,14 +246,25 @@ export class LatexParser { addDeps(line: string): void { line = line.trim(); - // ignore absolute files + // ignore absolute files (starting with /) if (line[0] === "/") return; if (line[line.length - 1] === "\\") { line = line.slice(0, line.length - 1); } - // we only want to know about tex and bib files - const pl = line.toLowerCase(); // could be name.TEX - if (!pl.endsWith(".tex") && !pl.endsWith(".bib")) return; + // Skip files that contain a colon (like "master.pdf :") + if (line.includes(":")) return; + + // Get the file extension (returns empty string if no extension) + const ext = filename_extension(line).toLowerCase(); + + // If there's an extension, check if it's in the whitelist + if (ext) { + if (!ALLOWED_DEP_EXTENSIONS.includes(ext as any)) { + return; + } + } + // If no extension, include it (files without extensions are allowed) + this.deps.push(line); } @@ -306,7 +339,7 @@ export class LatexParser { const packageMatch = this.currentLine.match(PACKAGE_REGEX); if (!packageMatch) return; const packageName = packageMatch[1]; - // Regex to get rid of the unnecesary (packagename) prefix in most multi-line warnings + // Regex to get rid of the unnecessary (packagename) prefix in most multi-line warnings const prefixRegex = new RegExp(`(?:\\(${packageName}\\))*[\\s]*(.*)`, "i"); // After every warning message there's a blank line, let's use it while (!!(this.currentLine = this.log.nextLine())) { diff --git a/src/packages/frontend/misc/latex-log-parser.test.ts b/src/packages/frontend/misc/latex-log-parser.test.ts index 1d9c80c77b3..e622c12a5b8 100644 --- a/src/packages/frontend/misc/latex-log-parser.test.ts +++ b/src/packages/frontend/misc/latex-log-parser.test.ts @@ -1,4 +1,5 @@ import fs from "fs"; + import { LatexParser } from "@cocalc/frontend/frame-editors/latex-editor/latex-log-parser"; describe("latex-log-parser", () => { @@ -14,7 +15,7 @@ describe("latex-log-parser", () => { expect(parsed1.deps[1]).toEqual("subfile.tex"); }); - // This is an abbrivated log of https://github.com/sagemathinc/cocalc/issues/8089 + // This is an abbreviated log of https://github.com/sagemathinc/cocalc/issues/8089 test("log2", () => { const log2 = fs.readFileSync("./misc/latex-logs/log2.txt", "utf-8"); const parsed2 = new LatexParser(log2, { @@ -23,7 +24,27 @@ describe("latex-log-parser", () => { const err0 = parsed2.all[0]; expect(err0.file).toEqual("ch_Euclidean.tex"); expect(err0.message).toEqual("Marginpar on page 1 moved."); - expect(parsed2.deps).toEqual(["01.tex", "02.5.tex"]); + expect(parsed2.deps).toEqual(["./livre1.bst", "01.tex", "02.5.tex"]); expect(parsed2.files).toEqual(["livre1.tex", "ch_Euclidean.tex"]); }); + + // Test for non-.tex/.bib files in dependencies (e.g., .txt files used via \input{}) + test("log3", () => { + const log3 = fs.readFileSync("./misc/latex-logs/log3.txt", "utf-8"); + const parsed3 = new LatexParser(log3, { + ignoreDuplicates: true, + }).parse(); + expect(parsed3.deps).toEqual([ + "../subdir0/file2.md", + "long-running.tex", + "long-running.txt", + "subdir/file_9", + ]); + // No .tex or .bib files in parentheses, so files array is empty + expect(parsed3.files).toEqual([]); + expect(parsed3.errors).toEqual([]); + expect(parsed3.warnings).toEqual([]); + expect(parsed3.typesetting).toEqual([]); + expect(parsed3.all).toEqual([]); + }); }); diff --git a/src/packages/frontend/misc/latex-logs/log3.txt b/src/packages/frontend/misc/latex-logs/log3.txt new file mode 100644 index 00000000000..072702d364c --- /dev/null +++ b/src/packages/frontend/misc/latex-logs/log3.txt @@ -0,0 +1,27 @@ +(./long-running.txt) (./subdir/file_9) +(../subdir0/file2.md) [1{/var/lib/texmf/fonts/map/pdftex/updmap/pdftex.map}] +(./long-running.aux) ) +Output written on long-running.pdf (1 page, 15440 bytes). +SyncTeX written on long-running.synctex.gz. +Transcript written on long-running.log. +Latexmk: Examining 'long-running.log' +=== TeX engine is 'pdfTeX' +Latexmk: applying rule 'pdflatex'... +Latexmk: All targets (long-running.pdf) are up-to-date +#===Dependents, and related info, for long-running.tex: +long-running.pdf :\ +../subdir0/file2.md\ +/etc/texmf/web2c/texmf.cnf\ +/usr/share/texlive/texmf-dist/fonts/type1/public/amsfonts/cm/cmr10.pfb\ +/usr/share/texlive/texmf-dist/tex/latex/base/article.cls\ +/usr/share/texlive/texmf-dist/tex/latex/base/size10.clo\ +/usr/share/texlive/texmf-dist/tex/latex/l3backend/l3backend-pdftex.def\ +/usr/share/texlive/texmf-dist/web2c/texmf.cnf\ +/usr/share/texmf/web2c/texmf.cnf\ +/var/lib/texmf/fonts/map/pdftex/updmap/pdftex.map\ +/var/lib/texmf/web2c/pdftex/pdflatex.fmt\ +long-running.tex\ +long-running.txt\ +subdir/file_9 +#===End dependents for long-running.tex: