Hi Jim, Jim Diamond <[email protected]> writes:
> A patch so that AUCTeX properly parses ConTeXt LMTX error messages. > > Aside from the required lisp code, I took the liberty of adding some > comments in relevant places to assist the next person who might try to > modify this code. Many thanks for working on this. Please find my comments below. > From 7877108bde8e1655678d4ba5ac13c39d806ffb3d Mon Sep 17 00:00:00 2001 > From: Jim Diamond <[email protected]> > Date: Mon, 2 Mar 2026 18:33:46 -0400 > Subject: [PATCH] Fix parsing of error messages for ConTeXt LMTX. > > * tex.el (TeX-parse-error, TeX-fin-display-help, TeX-error) ^ TeX-fin*d*-...? > TeX-help-error): many changes to these functions to handle error > messages output by ConTeXt LMTX. Can you be more specific about the changes? We usually describe briefly those changes. > Some illuminating comments added for the next person who touches this > code. (Bug#80350) * context.el (TeX-ConTeXt-sentinel): rewrite to > reflect ConTeXt LMTX error messages and to use > `TeX-ConTeXt-sentinel-check' instead of `TeX-TeX-sentinel-check'. Add > function `TeX-ConTeXt-sentinel-check' rather than adapting > `TeX-TeX-sentinel-check' since the ConTeXt LMTX error message syntax > is so different from that of pdftex et al. (Bug#80350) --- context.el > | 125 +++++++++++++++++++++++++++++++++++++---------------- tex.el | > 121 ++++++++++++++++++++++++++++++++++++++++----------- 2 files > changed, 182 insertions(+), 64 deletions(-) > > diff --git a/context.el b/context.el > index 84b3efef..3f78d4a8 100644 > --- a/context.el > +++ b/context.el > @@ -567,45 +567,94 @@ for a label to be inserted after the sectioning > command." > > > ;; Various > + > +;; This function is called with (current-buffer) = the output buffer. > +(defun TeX-ConTeXt-sentinel-check (process name) > + "Check ConTeXt (LMTX) output buffer after running TeX. > + Return t if errors were found." ^ ^ ^ Do you have an extra space at the beginning of the second line of the docstring? If so, please remove it. Are the extra spaces around t on purpose? > + ;; Set TeX-current-page to (effectively) match what > + ;; TeX-TeX-sentinel-check does: > + ;; -> if no errors, the number of pages shipped out; and > + ;; -> if errors, the number of pages shipped out + 1. > + ;; Also determine the extension of the output file. > + (save-excursion > + (goto-char (point-max)) > + (if (re-search-backward " > flushing realpage \\([0-9]+\\), " nil t) > + (setq TeX-current-page (TeX-match-buffer 1)) I think you have Tabs in your change, e.g., in the line above. AUCTeX repo has this in its .dir-locals.el: (emacs-lisp-mode . ((mode . bug-reference-prog) (electric-quote-comment . nil) (electric-quote-string . nil) (indent-tabs-mode . nil))) I wonder where those Tabs are coming? > + (setq TeX-current-page "0")) > + ;; If running in "don't quit on error" mode, there will be a > + ;; '^pages .* > flushing realpage' message after the '^tex error' > + ;; message. In this case, no need to add 1. > + (goto-char (point-min)) > + (if (re-search-forward "^tex error" nil t) > + (if (re-search-forward "^pages .* > flushing realpage" nil t) > + nil > + (setq TeX-current-page (number-to-string > + (+ 1 (string-to-number TeX-current-page)))))) (1+ (string-to-number TeX-current-page)) > + (setq TeX-current-page (concat "{" TeX-current-page "}")) > + (setq TeX-output-extension "pdf")) ;; for the last 200 years now, +/-. > + > + (if process (TeX-format-mode-line process)) > + > + (if (catch 'found > + (while (re-search-forward > + "^\\(?:.*tex error on line [0-9]+ in file \\(.+?\\):\\)" nil t) > + (if (or (not (match-beginning 1)) > + ;; Ignore non-error warning. (bug#55065) > + (file-exists-p (TeX-match-buffer 1))) > + (throw 'found t)))) > + (progn > + (if TeX-error-overview-open-after-TeX-run > + ;; Don't leave inconsistent message. > + (message nil) > + (message "%s errors in `%s'. Use %s to display." > + name (buffer-name) > + (substitute-command-keys > + "\\<TeX-mode-map>\\[TeX-next-error]")) > + ) No sole parenthesis in a line, please. > + (setq TeX-command-next TeX-command-default) > + ;; error reported to TeX-error-report-switches > + (setq TeX-error-report-switches > + (plist-put TeX-error-report-switches > + (intern (plist-get TeX-error-report-switches > + 'TeX-current-master)) > + t)) > + t) > + ;; In case that there were only non-error warnings of type > + ;; bug#55065, restore point to the initial position. > + (goto-char (point-min)) > + (setq TeX-command-next TeX-command-Show) > + nil)) > + > + > (defun TeX-ConTeXt-sentinel (process name) > - "Cleanup TeX output buffer after running ConTeXt." > - (cond > - ;; Mark IV > - ((with-current-buffer TeX-command-buffer > - (string= ConTeXt-Mark-version "IV")) > - (cond ((TeX-TeX-sentinel-check process name)) > - ((re-search-forward "fatal error: " nil t) > - (message (concat name ": problems after " > - (TeX-current-pages))) > - (setq TeX-command-next TeX-command-default)) > - (t > - (message (concat name ": successfully formatted " > - (TeX-current-pages))) > - (setq TeX-command-next TeX-command-Show)))) > - ;; Mark II > - (t > - (cond ((TeX-TeX-sentinel-check process name)) > - ((save-excursion > - ;; in a full ConTeXt run there will multiple texutil > - ;; outputs. Just looking for "another run needed" would > - ;; find the first occurence > - (goto-char (point-max)) > - (re-search-backward "TeXUtil " nil t) > - (re-search-forward "another run needed" nil t)) > - (message (concat "You should run ConTeXt again " > - "to get references right, " > - (TeX-current-pages))) > - (setq TeX-command-next TeX-command-default)) > - ((re-search-forward "removed files :" nil t) > - (message "sucessfully cleaned up")) > - ((re-search-forward "^ ?TeX\\(Exec\\|Util\\)" nil t) ;; strange > regexp --pg > - (message (concat name ": successfully formatted " > - (TeX-current-pages))) > - (setq TeX-command-next TeX-command-Show)) > - (t > - (message (concat name ": problems after " > - (TeX-current-pages))) > - (setq TeX-command-next TeX-command-default))))) > + "Examine the TeX output buffer after running ConTeXt. > + > + Parse the output buffer to collect errors and warnings if the > + variable `TeX-parse-all-errors' is non-nil. > + > + Open the error overview if > + `TeX-error-overview-open-after-TeX-run' is non-nil and there are > + errors or warnings to show." Again, the docstring seems to be intended. > + > + (if (TeX-ConTeXt-sentinel-check process name) > + (progn > + ;; ConTeXt LMTX stops after 1 error (unless "heroic" efforts are > + ;; made by the user to do otherwise) and if such efforts are made > + ;; the error messages in the log file are not complete (at least > + ;; as of ConTeXt Version 2026.02.12). Arguably it might make > + ;; sense to just call (TeX-parse-error) once (and set the other > + ;; variables as seen in (TeX-parse-all-errors)). But for now, ... > + (if TeX-parse-all-errors > + (TeX-parse-all-errors)) > + (if (and (with-current-buffer TeX-command-buffer > + TeX-error-overview-open-after-TeX-run) > + (TeX-error-overview-make-entries > + (TeX-master-directory) (TeX-active-buffer))) > + (TeX-error-overview))) > + > + (message (concat name ": formatted " (TeX-current-pages))) > + (setq TeX-command-next TeX-command-Show)) > (unless TeX-error-list > (run-hook-with-args 'TeX-after-compilation-finished-functions > (with-current-buffer TeX-command-buffer > diff --git a/tex.el b/tex.el > index 91d29d63..ce78d47c 100644 > --- a/tex.el > +++ b/tex.el > @@ -9654,24 +9654,28 @@ displaying the issue. > Return non-nil if an error or warning is found." > (let ((regexp > (concat > - ;; TeX error > + ;; TeX error: grab (1) filename:line-number and (2) filename: > "^\\(!\\|\\(.+?\\):[0-9]+:\\) \\|" > - ;; New file > + ;; New file (or parenthesized comment): match 3 > "(\n?\\([^\n()]+\\)\\|" > - ;; End of file. > + ;; End of file (or comment): "match" 4 > "\\()\\)\\|" > - ;; Hook to change line numbers > + ;; Hook to change line numbers: match 5 > " !\\(?:offset(\\([---0-9]+\\))\\|" > - ;; Hook to change file name > + ;; Hook to change file name: match 6 > "name(\\([^)]+\\))\\)\\|" > - ;; Start of LaTeX bad box > + ;; Start of LaTeX bad box: match 7 > "^\\(\\(?:Overfull\\|Underfull\\|Tight\\|Loose\\) " > ;; Horizontal bad box > "\\(?:\\\\hbox.* at lines? [0-9]+\\(?:--[0-9]+\\)?$\\|" > ;; Vertical bad box. See also `TeX-warning'. > "\\\\vbox ([ a-z0-9]+) has occurred while \\\\output is active > \\[[^]]+\\]\\)\\)\\|" > - ;; LaTeX warning > - "^\\(" LaTeX-warnings-regexp ".*\\)")) > + ;; LaTeX warning: match 8 > + "^\\(" LaTeX-warnings-regexp ".*\\)" > + ;; ConTeXt LMTX error; sample output line: > + ;; tex error > tex error on line 5 in file ./bbb.tex: ! > Undefined control sequence > + ;; Grab (9) entire line and (10) filename > + "\\|^\\(tex error .* in file \\([^:]*\\): \\)")) > (error-found nil)) > (while > (cond > @@ -9683,18 +9687,21 @@ Return non-nil if an error or warning is found." > (beep) > (TeX-pop-to-buffer old)) > nil) > - ;; TeX error > - ((match-beginning 1) > - (if (or (not (match-beginning 2)) > - ;; Ignore non-error warning. (bug#55065) > - (file-exists-p (TeX-match-buffer 2))) > + ;; TeX/LaTeX (1) or ConTeXt LMTX (9) error: > + ((or (match-beginning 1) (match-beginning 9)) > + (if (or ;; Ignore non-error warning. (bug#55065) > + (file-exists-p (TeX-match-buffer 2)) > + (file-exists-p (TeX-match-buffer 10))) > (progn > - (when (match-beginning 2) > - (unless TeX-error-file > - (push nil TeX-error-file) > - (push nil TeX-error-offset)) > - (unless (car TeX-error-offset) > - (rplaca TeX-error-file (TeX-match-buffer 2)))) > + (unless TeX-error-file > + (push nil TeX-error-file) > + (push nil TeX-error-offset)) > + (unless (car TeX-error-offset) > + ;; match 2 or 10 is the .tex file name. > + (rplaca TeX-error-file > + (if (match-beginning 2) > + (TeX-match-buffer 2) > + (TeX-match-buffer 10)))) > (setq error-found t) > (if (looking-at "Preview ") > t > @@ -9815,6 +9822,7 @@ value is not used here." > (setq-local TeX-command-buffer command-buffer) > > ;; Find the location of the error or warning. > + ;; Note: we are searching in the TeX/ConTeXt *source file*. Another TAB. > (let ((narrowed (buffer-narrowed-p)) > (visible-min (point-min)) > (visible-max (point-max)) > @@ -9868,6 +9876,21 @@ value is not used here." > (t > (message "! %s" TeX-translate-location-error))))) > > + > +;; TeX and ConTeXt LMTX error messages are formatted differently (and thus > +;; some tweakings are necessary for ConTeXt error messages to be parsed). > +;; E.g., in TeX: > +;; ./file.tex:9: Undefined control sequence. > +;; l.9 blah blah \undefinedINplainTEX > +;; <<< line with many initial spaces > +;; and in ConTeXt: > +;; tex error > tex error on line 9 in file ./file.tex: Undefined > control sequence > +;; <<<--- empty line here > +;; <line 3.9> > +;; aardvark \undefinedINcontext > +;; <<<--- empty line here > +;; Because of how the parsing is done below, these formatting differences > +;; must be handled. > (defun TeX-error (&optional store) > "Display an error. > > @@ -9894,16 +9917,48 @@ information in `TeX-error-list' instead of displaying > the error." > (re-search-backward ":\\([0-9]+\\): " > (line-beginning-position) t)) > (string-to-number (TeX-match-buffer 1))) > + ;; ConTeXt: ^<line n.[linenum]>\n +[error message]' > + ((re-search-forward "^<line [^.]+[.]\\([0-9]+\\)>" nil t) > + ;; Need this in the ConTeXt case for the 'string' search > + ;; (just below here) to work correctly (FWIW): > + (forward-line) > + (setq context-available t) > + ;; ConTeXt has a blank line where pdftex does not; adjust: > + (setq context-start (1+ context-start)) > + (string-to-number (TeX-match-buffer 1))) > ;; nothing found > (t 1))) > > - ;; And a string of the context to search for. > + ;; Save a string of the error token, used to position the cursor > + ;; in the source file. > + ;; plain TeX example of what we are looking at: > + ;; ((point) is before ' aard...') > + ;; l.9 aardvark \undefinedINplainTEX > + ;; \n > + ;; ConTeXt: > + ;; ((point) is before ' aard...') > + ;; aardvark \undefinedINcontext > + ;; \n > + ;; The pdftex error message *always* has a line starting with > + ;; spaces after the error line. > + ;; ConTeXt LMTX (V 2026.02.12 anyway) does not have such a thing > + ;; when the error token is at the end of a line. Because of the > + ;; space chars on the line following the pdftex error message, the > + ;; (following) regexp in the previous version of this function > + ;; didn't include the \n at the end of the line(s). > + ;; However, since ConTeXt may have no space chars on the next > + ;; line, the match includes the \n, which causes TeX-next-error to > + ;; position the cursor incorrectly. > + ;; This regexp deals with this problem. > (string (progn > (beginning-of-line) > - (re-search-forward " \\(\\([^ \t]*$\\)\\|\\($\\)\\)") > + (re-search-forward " \\(\\([^ \t\n\r]*$\\)\\|\\($\\)\\)") > (TeX-match-buffer 1))) > > - ;; And we have now found to the end of the context. > + ;; (point) is now positioned at the end of the input line > + ;; which caused this error (TeX) or the beginning of the next > + ;; line (ConTeXt). To find the error context, rather than > searching > + ;; just use (point) and locations we saved above. > (context (if context-available > (buffer-substring context-start (progn (forward-line 1) > (end-of-line) > @@ -9917,7 +9972,7 @@ information in `TeX-error-list' instead of displaying > the error." > (file (car TeX-error-file)) > info-list) > > - ;; Remember where we was. > + ;; Remember where we were. > (setq TeX-error-point (point) > info-list (list 'error file line error offset context string nil > nil > TeX-error-point nil)) > @@ -10204,15 +10259,29 @@ a bad box." > (insert-file-contents log-file nil nil nil 'replace) > (setq TeX--log-file-readin-modtime modtime))) > (goto-char (point-min)) > - (when (and (search-forward error nil t 1) > + (if (and (search-forward error nil t 1) > (re-search-forward "^l\\." nil t) > (re-search-forward "^ [^\n]+$" nil t)) > (let ((start (1+ (point)))) > (forward-char 1) > (re-search-forward "^$") > (concat "From the .log file...\n\n" > - (buffer-substring start (point))))))) > - help)))) > + (buffer-substring start (point)))) > + ;; ConTeXt case: assume just one error per run, > + ;; since it requires some ConTeXt wizardry to not > + ;; stop on the first error, and, if the run > + ;; doesn't stop on the first error, getting > + ;; meaningful info from the log file is very > + ;; difficult. > + (goto-char (point-max)) > + (if (re-search-backward "^[0-9]+ ") > + (progn > + (end-of-line) > + (let ((start (1+ (point)))) > + (goto-char (point-max)) > + (concat "From the .log file...\n\n" > + (buffer-substring start (point))))))))) You could also do: (when (re-search-backward "^[0-9]+ ") (end-of-line) ... and get rid of that `progn'. > + help)))) > (goto-char (point-min)) > (TeX-special-mode) > (TeX-pop-to-buffer old-buffer nil t))) Can you please consider my comments and send a new patch? I will try to read the code more carefully during the next round. TIA. Best, Arash _______________________________________________ bug-auctex mailing list [email protected] https://lists.gnu.org/mailman/listinfo/bug-auctex
