unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: Markus Rost <rost@mathematik.uni-bielefeld.de>
Cc: occitan@esperanto.org, emacs-devel@gnu.org, storm@cua.dk
Subject: Re: compilation-forget-errors still used by tex-mode.el
Date: Sat, 20 Mar 2004 18:01:33 +0100	[thread overview]
Message-ID: <E1B4jqn-0003Df-00@yui26.Mathematik.Uni-Bielefeld.DE> (raw)
In-Reply-To: <jwvwu5g9apa.fsf-monnier+emacs@asado.iro.umontreal.ca> (message from Stefan Monnier on Fri, 19 Mar 2004 09:25:39 -0500)

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)
============================================================

  parent reply	other threads:[~2004-03-20 17:01 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <E1B1se8-0003lr-00@yui26.Mathematik.Uni-Bielefeld.DE>
     [not found] ` <jwvwu5p6949.fsf-monnier+emacs@asado.iro.umontreal.ca>
     [not found]   ` <jwvsmg6rm15.fsf-monnier+emacs@asado.iro.umontreal.ca>
     [not found]     ` <E1B43eN-0003F5-00@yui26.Mathematik.Uni-Bielefeld.DE>
     [not found]       ` <jwvn06dsy2i.fsf-monnier+emacs@asado.iro.umontreal.ca>
     [not found]         ` <E1B44qZ-0003Yp-00@yui26.Mathematik.Uni-Bielefeld.DE>
     [not found]           ` <jwvbrmtsup7.fsf-monnier+emacs@asado.iro.umontreal.ca>
     [not found]             ` <E1B45ij-0003ni-00@yui26.Mathematik.Uni-Bielefeld.DE>
     [not found]               ` <jwv1xnpsru8.fsf-monnier+emacs@asado.iro.umontreal.ca>
     [not found]                 ` <E1B46gC-0004BN-00@yui26.Mathematik.Uni-Bielefeld.DE>
2004-03-19  5:51                   ` compilation-forget-errors still used by tex-mode.el Stefan Monnier
2004-03-19 10:33                     ` Kim F. Storm
2004-03-19 14:25                       ` Stefan Monnier
2004-03-19 21:41                         ` Miles Bader
2004-03-20 17:01                         ` Markus Rost [this message]
2004-03-20 19:41                           ` Daniel Pfeiffer
2004-03-21  0:14                             ` Markus Rost
2004-03-31 11:57                         ` Daniel Pfeiffer
2004-04-01 13:13                           ` Kim F. Storm
2004-04-01 16:18                           ` monnier
2004-04-01 18:34                             ` Daniel Pfeiffer
2004-04-01 21:34                               ` Kim F. Storm
2004-04-02  2:01                                 ` Miles Bader
2004-04-02 11:07                                   ` Kim F. Storm
2004-04-02 16:10                                     ` Daniel Pfeiffer
2004-04-02 16:19                                     ` Stefan Monnier
2004-04-02 19:28                                       ` Kim F. Storm

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=E1B4jqn-0003Df-00@yui26.Mathematik.Uni-Bielefeld.DE \
    --to=rost@mathematik.uni-bielefeld.de \
    --cc=emacs-devel@gnu.org \
    --cc=occitan@esperanto.org \
    --cc=storm@cua.dk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).