[comp.emacs] generalized compile.el

mark@hyper.UUCP (Mark Mendel) (01/10/88)

Here is a patch to compile.el from GNU Emacs 18.33.

I replaced the  single, complex compilation-error-regexp variable with a list
of regular expressions, compilation-error-regexps.  Each of these regular
expressions must contain two parenthesized sub-expressions which delimit the
file name and line number [in either order].

This allows easy customization to handle the output from different
compilers. 

If the match succeeds but the file name is empty, the file name from the
previous error is assumed.  This provides support for compilers like the TEK
68020 assembler that only prints the filename once for each file.

With the old version, you could change the regexp, but then the code that
extracted the filename from the match wouldn't work properly.

WARNING: You may have to add the regexps for some compilers that were covered
by the orignal regexp, but don't match any of my regexps.

Look at the value and documentation for the variable compilation-error-regexps
to see how to add new regexps.

The diff:


*** orig/compile.el	Sat Jan  9 09:49:17 1988
--- compile.el	Sat Jan  9 09:48:45 1988
***************
*** 39,45
    "Position of end of buffer when last error messages parsed.")
  
  (defvar compilation-error-message nil
!   "Message to print when no more matches for compilation-error-regexp are found")
  
  (defvar compilation-error-regexp
    "\\([^ \n]+\\(: *\\|, line \\|(\\)[0-9]+\\)\\|\\([0-9]+.*of *[^ \n]+\\)"

--- 39,45 -----
    "Position of end of buffer when last error messages parsed.")
  
  (defvar compilation-error-message nil
!   "Message to print when no more matches for compilation-error-regexps are found")
  
  (defvar compilation-error-regexps
    '("^[^\"]*\"\\([^\"]*\\)\", line \\([0-9]+\\)" 	; Tek Version 020
***************
*** 41,49
  (defvar compilation-error-message nil
    "Message to print when no more matches for compilation-error-regexp are found")
  
! (defvar compilation-error-regexp
!   "\\([^ \n]+\\(: *\\|, line \\|(\\)[0-9]+\\)\\|\\([0-9]+.*of *[^ \n]+\\)"
!   "Regular expression for filename/linenumber in error in compilation log.")
  
  (defun compile (command)
    "Compile the program including the current buffer.  Default: run make.

--- 41,56 -----
  (defvar compilation-error-message nil
    "Message to print when no more matches for compilation-error-regexps are found")
  
! (defvar compilation-error-regexps
!   '("^[^\"]*\"\\([^\"]*\\)\", line \\([0-9]+\\)" 	; Tek Version 020
!     "^\\(.*\\): *\\([0-9]\\)+:"	      			; Ultrix cc
!     "^\\([^(]*\\)(\\([0-9]+\\)):"			; lint
!     "^In file \"\\([^\"]*\\)\":\n  \\([0-9]+\\):"	; Tek assembler
!     "^  \\([0-9]+\\):\\(\\)"				; Tek assembler
!     )
!   "List of regular expressions to match filename/linenumber in compiation log.
! Two parenthesized expressions must match filename & linenumber, in either
! order. If the filename is nil, the file name from the previous match is used.")
  
  (defun compile (command)
    "Compile the program including the current buffer.  Default: run make.
***************
*** 89,95
      (terpri)
      (princ command)
      (terpri))
!   (let ((regexp compilation-error-regexp))
      (save-excursion
        (switch-to-buffer "*compilation*")
        (make-local-variable 'compilation-error-regexp)

--- 96,102 -----
      (terpri)
      (princ command)
      (terpri))
!   (let ((regexp compilation-error-regexps))
      (save-excursion
        (switch-to-buffer "*compilation*")
        (make-local-variable 'compilation-error-regexps)
***************
*** 92,99
    (let ((regexp compilation-error-regexp))
      (save-excursion
        (switch-to-buffer "*compilation*")
!       (make-local-variable 'compilation-error-regexp)
!       (setq compilation-error-regexp regexp)))
    (set-process-sentinel compilation-process 'compilation-sentinel)
    (let* ((thisdir default-directory)
  	 (outbuf (process-buffer compilation-process))

--- 99,106 -----
    (let ((regexp compilation-error-regexps))
      (save-excursion
        (switch-to-buffer "*compilation*")
!       (make-local-variable 'compilation-error-regexps)
!       (setq compilation-error-regexps regexp)))
    (set-process-sentinel compilation-process 'compilation-sentinel)
    (let* ((thisdir default-directory)
  	 (outbuf (process-buffer compilation-process))
***************
*** 223,229
    (setq compilation-error-list nil)
    (message "Parsing error messages...")
    (let (text-buffer
! 	last-filename last-linenum)
      ;; Don't reparse messages already seen at last parse.
      (goto-char compilation-parsing-end)
      ;; Don't parse the first two lines as error messages.

--- 230,242 -----
    (setq compilation-error-list nil)
    (message "Parsing error messages...")
    (let (text-buffer
! 	last-filename last-linenum regexp regexps)
!     (setq regexps compilation-error-regexps)
!     (setq regexp (car regexps))
!       (while (setq regexps (cdr regexps))
! 	(setq regexp
! 	      (concat regexp "\\|" (car regexps))))
! 
      ;; Don't reparse messages already seen at last parse.
      (goto-char compilation-parsing-end)
      ;; Don't parse the first two lines as error messages.
***************
*** 230,237
      ;; This matters for grep.
      (if (bobp)
  	(forward-line 2))
!     (while (re-search-forward compilation-error-regexp nil t)
!       (let (linenum filename
  	    error-marker text-marker)
  	;; Extract file name and line number from error message.
  	(save-restriction

--- 243,250 -----
      ;; This matters for grep.
      (if (bobp)
  	(forward-line 2))
!     (while (compilation-match-error regexp)
!       (let (linenum filename m1 m2
  	    error-marker text-marker)
  
  	;; Extract file name and line number from error message.
***************
*** 233,238
      (while (re-search-forward compilation-error-regexp nil t)
        (let (linenum filename
  	    error-marker text-marker)
  	;; Extract file name and line number from error message.
  	(save-restriction
  	  (narrow-to-region (match-beginning 0) (match-end 0))

--- 246,252 -----
      (while (compilation-match-error regexp)
        (let (linenum filename m1 m2
  	    error-marker text-marker)
+ 
  	;; Extract file name and line number from error message.
  	(setq m1 (buffer-substring (match-beginning 1) (match-end 1))
  	      m2 (buffer-substring (match-beginning 2) (match-end 2)))
***************
*** 234,266
        (let (linenum filename
  	    error-marker text-marker)
  	;; Extract file name and line number from error message.
! 	(save-restriction
! 	  (narrow-to-region (match-beginning 0) (match-end 0))
! 	  (goto-char (point-max))
! 	  (skip-chars-backward "[0-9]")
! 	  ;; If it's a lint message, use the last file(linenum) on the line.
! 	  ;; Normally we use the first on the line.
! 	  (if (= (preceding-char) ?\()
! 	      (progn
! 		(narrow-to-region (point-min) (1+ (buffer-size)))
! 		(end-of-line)
! 		(re-search-backward compilation-error-regexp)
! 		(skip-chars-backward "^ \t\n")
! 		(narrow-to-region (point) (match-end 0))
! 		(goto-char (point-max))
! 		(skip-chars-backward "[0-9]")))
! 	  ;; Are we looking at a "filename-first" or "line-number-first" form?
! 	  (if (looking-at "[0-9]")
! 	      (progn
! 		(setq linenum (read (current-buffer)))
! 		(goto-char (point-min)))
! 	    ;; Line number at start, file name at end.
! 	    (progn
! 	      (goto-char (point-min))
! 	      (setq linenum (read (current-buffer)))
! 	      (goto-char (point-max))
! 	      (skip-chars-backward "^ \t\n")))
! 	  (setq filename (compilation-grab-filename)))
  	;; Locate the erring file and line.
  	(if (and (equal filename last-filename)
  		 (= linenum last-linenum))

--- 248,267 -----
  	    error-marker text-marker)
  
  	;; Extract file name and line number from error message.
! 	(setq m1 (buffer-substring (match-beginning 1) (match-end 1))
! 	      m2 (buffer-substring (match-beginning 2) (match-end 2)))
! 	(if (string-match "^[0-9]+$" m1)
! 	    (setq linenum m1
! 		  filename m2)
! 	  (setq linenum m2
! 		filename m1))
! 
! 	(setq linenum (string-to-int linenum))
! 
! 	(if (string-equal filename "")
! 	    ; handle <filename> / multiple <linenum>s 
! 	    (setq filename last-filename))
! 
  	;; Locate the erring file and line.
  	(if (and (equal filename last-filename)
  		 (= linenum last-linenum))
***************
*** 265,272
  	(if (and (equal filename last-filename)
  		 (= linenum last-linenum))
  	    nil
- 	  (beginning-of-line 1)
- 	  (setq error-marker (point-marker))
  	  ;; text-buffer gets the buffer containing this error's file.
  	  (if (not (equal filename last-filename))
  	      (setq text-buffer

--- 266,271 -----
  	(if (and (equal filename last-filename)
  		 (= linenum last-linenum))
  	    nil
  	  ;; text-buffer gets the buffer containing this error's file.
  	  (if (not (equal filename last-filename))
  	      (setq text-buffer
***************
*** 276,281
  	  (if text-buffer
  	      ;; Go to that buffer and find the erring line.
  	      (save-excursion
  		(set-buffer text-buffer)
  		(if (zerop last-linenum)
  		    (progn

--- 275,282 -----
  	  (if text-buffer
  	      ;; Go to that buffer and find the erring line.
  	      (save-excursion
+ 		(beginning-of-line 1)
+ 		(setq error-marker (point-marker))
  		(set-buffer text-buffer)
  		(if (zerop last-linenum)
  		    (progn
***************
*** 286,293
  		(setq text-marker (point-marker))
  		(setq compilation-error-list
  		      (cons (list error-marker text-marker)
! 			    compilation-error-list)))))
! 	(forward-line 1)))
      (setq compilation-parsing-end (point-max)))
    (message "Parsing error messages...done")
    (setq compilation-error-list (nreverse compilation-error-list)))

--- 287,293 -----
  		(setq text-marker (point-marker))
  		(setq compilation-error-list
  		      (cons (list error-marker text-marker)
! 			    compilation-error-list)))))))
      (setq compilation-parsing-end (point-max)))
    (message "Parsing error messages...done")
    (setq compilation-error-list (nreverse compilation-error-list)))
***************
*** 292,309
    (message "Parsing error messages...done")
    (setq compilation-error-list (nreverse compilation-error-list)))
  
! (defun compilation-grab-filename ()
!   "Return a string which is a filename, starting at point.
! Ignore quotes and parentheses around it, as well as trailing colons."
!   (if (eq (following-char) ?\")
!       (save-restriction
! 	(narrow-to-region (point)
! 			  (progn (forward-sexp 1) (point)))
! 	(goto-char (point-min))
! 	(read (current-buffer)))
!     (buffer-substring (point)
! 		      (progn
! 			(skip-chars-forward "^ :,\n\t(")
! 			(point)))))
  
  (define-key ctl-x-map "`" 'next-error)

--- 292,306 -----
    (message "Parsing error messages...done")
    (setq compilation-error-list (nreverse compilation-error-list)))
  
! (defun compilation-match-error (compilation-error-regexp)
!   (and (re-search-forward compilation-error-regexp nil t)
!        (let (regexps end)
! 	 (setq regexps compilation-error-regexps
! 	       end (match-end 0))
! 	 (goto-char (match-beginning 0))
! 	 (while (and regexps
! 		     (not (re-search-forward (car regexps) end t)))
! 	   (setq regexps (cdr regexps)))
! 	 regexps)))
  
  (define-key ctl-x-map "`" 'next-error)
-- 
Mark G. Mendel, ihnp4!umn-cs!hyper!mark,  Network Systems Corporation
(612)-424-4888 x2779