entered into RCS
[bpt/emacs.git] / lisp / progmodes / compile.el
CommitLineData
daa37602 1;;; compile.el --- run compiler as inferior of Emacs, parse error messages.
fad160d5 2
29add8b9 3;; Author: Roland McGrath <roland@prep.ai.mit.edu>
d1c7011d
ER
4;; Maintainer: FSF
5;; Last-Modified: 05 Jul 1992
fd7fa35a 6;; Keyword: tools, processes
d1c7011d 7
d3cb357b 8;;;!!! dup removal is broken.
fad160d5 9
29add8b9 10;; Copyright (C) 1985, 86, 87, 92 Free Software Foundation, Inc.
55dfd2c4
RS
11
12;; This file is part of GNU Emacs.
13
29add8b9
RM
14;; GNU Emacs is free software; you can redistribute it and/or modify
15;; it under the terms of the GNU General Public License as published by
16;; the Free Software Foundation; either version 2, or (at your option)
17;; any later version.
18
55dfd2c4 19;; GNU Emacs is distributed in the hope that it will be useful,
29add8b9
RM
20;; but WITHOUT ANY WARRANTY; without even the implied warranty of
21;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22;; GNU General Public License for more details.
23
24;; You should have received a copy of the GNU General Public License
25;; along with GNU Emacs; see the file COPYING. If not, write to
26;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
55dfd2c4 27
d1c7011d
ER
28;;; Code:
29
7c163413
RM
30;;;###autoload
31(defvar compilation-mode-hook nil
32 "*List of hook functions run by compilation-mode (see `run-hooks').")
33
34;;;###autoload
d3cb357b
RM
35(defconst compilation-window-height nil
36 "*Number of lines in a compilation window. If nil, use Emacs default.")
37
55dfd2c4
RS
38(defvar compilation-error-list nil
39 "List of error message descriptors for visiting erring functions.
d3cb357b 40Each error descriptor is a cons (or nil).
55dfd2c4 41Its car is a marker pointing to an error message.
d3cb357b
RM
42If its cdr is a marker, it points to the text of the line the message is about.
43If its cdr is a cons, that cons's car is a cons (DIRECTORY . FILE), specifying
44file the message is about, and its cdr is the number of the line the message
45is about. Or its cdr may be nil if that error is not interesting.
46
47The value may be t instead of a list; this means that the buffer of
48error messages should be reparsed the next time the list of errors is wanted.")
55dfd2c4
RS
49
50(defvar compilation-old-error-list nil
51 "Value of `compilation-error-list' after errors were parsed.")
52
d3cb357b
RM
53(defvar compilation-parse-errors-function 'compilation-parse-errors
54 "Function to call (with no args) to parse error messages from a compilation.
55It should read in the source files which have errors and set
56`compilation-error-list' to a list with an element for each error message
57found. See that variable for more info.")
55dfd2c4 58
aa228418 59;;;###autoload
d3cb357b 60(defvar compilation-buffer-name-function nil
aa228418 61 "*Function to call with one argument, the name of the major mode of the
d3cb357b
RM
62compilation buffer, to give the buffer a name. It should return a string.
63If nil, the name \"*compilation*\" is used for compilation buffers,
64and the name \"*grep*\" is used for grep buffers.
aa228418 65\(Actually, the name (concat \"*\" (downcase major-mode) \"*\") is used.)")
55dfd2c4 66
aa228418 67;;;###autoload
d3cb357b 68(defvar compilation-finish-function nil
aa228418 69 "*Function to call when a compilation process finishes.
d3cb357b
RM
70It is called with two arguments: the compilation buffer, and a string
71describing how the process finished.")
55dfd2c4 72
d3cb357b
RM
73(defvar compilation-last-buffer nil
74 "The buffer in which the last compilation was started,
75or which was used by the last \\[next-error] or \\[compile-goto-error].")
55dfd2c4 76
ebff767c
RM
77(defvar compilation-in-progress nil
78 "List of compilation processes now running.")
79(or (assq 'compilation-in-progress minor-mode-alist)
80 (setq minor-mode-alist (cons '(compilation-in-progress " Compiling")
81 minor-mode-alist)))
82
d3cb357b
RM
83(defvar compilation-parsing-end nil
84 "Position of end of buffer when last error messages were parsed.")
85
86(defvar compilation-error-message "No more errors"
87 "Message to print when no more matches for `compilation-error-regexp-alist'
88are found.")
89
90(defvar compilation-error-regexp-alist
91 '(
92 ;; 4.3BSD grep, cc, lint pass 1:
93 ;; /usr/src/foo/foo.c(8): warning: w may be used before set
94 ;; or GNU utilities
95 ;; foo.c:8: error message
96 ("^\\([^:( \t\n]+\\)[:( \t]+\\([0-9]+\\)[:) \t]" 1 2)
97 ;; 4.3BSD lint pass 2
98 ;; strcmp: variable # of args. llib-lc(359) :: /usr/src/foo/foo.c(8)
daa37602 99 ("[ \t:]+\\([^:( \t\n]+\\)[ \t]*[:(]*(+[ \t]*\\([0-9]+\\))[:) \t]*$" 1 2)
d3cb357b
RM
100 ;; 4.3BSD lint pass 3
101 ;; bloofle defined( /users/wolfgang/foo.c(4) ), but never used
daa37602
JB
102 ;; This used to be
103 ;; ("[ \t(]+\\([^:( \t\n]+\\)[:( \t]+\\([0-9]+\\)[:) \t]+" 1 2)
104 ;; which is regexp Impressionism - it matches almost anything!
105 ("([ \t]*\\([^:( \t\n]+\\)[ \t]*[:(][ \t]*\\([0-9]+\\))" 1 2)
d3cb357b 106 ;; Line 45 of "foo.c": bloofel undefined (who does this?)
daa37602 107 ("^[Ll]ine[ \t]+\\([0-9]+\\)[ \t]+of[ \t]+\"\\([^\"\n]+\\)\":" 2 1)
d3cb357b
RM
108 ;; Apollo cc, 4.3BSD fc
109 ;; "foo.f", line 3: Error: syntax error near end of statement
daa37602 110 ("^\"\\([^\"\n]+\\)\", line \\([0-9]+\\):" 1 2)
d3cb357b
RM
111 ;; HP-UX 7.0 fc
112 ;; foo.f :16 some horrible error message
daa37602 113 ("^\\([^ \t\n:]+\\)[ \t]*:\\([0-9]+\\)" 1 2)
d3cb357b
RM
114 ;; IBM AIX PS/2 C version 1.1
115 ;; ****** Error number 140 in line 8 of file errors.c ******
daa37602 116 ("in line \\([0-9]+\\) of file \\([^ \n]+[^. \n]\\)\\.? " 2 1)
d3cb357b
RM
117 ;; IBM AIX lint is too painful to do right this way. File name
118 ;; prefixes entire sections rather than being on each line.
119 )
120 "Alist (REGEXP FILE-IDX LINE-IDX) of regular expressions to match errors in
121compilation. If REGEXP matches, the FILE-IDX'th subexpression gives the file
122name, and the LINE-IDX'th subexpression gives the line number.")
55dfd2c4 123
7c163413 124;;;###autoload
d3cb357b 125(defvar compilation-search-path '(nil)
7c163413 126 "*List of directories to search for source files named in error messages.
d3cb357b
RM
127Elements should be directory names, not file names of directories.
128nil as an element means to try the default directory.")
55dfd2c4
RS
129
130(defvar compile-command "make -k "
131 "Last shell command used to do a compilation; default for next compilation.
132
133Sometimes it is useful for files to supply local values for this variable.
134You might also use mode hooks to specify it in certain modes, like this:
135
136 (setq c-mode-hook
137 '(lambda () (or (file-exists-p \"makefile\") (file-exists-p \"Makefile\")
138 (progn (make-local-variable 'compile-command)
139 (setq compile-command
140 (concat \"make -k \"
141 buffer-file-name))))))")
142
d3cb357b
RM
143;;;###autoload
144(defvar grep-command "grep -n "
145 "Last shell command used to do a grep search; default for next search.
146Typically \"grep -n\" or \"egrep -n\".
147\(The \"-n\" option tells grep to output line numbers.)")
148
149(defconst compilation-enter-directory-regexp
daa37602 150 ": Entering directory `\\(.*\\)'$"
d3cb357b 151 "Regular expression for a line in the compilation log that
daa37602 152changes the current directory. This must contain one \\(, \\) pair
d3cb357b
RM
153around the directory name.
154
155The default value matches lines printed by the `-w' option of GNU Make.")
156
157(defconst compilation-leave-directory-regexp
daa37602 158 ": Leaving directory `\\(.*\\)'$"
d3cb357b
RM
159 "Regular expression for a line in the compilation log that
160changes the current directory to a previous value. This may
daa37602 161contain one \\(, \\) pair around the name of the directory
d3cb357b
RM
162being moved from. If it does not, the last directory entered
163\(by a line matching `compilation-enter-directory-regexp'\) is assumed.
164
165The default value matches lines printed by the `-w' option of GNU Make.")
166
167(defvar compilation-directory-stack nil
168 "Stack of directories entered by lines matching
169\`compilation-enter-directory-regexp' and not yet left by lines matching
170\`compilation-leave-directory-regexp'. The head element is the directory
171the compilation was started in.")
172
173;;;###autoload
55dfd2c4
RS
174(defun compile (command)
175 "Compile the program including the current buffer. Default: run `make'.
176Runs COMMAND, a shell command, in a separate process asynchronously
177with output going to the buffer `*compilation*'.
d3cb357b 178
55dfd2c4
RS
179You can then use the command \\[next-error] to find the next error message
180and move to the source code that caused it.
181
182To run more than one compilation at once, start one and rename the
d3cb357b
RM
183\`*compilation*' buffer to some other name with \\[rename-buffer].
184Then start the next one.
185
186The name used for the buffer is actually whatever is returned by
187the function in `compilation-buffer-name-function', so you can set that
188to a function that generates a unique name."
55dfd2c4
RS
189 (interactive (list (read-string "Compile command: " compile-command)))
190 (setq compile-command command)
191 (save-some-buffers nil nil)
d3cb357b 192 (compile-internal compile-command "No more errors"))
55dfd2c4 193
d3cb357b 194;;;###autoload
55dfd2c4
RS
195(defun grep (command-args)
196 "Run grep, with user-specified args, and collect output in a buffer.
197While grep runs asynchronously, you can use the \\[next-error] command
d3cb357b
RM
198to find the text that grep hits refer to.
199
200The variable `grep-command' holds the last grep command run,
201and is the default for future runs. The command should use the `-n'
202flag, so that line numbers are displayed for each match.
203What the user enters in response to the prompt for grep args is
204appended to everything up to and including the `-n' in `grep-command'."
55dfd2c4
RS
205 (interactive
206 (list (read-string (concat "Run "
207 (substring grep-command 0
208 (string-match "[\t ]+" grep-command))
209 " (with args): ")
210 (progn
211 (string-match "-n[\t ]+" grep-command)
212 (substring grep-command (match-end 0))))))
213 ;; why a redundant string-match? It might not be interactive ...
214 (setq grep-command (concat (substring grep-command 0
215 (progn
216 (string-match "-n" grep-command)
217 (match-end 0)))
218 " " command-args))
219 (compile-internal (concat grep-command " /dev/null")
220 "No more grep hits" "grep"))
221
222(defun compile-internal (command error-message
d3cb357b
RM
223 &optional name-of-mode parser regexp-alist
224 name-function)
55dfd2c4
RS
225 "Run compilation command COMMAND (low level interface).
226ERROR-MESSAGE is a string to print if the user asks to see another error
227and there are no more errors. Third argument NAME-OF-MODE is the name
d3cb357b
RM
228to display as the major mode in the compilation buffer.
229
230Fourth arg PARSER is the error parser function (nil means the default). Fifth
231arg REGEXP-ALIST is the error message regexp alist to use (nil means the
232default). Sixth arg NAME-FUNCTION is a function called to name the buffer (nil
233means the default). The defaults for these variables are the global values of
234\`compilation-parse-errors-function', `compilation-error-regexp-alist', and
235\`compilation-buffer-name-function', respectively."
236 (let (outbuf)
55dfd2c4 237 (save-excursion
d3cb357b
RM
238 (or name-of-mode
239 (setq name-of-mode "Compilation"))
240 (setq outbuf
241 (get-buffer-create
242 (funcall (or name-function compilation-buffer-name-function
243 (function (lambda (mode)
244 (concat "*" (downcase mode) "*"))))
245 name-of-mode)))
246 (set-buffer outbuf)
247 (let ((comp-proc (get-buffer-process (current-buffer))))
248 (if comp-proc
249 (if (or (not (eq (process-status comp-proc) 'run))
250 (yes-or-no-p
251 "A compilation process is running; kill it? "))
252 (condition-case ()
253 (progn
254 (interrupt-process comp-proc)
255 (sit-for 1)
256 (delete-process comp-proc))
257 (error nil))
258 (error "Cannot have two processes in `%s' at once"
259 (buffer-name))
260 )))
261 ;; In case the compilation buffer is current, make sure we get the global
262 ;; values of compilation-error-regexp-alist, etc.
263 (kill-all-local-variables))
264 (let ((regexp-alist (or regexp-alist compilation-error-regexp-alist))
265 (parser (or parser compilation-parse-errors-function))
266 (thisdir default-directory)
267 outwin)
268 (save-excursion
269 ;; Clear out the compilation buffer and make it writable.
270 ;; Change its default-directory to the directory where the compilation
271 ;; will happen, and insert a `cd' command to indicate this.
272 (set-buffer outbuf)
273 (setq buffer-read-only nil)
274 (erase-buffer)
275 (setq default-directory thisdir)
276 (insert "cd " thisdir "\n" command "\n")
277 (set-buffer-modified-p nil))
278 ;; If we're already in the compilation buffer, go to the end
279 ;; of the buffer, so point will track the compilation output.
280 (if (eq outbuf (current-buffer))
281 (goto-char (point-max)))
282 ;; Pop up the compilation buffer.
283 (setq outwin (display-buffer outbuf))
55dfd2c4 284 (set-buffer outbuf)
55dfd2c4 285 (compilation-mode)
fad160d5 286 (buffer-disable-undo (current-buffer))
e5d77022 287 (setq buffer-read-only t)
d3cb357b
RM
288 (set (make-local-variable 'compilation-parse-errors-function) parser)
289 (set (make-local-variable 'compilation-error-message) error-message)
290 (set (make-local-variable 'compilation-error-regexp-alist) regexp-alist)
291 (setq default-directory thisdir
292 compilation-directory-stack (list default-directory))
55dfd2c4 293 (set-window-start outwin (point-min))
d3cb357b 294 (setq mode-name name-of-mode)
55dfd2c4 295 (or (eq outwin (selected-window))
d3cb357b
RM
296 (set-window-point outwin (point-min)))
297 (and compilation-window-height
f98955ea 298 (= (window-width outwin) (frame-width))
d3cb357b
RM
299 (let ((w (selected-window)))
300 (unwind-protect
301 (progn
302 (select-window outwin)
303 (enlarge-window (- compilation-window-height
304 (window-height))))
305 (select-window w))))
306 ;; Start the compilation.
ebff767c
RM
307 (let ((proc (start-process-shell-command (downcase mode-name)
308 outbuf
309 command)))
310 (set-process-sentinel proc 'compilation-sentinel)
311 (setq compilation-in-progress (cons proc compilation-in-progress))))
d3cb357b
RM
312 ;; Make it so the next C-x ` will use this buffer.
313 (setq compilation-last-buffer outbuf)))
55dfd2c4
RS
314
315(defvar compilation-mode-map
316 (let ((map (make-sparse-keymap)))
317 (define-key map "\C-c\C-c" 'compile-goto-error)
d3cb357b 318 (define-key map "\C-c\C-k" 'kill-compilation)
55dfd2c4
RS
319 map)
320 "Keymap for compilation log buffers.")
321
322(defun compilation-mode ()
323 "Major mode for compilation log buffers.
324\\<compilation-mode-map>To visit the source for a line-numbered error,
d3cb357b 325move point to the error message line and type \\[compile-goto-error].
7c163413
RM
326To kill the compilation, type \\[kill-compilation].
327
328Runs `compilation-mode-hook' with `run-hooks' (which see)."
55dfd2c4
RS
329 (interactive)
330 (fundamental-mode)
331 (use-local-map compilation-mode-map)
55dfd2c4
RS
332 (setq major-mode 'compilation-mode)
333 (setq mode-name "Compilation")
d3cb357b
RM
334 ;; Make buffer's mode line show process state
335 (setq mode-line-process '(": %s"))
336 (set (make-local-variable 'compilation-error-list) nil)
337 (set (make-local-variable 'compilation-old-error-list) nil)
338 (set (make-local-variable 'compilation-parsing-end) 1)
339 (set (make-local-variable 'compilation-directory-stack) nil)
7c163413
RM
340 (setq compilation-last-buffer (current-buffer))
341 (run-hooks 'compilation-mode-hook))
55dfd2c4
RS
342
343;; Called when compilation process changes state.
55dfd2c4 344(defun compilation-sentinel (proc msg)
d3cb357b
RM
345 "Sentinel for compilation buffers."
346 (let ((buffer (process-buffer proc)))
ebff767c
RM
347 (if (memq (process-status proc) '(signal exit))
348 (progn
349 (if (null (buffer-name buffer))
350 ;; buffer killed
351 (set-process-buffer proc nil)
352 (let ((obuf (current-buffer))
353 omax opoint)
354 ;; save-excursion isn't the right thing if
355 ;; process-buffer is current-buffer
356 (unwind-protect
357 (progn
358 ;; Write something in the compilation buffer
359 ;; and hack its mode line.
360 (set-buffer buffer)
361 (setq buffer-read-only nil)
362 (setq omax (point-max)
363 opoint (point))
364 (goto-char omax)
365 ;; Record where we put the message, so we can ignore it
366 ;; later on.
367 (insert ?\n mode-name " " msg)
368 (forward-char -1)
369 (insert " at " (substring (current-time-string) 0 19))
370 (forward-char 1)
371 (setq mode-line-process
372 (concat ": "
373 (symbol-name (process-status proc))))
374 ;; Since the buffer and mode line will show that the
375 ;; process is dead, we can delete it now. Otherwise it
376 ;; will stay around until M-x list-processes.
377 (delete-process proc)
378 ;; Force mode line redisplay soon.
379 (set-buffer-modified-p (buffer-modified-p))
380 (setq buffer-read-only t) ;I think is this wrong --roland
381 (if (and opoint (< opoint omax))
382 (goto-char opoint)))
383 (set-buffer obuf))
384 (if compilation-finish-function
385 (funcall compilation-finish-function buffer msg))
386 ))
387 (setq compilation-in-progress (delq proc compilation-in-progress))
388 ))))
55dfd2c4
RS
389
390(defun kill-compilation ()
391 "Kill the process made by the \\[compile] command."
392 (interactive)
d3cb357b 393 (let ((buffer (compilation-find-buffer)))
55dfd2c4 394 (if (get-buffer-process buffer)
d3cb357b
RM
395 (interrupt-process (get-buffer-process buffer))
396 (error "The compilation process is not running."))))
397
55dfd2c4 398
d3cb357b
RM
399;; Parse any new errors in the compilation buffer,
400;; or reparse from the beginning if the user has asked for that.
55dfd2c4 401(defun compile-reinitialize-errors (argp)
d3cb357b
RM
402 (save-excursion
403 (set-buffer compilation-last-buffer)
404 ;; If we are out of errors, or if user says "reparse",
405 ;; discard the info we have, to force reparsing.
406 (if (or (eq compilation-error-list t)
407 (consp argp))
408 (progn (compilation-forget-errors)
409 (setq compilation-parsing-end 1)))
410 (if compilation-error-list
411 ;; Since compilation-error-list is non-nil, it points to a specific
412 ;; error the user wanted. So don't move it around.
413 nil
414 (switch-to-buffer compilation-last-buffer)
55dfd2c4
RS
415 (set-buffer-modified-p nil)
416 (let ((at-start (= compilation-parsing-end 1)))
d3cb357b 417 (funcall compilation-parse-errors-function)
55dfd2c4
RS
418 ;; Remember the entire list for compilation-forget-errors.
419 ;; If this is an incremental parse, append to previous list.
420 (if at-start
421 (setq compilation-old-error-list compilation-error-list)
422 (setq compilation-old-error-list
423 (nconc compilation-old-error-list compilation-error-list)))))))
424
425(defun compile-goto-error (&optional argp)
426 "Visit the source for the error message point is on.
427Use this command in a compilation log buffer.
428C-u as a prefix arg means to reparse the buffer's error messages first;
429other kinds of prefix arguments are ignored."
430 (interactive "P")
d3cb357b
RM
431 (or (compilation-buffer-p (current-buffer))
432 (error "Not in a compilation buffer."))
433 (setq compilation-last-buffer (current-buffer))
55dfd2c4
RS
434 (compile-reinitialize-errors argp)
435 (save-excursion
436 (beginning-of-line)
d3cb357b
RM
437 ;; Move compilation-error-list to the elt of
438 ;; compilation-old-error-list whose car is the error we want.
55dfd2c4 439 (setq compilation-error-list
d3cb357b
RM
440 (memq (let (elt)
441 (while (not (or (setq elt (assoc (point-marker)
442 compilation-old-error-list))
443 (eobp)))
444 ;; This line doesn't contain an error.
445 ;; Move forward a line and look again.
446 (forward-line 1))
447 elt)
55dfd2c4
RS
448 compilation-old-error-list)))
449 ;; Move to another window, so that next-error's window changes
450 ;; result in the desired setup.
451 (or (one-window-p)
452 (other-window -1))
453 (next-error 1))
454
d3cb357b
RM
455(defun compilation-buffer-p (buffer)
456 (assq 'compilation-error-list (buffer-local-variables buffer)))
457
458;; Return a compilation buffer.
459;; If the current buffer is a compilation buffer, return it.
460;; If compilation-last-buffer is set to a live buffer, use that.
461;; Otherwise, look for a compilation buffer and signal an error
462;; if there are none.
4746118a
JB
463(defun compilation-find-buffer (&optional other-buffer)
464 (if (and (not other-buffer)
465 (compilation-buffer-p (current-buffer)))
d3cb357b
RM
466 ;; The current buffer is a compilation buffer.
467 (current-buffer)
4746118a
JB
468 (if (and compilation-last-buffer (buffer-name compilation-last-buffer)
469 (or (not other-buffer) (not (eq compilation-last-buffer
470 (current-buffer)))))
d3cb357b
RM
471 compilation-last-buffer
472 (let ((buffers (buffer-list)))
4746118a
JB
473 (while (and buffers (or (not (compilation-buffer-p (car buffers)))
474 (and other-buffer
475 (eq (car buffers) (current-buffer)))))
d3cb357b
RM
476 (setq buffers (cdr buffers)))
477 (if buffers
478 (car buffers)
4746118a
JB
479 (or (and other-buffer
480 (compilation-buffer-p (current-buffer))
481 ;; The current buffer is a compilation buffer.
482 (progn
483 (if other-buffer
484 (message "This is the only compilation buffer."))
485 (current-buffer)))
486 (error "No compilation started!")))))))
d3cb357b
RM
487
488;;;###autoload
55dfd2c4
RS
489(defun next-error (&optional argp)
490 "Visit next compilation error message and corresponding source code.
491This operates on the output from the \\[compile] command.
492If all preparsed error messages have been processed,
493the error message buffer is checked for new ones.
494
495A prefix arg specifies how many error messages to move;
496negative means move back to previous error messages.
497Just C-u as a prefix means reparse the error message buffer
498and start at the first error.
499
500\\[next-error] normally applies to the most recent compilation started,
501but as long as you are in the middle of parsing errors from one compilation
502output buffer, you stay with that compilation output buffer.
503
504Use \\[next-error] in a compilation output buffer to switch to
505processing errors from that compilation.
506
d3cb357b
RM
507See variables `compilation-parse-errors-function' and
508\`compilation-error-regexp-alist' for customization ideas."
55dfd2c4 509 (interactive "P")
d3cb357b 510 (setq compilation-last-buffer (compilation-find-buffer))
55dfd2c4 511 (compile-reinitialize-errors argp)
d3cb357b
RM
512 ;; Make ARGP nil if the prefix arg was just C-u,
513 ;; since that means to reparse the errors, which the
514 ;; compile-reinitialize-errors call just did.
515 ;; Now we are only interested in a numeric prefix arg.
55dfd2c4
RS
516 (if (consp argp)
517 (setq argp nil))
d3cb357b
RM
518 (let (next-errors next-error)
519 (save-excursion
520 (set-buffer compilation-last-buffer)
521 (setq next-errors (nthcdr (+ (- (length compilation-old-error-list)
522 (length compilation-error-list)
523 1)
524 (prefix-numeric-value argp))
525 compilation-old-error-list)
526 next-error (car next-errors))
527 (while
55dfd2c4 528 (progn
d3cb357b
RM
529 (if (null next-error)
530 (progn
531 (if argp (if (> (prefix-numeric-value argp) 0)
532 (error "Moved past last error")
533 (error "Moved back past first error")))
534 (compilation-forget-errors)
535 (error (concat compilation-error-message
536 (and (get-buffer-process (current-buffer))
537 (eq (process-status
538 (get-buffer-process
539 (current-buffer)))
540 'run)
541 " yet"))))
542 (setq compilation-error-list (cdr next-errors))
543 (if (null (cdr next-error))
544 ;; This error is boring. Go to the next.
545 t
546 (or (markerp (cdr next-error))
547 ;; This error has a filename/lineno pair.
548 ;; Find the file and turn it into a marker.
549 (let* ((fileinfo (car (cdr next-error)))
550 (buffer (compilation-find-file (cdr fileinfo)
551 (car fileinfo)
552 (car next-error))))
553 (if (null buffer)
554 ;; We can't find this error's file.
555 ;; Remove all errors in the same file.
556 (progn
557 (setq next-errors compilation-old-error-list)
558 (while next-errors
559 (and (consp (cdr (car next-errors)))
560 (equal (car (cdr (car next-errors)))
561 fileinfo)
562 (progn
563 (set-marker (car (car next-errors)) nil)
564 (setcdr (car next-errors) nil)))
565 (setq next-errors (cdr next-errors)))
566 ;; Look for the next error.
567 t)
568 ;; We found the file. Get a marker for this error.
569 (set-buffer buffer)
570 (save-excursion
571 (save-restriction
572 (widen)
573 (let ((errors compilation-old-error-list)
574 (last-line (cdr (cdr next-error))))
575 (goto-line last-line)
576 (beginning-of-line)
577 (setcdr next-error (point-marker))
578 ;; Make all the other error messages referring
579 ;; to the same file have markers into the buffer.
580 (while errors
581 (and (consp (cdr (car errors)))
582 (equal (car (cdr (car errors))) fileinfo)
583 (let ((this (cdr (cdr (car errors))))
584 (lines (- (cdr (cdr (car errors)))
585 last-line)))
586 (if (eq selective-display t)
587 (if (< lines 0)
588 (re-search-backward "[\n\C-m]"
589 nil 'end
590 (- lines))
591 (re-search-forward "[\n\C-m]"
592 nil 'end
593 lines))
594 (forward-line lines))
595 (setq last-line this)
596 (setcdr (car errors) (point-marker))))
597 (setq errors (cdr errors)))))))))
598 ;; If we didn't get a marker for this error,
599 ;; go on to the next one.
600 (not (markerp (cdr next-error))))))
601 (setq next-errors compilation-error-list
602 next-error (car next-errors))))
603
604 ;; Skip over multiple error messages for the same source location,
605 ;; so the next C-x ` won't go to an error in the same place.
606 (while (and compilation-error-list
607 (equal (cdr (car compilation-error-list)) (cdr next-error)))
608 (setq compilation-error-list (cdr compilation-error-list)))
609
610 ;; We now have a marker for the position of the error.
611 (switch-to-buffer (marker-buffer (cdr next-error)))
612 (goto-char (cdr next-error))
613 ;; If narrowing got in the way of
614 ;; going to the right place, widen.
615 (or (= (point) (marker-position (cdr next-error)))
616 (progn
617 (widen)
618 (goto-char (cdr next-error))))
619
55dfd2c4
RS
620 ;; Show compilation buffer in other window, scrolled to this error.
621 (let* ((pop-up-windows t)
622 (w (display-buffer (marker-buffer (car next-error)))))
623 (set-window-point w (car next-error))
d3cb357b
RM
624 (set-window-start w (car next-error)))))
625
626;;;###autoload
627(define-key ctl-x-map "`" 'next-error)
628
629;; Find a buffer for file FILENAME.
630;; Search the directories in compilation-search-path.
631;; A nil in compilation-search-path means to try the
632;; current directory, which is passed in DIR.
633;; If FILENAME is not found at all, ask the user where to find it.
634;; Pop up the buffer containing MARKER and scroll to MARKER if we ask the user.
635(defun compilation-find-file (filename dir marker)
636 (let ((dirs compilation-search-path)
637 result name)
638 (while (and dirs (null result))
639 (setq name (expand-file-name filename (or (car dirs) dir))
640 result (and (file-exists-p name)
641 (find-file-noselect name))
642 dirs (cdr dirs)))
643 (or result
644 ;; The file doesn't exist.
645 ;; Ask the user where to find it.
646 ;; If he hits C-g, then the next time he does
647 ;; next-error, he'll skip past it.
648 (progn
649 (let* ((pop-up-windows t)
650 (w (display-buffer (marker-buffer marker))))
651 (set-window-point w marker)
652 (set-window-start w marker))
653 (setq name
654 (expand-file-name
655 (read-file-name
656 (format "Find this error in: (default %s) "
657 filename) dir filename t)))
658 (if (file-directory-p name)
659 (setq name (concat (file-name-as-directory name) filename)))
660 (if (file-exists-p name)
661 (find-file-noselect name))))))
662
663;; Set compilation-error-list to nil, and unchain the markers that point to the
664;; error messages and their text, so that they no longer slow down gap motion.
665;; This would happen anyway at the next garbage collection, but it is better to
666;; do it the right away.
55dfd2c4
RS
667(defun compilation-forget-errors ()
668 (while compilation-old-error-list
669 (let ((next-error (car compilation-old-error-list)))
670 (set-marker (car next-error) nil)
d3cb357b
RM
671 (if (markerp (cdr next-error))
672 (set-marker (cdr next-error) nil)))
55dfd2c4 673 (setq compilation-old-error-list (cdr compilation-old-error-list)))
d3cb357b
RM
674 (setq compilation-error-list nil)
675 (while (cdr compilation-directory-stack)
676 (setq compilation-directory-stack (cdr compilation-directory-stack))))
677
678
679(defun count-regexp-groupings (regexp)
680 "Return the number of \\( ... \\) groupings in REGEXP (a string)."
681 (let ((groupings 0)
682 (len (length regexp))
683 (i 0)
684 c)
685 (while (< i len)
686 (setq c (aref regexp i)
687 i (1+ i))
688 (cond ((= c ?\[)
689 ;; Find the end of this [...].
690 (while (and (< i len)
691 (not (= (aref regexp i) ?\])))
692 (setq i (1+ i))))
693 ((= c ?\\)
694 (if (< i len)
695 (progn
696 (setq c (aref regexp i)
697 i (1+ i))
698 (if (= c ?\))
699 ;; We found the end of a grouping,
700 ;; so bump our counter.
701 (setq groupings (1+ groupings))))))))
702 groupings))
55dfd2c4
RS
703
704(defun compilation-parse-errors ()
705 "Parse the current buffer as grep, cc or lint error messages.
d3cb357b 706See variable `compilation-parse-errors-function' for the interface it uses."
55dfd2c4
RS
707 (setq compilation-error-list nil)
708 (message "Parsing error messages...")
709 (let (text-buffer
d3cb357b
RM
710 regexp enter-group leave-group error-group
711 alist subexpr error-regexp-groups)
712
55dfd2c4
RS
713 ;; Don't reparse messages already seen at last parse.
714 (goto-char compilation-parsing-end)
715 ;; Don't parse the first two lines as error messages.
716 ;; This matters for grep.
717 (if (bobp)
718 (forward-line 2))
d3cb357b
RM
719
720 ;; Compile all the regexps we want to search for into one.
721 (setq regexp (concat "\\(" compilation-enter-directory-regexp "\\)\\|"
722 "\\(" compilation-leave-directory-regexp "\\)\\|"
723 "\\(" (mapconcat (function
724 (lambda (elt)
725 (concat "\\(" (car elt) "\\)")))
726 compilation-error-regexp-alist
727 "\\|") "\\)"))
728
729 ;; Find out how many \(...\) groupings are in each of the regexps, and set
730 ;; *-GROUP to the grouping containing each constituent regexp (whose
731 ;; subgroups will come immediately thereafter) of the big regexp we have
732 ;; just constructed.
733 (setq enter-group 1
734 leave-group (+ enter-group
735 (count-regexp-groupings
736 compilation-enter-directory-regexp)
737 1)
738 error-group (+ leave-group
739 (count-regexp-groupings
740 compilation-leave-directory-regexp)
741 1))
742
743 ;; Compile an alist (IDX FILE LINE), where IDX is the number of the
744 ;; subexpression for an entire error-regexp, and FILE and LINE are the
745 ;; numbers for the subexpressions giving the file name and line number.
746 (setq alist compilation-error-regexp-alist
747 subexpr (1+ error-group))
748 (while alist
749 (setq error-regexp-groups (cons (list subexpr
750 (+ subexpr (nth 1 (car alist)))
751 (+ subexpr (nth 2 (car alist))))
752 error-regexp-groups))
753 (setq subexpr (+ subexpr 1 (count-regexp-groupings (car (car alist)))))
754 (setq alist (cdr alist)))
755
756 (while (re-search-forward regexp nil t)
757 ;; Figure out which constituent regexp matched.
758 (cond ((match-beginning enter-group)
759 ;; The match was the enter-directory regexp.
760 (let ((dir
761 (file-name-as-directory
762 (expand-file-name
763 (buffer-substring (match-beginning (+ enter-group 1))
764 (match-end (+ enter-group 1)))))))
765 (setq compilation-directory-stack
766 (cons dir compilation-directory-stack))
767 (and (file-directory-p dir)
768 (setq default-directory dir))))
769
770 ((match-beginning leave-group)
771 ;; The match was the leave-directory regexp.
772 (let ((beg (match-beginning (+ leave-group 1)))
773 (stack compilation-directory-stack))
774 (if beg
775 (let ((dir
776 (file-name-as-directory
777 (expand-file-name
778 (buffer-substring beg
779 (match-end (+ leave-group
780 1)))))))
781 (while (and stack
782 (not (string-equal (car stack) dir)))
783 (setq stack (cdr stack)))))
784 (setq compilation-directory-stack (cdr stack))
785 (setq stack (car compilation-directory-stack))
786 (if stack
787 (setq default-directory stack))
788 ))
789
790 ((match-beginning error-group)
791 ;; The match was the composite error regexp.
792 ;; Find out which individual regexp matched.
793 (setq alist error-regexp-groups)
794 (while (and alist
795 (null (match-beginning (car (car alist)))))
796 (setq alist (cdr alist)))
797 (if alist
798 (setq alist (car alist))
799 (error "Impossible regexp match!"))
800
801 ;; Extract the file name and line number from the error message.
802 (let ((filename
803 (cons default-directory
804 (buffer-substring (match-beginning (nth 1 alist))
805 (match-end (nth 1 alist)))))
806 (linenum (save-restriction
807 (narrow-to-region
808 (match-beginning (nth 2 alist))
809 (match-end (nth 2 alist)))
810 (goto-char (point-min))
811 (if (looking-at "[0-9]")
812 (read (current-buffer))))))
813 ;; Locate the erring file and line.
814 ;; Cons a new elt onto compilation-error-list,
815 ;; giving a marker for the current compilation buffer
816 ;; location, and the file and line number of the error.
817 (save-excursion
818 (beginning-of-line 1)
819 (setq compilation-error-list
820 (cons (cons (point-marker)
821 (cons filename linenum))
822 compilation-error-list)))))
823 (t
824 (error "Impossible regexp match!"))))
55dfd2c4
RS
825 (setq compilation-parsing-end (point-max)))
826 (message "Parsing error messages...done")
827 (setq compilation-error-list (nreverse compilation-error-list)))
828
55dfd2c4 829(define-key ctl-x-map "`" 'next-error)
4746118a
JB
830
831(provide 'compile)
fad160d5
ER
832
833;;; compile.el ends here