[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: compilation-forget-errors still used by tex-mode.el
From: |
Markus Rost |
Subject: |
Re: compilation-forget-errors still used by tex-mode.el |
Date: |
Sat, 20 Mar 2004 18:01:33 +0100 |
As for ideas: What about having for tex compilation parses an option
like
(defcustom tex-plus-error-parse-level nil
"*If non-nil, consider also over/underfull hbox messages as errors.
This enables you to jump to the corresponding source locations."
:type 'boolean
:group 'tex-run)
I once wrote a corresponding hack and use it a lot.
It seems however that one can't use it directly with the new
compile.el and I don't have the time to adjust it. In case someone is
interested, I append here the file containing the code.
===File ~/emacs/lisp/emacs-21/tex-plus.el===================
(let ((l0 (car ispell-tex-skip-alists))
(l1 (cadr ispell-tex-skip-alists)))
(add-to-list 'l0 '("\\\\\\(eq\\)?ref" ispell-tex-arg-end))
(add-to-list 'l0 '("\\\\label" ispell-tex-arg-end))
(add-to-list 'l0 '("[^\\]%.*$"))
(add-to-list 'l1 '("gather\\*?" . "\\\\end[ \t\n]*{[ \t\n]*gather\\*?[
\t\n]*}") t)
(add-to-list 'l1 '("align\\*?" . "\\\\end[ \t\n]*{[ \t\n]*align\\*?[
\t\n]*}") t)
(setcar ispell-tex-skip-alists l0)
(setcar (cdr ispell-tex-skip-alists) l1))
(require 'tex-mode)
(if (string-lessp emacs-version "21.3.49")
(defvar tex-compile-commands nil))
(defvar tex-compile-commands-0 tex-compile-commands
"The original value of `tex-compile-commands'
Used in combination with `tex-compile-commands-1'
Don't set this variable yourself.")
(defcustom tex-compile-commands-1 nil
"List of additional commands for `tex-compile'.
Prepended to `tex-compile-commands-0' to set `tex-compile-commands'.
Set this variable with customize.
See `tex-compile-commands' for the syntax."
:type '(repeat (list
(radio :tag "Commands"
string sexp)
(choice :tag "Input File"
(string :tag "String")
(const :tag "TeX files of the document" t)
(const :tag "Don't know" nil))
(choice :tag "Output File"
(string :tag "String")
(const :tag "No Output File" nil))))
:set (lambda (symbol value)
(set-default symbol value)
(setq tex-compile-commands
(append value (copy-sequence tex-compile-commands-0))))
:group 'tex-run)
;;; Customize the tex-shell.
;; I want it to use HISTFILE=~/.bash/.bash1_history
(defcustom tex-shell-hook nil
"Hook for `tex-shell'."
:type 'hook
:group 'tex-run)
(defcustom tex-shell-file-name nil
"*If non-nil, the shell file name to run in the subshell used to run TeX.
See also `tex-shell-arg-list'."
:type '(choice (const :tag "None" nil)
string)
:group 'tex-run)
(defcustom tex-shell-arg-list nil
"*Alist of options passed to subshell used to run TeX.
See also `tex-shell-file-name'."
:type '(repeat :tag "Option list" string)
:group 'tex-run)
(defun tex-start-shell ()
(with-current-buffer
(apply 'make-comint
"tex-shell"
(or tex-shell-file-name explicit-shell-file-name
(getenv "ESHELL") (getenv "SHELL") "/bin/sh")
nil (or tex-shell-arg-list '("-i")))
(let ((proc (get-process "tex-shell")))
(set-process-sentinel proc 'tex-shell-sentinel)
(process-kill-without-query proc)
(tex-shell)
(while (zerop (buffer-size))
(sleep-for 1)))))
;;; My error parsing.
(defadvice tex-send-tex-command (after tex-plus-compilation activate)
(when (tex-shell-running)
(with-current-buffer (process-buffer (tex-shell-running))
(setq compilation-parse-errors-function
'tex-plus-compilation-parse-errors)
;; Clean up.
(let ((buffer-undo-list t)
(inhibit-read-only t)
deactivate-mark)
;; Remove the text-properties added by
;; tex-plus-compilation-parse-errors.
(if compilation-old-error-list
(remove-text-properties (point-min) (point-max)
'(syntax-table nil)))))))
(defvar tex-plus-start-tex-marker nil
"Marker pointing after last TeX-running command in the TeX shell buffer.")
(defcustom tex-plus-error-parse-level nil
"*If non-nil, consider also over/underfull hbox messages as errors.
This enables you to jump to the corresponding source locations."
:type 'boolean
:group 'tex-run)
;;; Error Parsing
(easy-mmode-defsyntax
tex-plus-error-parse-syntax-table
'((?\{ . "_")
(?\} . "_")
(?\[ . "_")
(?\] . "_")
(?\" . "_"))
"A syntax table used by `tex-plus-compilation-parse-errors'.
Only \"(\" and \")\" are seen by backward-list.")
(easy-mmode-defsyntax
tex-plus-error-skip-syntax-table
'((?\( . "_")
(?\) . "_")
(?\{ . "_")
(?\} . "_")
(?\[ . "_")
(?\] . "_")
(?\" . "_"))
"A syntax table used by `tex-plus-compilation-parse-errors'.
No characters are seen by backward-list.")
(defun tex-plus-compilation-parse-errors (limit-search find-at-least)
"Parse the current buffer as TeX error messages.
See the variable `compilation-parse-errors-function' for the interface it uses.
This function parses only the last TeX compilation.
A special parsing routine is necessary, since TeX does not put file
names and line numbers on the same line as for the error messages."
(require 'thingatpt)
(setq compilation-error-list nil)
(message "Parsing error messages...")
(let (;; First a kind of buffer-save-state.
(buffer-undo-list t) (inhibit-read-only t) deactivate-mark
;; Dir may have changed.
(default-directory
(file-name-directory (buffer-file-name tex-last-buffer-texed)))
;; We use syntax-table text-properties.
(parse-sexp-lookup-properties t)
;; To restore it later.
(err-buf (current-buffer))
;; We need a table with only "(" and ")" seen by backward-list.
;; (tex-plus-error-parse-syntax-table
;; (let ((table (copy-syntax-table)))
;; (modify-syntax-entry ?\{ "_" table)
;; (modify-syntax-entry ?\} "_" table)
;; (modify-syntax-entry ?\[ "_" table)
;; (modify-syntax-entry ?\] "_" table)
;; (modify-syntax-entry ?\" "_" table)
;; table))
;; We need a table with no characters seen by backward-list.
;; (tex-plus-error-skip-syntax-table
;; (let ((table (copy-syntax-table)))
;; (modify-syntax-entry ?\( "_" table)
;; (modify-syntax-entry ?\) "_" table)
;; (modify-syntax-entry ?\{ "_" table)
;; (modify-syntax-entry ?\} "_" table)
;; (modify-syntax-entry ?\[ "_" table)
;; (modify-syntax-entry ?\] "_" table)
;; (modify-syntax-entry ?\" "_" table)
;; table))
;; We freeze point-max here to care about a running tex
;; process.
(current-point-max (point-max)) output-finished
;; The variables to play with.
(num-errors-found 0) parsing-end
last-error last-linenum
error-msg error-type error-start error-end error-text
linenum filename error-source)
;; Do we reparse or parse the first time?
(when (eq (marker-position compilation-parsing-end) 1)
;; If `compilation-forget-errors' would run a hook, that should
;; go there. What about a compilation-forget-errors-function?
(if (and (markerp tex-plus-start-tex-marker)
(eq (current-buffer) (marker-buffer tex-plus-start-tex-marker)))
(set-marker compilation-parsing-end tex-plus-start-tex-marker))
(remove-text-properties (point-min) (point-max) '(syntax-table nil)))
(goto-char compilation-parsing-end)
;; Is the tex run finished?
(save-excursion
(if (setq output-finished
(re-search-forward
"^Transcript written on " nil t))
;; Then limit the parse to its output.
(setq current-point-max output-finished)))
;; Parse messages.
;; To determine the error file we use backward-list with
;; syntax-table tex-plus-error-parse-syntax-table. The messages may
;; contain characters "(" and ")" which irritate the scanning.
;; Therefore the messages receive the syntax-table text-property
;; tex-plus-error-skip-syntax-table.
;; There are basically two types of messages: (I) true tex errors
;; and (II) messages about overfull hboxes and similar things.
;; If the user option `tex-plus-error-parse-level' is nil, type (II)
;; errors are neglected by default for
;; `compilation-error-list'. Otherwise they are treated in the
;; same way as type (I) errors.
(catch 'parsing-end
(while t
(unless
(re-search-forward
;; A regexp for all relevant messages.
;; It is probably incomplete.
"^\\(! \\|\\(Over\\|Under\\)full \\\\.*lines? \\([0-9]+\\)\\)"
current-point-max t)
;; No more messages: exit.
(setq parsing-end current-point-max)
(throw 'parsing-end nil))
(goto-char (match-beginning 0))
(setq error-msg (point-marker))
(setq error-start error-msg)
(cond
((looking-at "^! Emergency stop\\.")
;; A special case: We are at the end.
(setq parsing-end current-point-max)
(throw 'parsing-end nil))
((looking-at "^! ")
;; It is a type (I) error.
(setq error-type t)
;; In a "Runaway argument?", the error lines start before the
;; error message "! Paragraph ended..."
(if (looking-at "^! Paragraph ended before .* was complete.$")
(save-excursion
(forward-line -2)
(if (looking-at "^Runaway argument\\?\n ")
(setq error-start (point-marker)))))
(unless (re-search-forward
"^l\\.\\([0-9]+\\) \\(\\.\\.\\.\\)?\\(.*\\)$"
current-point-max t)
;; The output is not finished: forget this error and exit.
(setq parsing-end error-msg)
(throw 'parsing-end nil))
;; Find the end of this error.
(goto-char (match-end 0))
(forward-line)
(end-of-line)
(setq error-end (point))
;; Get line number and text for searching the source.
(setq linenum (string-to-int (match-string 1)))
(setq error-text (regexp-quote (match-string 3))))
((looking-at "^\\(Over\\|Under\\)full \\\\.*lines? \\([0-9]*\\)")
;; It is a type (II) error.
(setq error-type tex-plus-error-parse-level)
;; Find the end of this error. Code in parts stolen from
;; TeX-warning in tex-buf.el from AUC TeX.
(forward-line)
(end-of-line)
(while (or (equal (current-column) 79)
(save-excursion
(forward-line)
(save-match-data
;; perhaps incomplete or/and incorrect.
;; Maybe just exclude all lines with a \
;; (except for "^! " lines)?
(looking-at "\\( \\\\\\|.*\\[\\]\\)"))))
(forward-line)
(end-of-line))
(setq error-end (point))
(when (>= error-end current-point-max)
;; Output of this error is probably not finished:
;; forget this error and exit.
(setq parsing-end error-msg)
(throw 'parsing-end nil))
;; Get the line number of the source.
(setq linenum (string-to-int (match-string 2)))
;; Getting the error-text is too hard.
;; It is anyway not interesting if `tex-plus-error-parse-level' is
nil.
(setq error-text nil)))
;; Put appropriate syntax around the message.
(add-text-properties
error-start error-end
(list 'syntax-table tex-plus-error-skip-syntax-table))
(when error-type
;; Search for and in the source.
(goto-char error-start)
(save-excursion
(with-syntax-table tex-plus-error-parse-syntax-table
(if (or (null last-error)
(save-restriction
(narrow-to-region (car last-error) (point))
(condition-case ()
(while (not (bobp)) (backward-list 1))
(error t))))
;; Have to scan for the file.
(progn
(backward-up-list 1)
(skip-syntax-forward "(_")
(setq filename (thing-at-point 'filename))
(if (or (= 0 (length filename))
(not (file-exists-p filename)))
;; We failed, but continue the parse.
;; Here we could also give up with (error ...)
(message "Couldn't guess source file for error %s"
error-msg))
(if (equal filename (concat tex-zap-file ".tex"))
(set-buffer tex-last-buffer-texed)
(set-buffer (find-file-noselect filename)))
(save-restriction
(widen)
(goto-line linenum)
(or (null error-text)
(re-search-forward error-text nil t)
(re-search-backward error-text nil t))
(setq error-source (point-marker))))
;; No new file.
(set-buffer (marker-buffer (cdr last-error)))
(goto-char (cdr last-error))
(forward-line (- linenum last-linenum))
;; First try a forward search for the error text,
;; then a backward search limited by the last error
;; in this file, if it exists.
(or (null error-text)
(re-search-forward error-text nil t)
(re-search-backward error-text (cdr last-error) t))
(setq error-source (point-marker)))
(set-buffer err-buf)))
;; Have we found more than enough errors? Yes, if we are
;; beyond the requirements, if there is a previous error,
;; and if the following is true: The error is in a new file
;; or we have parsed already 50 errors.
;; The limit 50 is a heuristic. It avoids a long parse if
;; something really bad happened with the tex run and one
;; just wants to jump to the first few errors.
;; Such a break should be allowed by compilation-mode: An
;; equivalent break happens once in a while when the grep
;; process is running while parsing.
(when (and
(if limit-search
(>= error-msg limit-search) t)
(if find-at-least
(>= num-errors-found find-at-least) t)
compilation-error-list
(or (not (eq (marker-buffer error-source)
(marker-buffer (cdr last-error))))
(>= num-errors-found 50)))
;; We forget this error and exit.
(setq parsing-end error-msg)
(throw 'parsing-end nil))
;; Put it on the list and prepare for the next error.
(setq last-error (cons error-msg error-source)
compilation-error-list (nconc compilation-error-list
(list last-error))
num-errors-found (1+ num-errors-found)
last-linenum linenum
parsing-end error-end)
(if (>= num-errors-found 10)
(message "Parsing error messages...[%s]"
(+ num-errors-found
(length compilation-old-error-list)))))
;; Go to the end of message and continue the loop.
(goto-char error-end)))
;; Set `compilation-parsing-end' only here, in case of an error
;; while parsing.
(if (and output-finished (eq parsing-end current-point-max))
;; All errors are parsed. Put compilation-parsing-end at the
;; very end of buffer, moving with insertions. This avoids
;; unnecessary reparsing in some situations.
(progn (set-marker compilation-parsing-end (point-max-marker))
(set-marker-insertion-type compilation-parsing-end t))
(set-marker compilation-parsing-end parsing-end)))
(message "Parsing error messages...done"))
(provide 'tex-plus)
============================================================