(rmail-last-rmail-file): Initialize to a file name.
[bpt/emacs.git] / lisp / progmodes / compile.el
1 ;;; compile.el --- run compiler as inferior of Emacs, parse error messages.
2
3 ;; Copyright (C) 1985, 86, 87, 93 Free Software Foundation, Inc.
4
5 ;; Author: Roland McGrath <roland@prep.ai.mit.edu>
6 ;; Maintainer: FSF
7 ;; Keywords: tools, processes
8
9 ;; This file is part of GNU Emacs.
10
11 ;; GNU Emacs is free software; you can redistribute it and/or modify
12 ;; it under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation; either version 2, or (at your option)
14 ;; any later version.
15
16 ;; GNU Emacs is distributed in the hope that it will be useful,
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 ;; GNU General Public License for more details.
20
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs; see the file COPYING. If not, write to
23 ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
24
25 ;;; Commentary:
26
27 ;; This package provides the compile and grep facilities documented in
28 ;; the Emacs user's manual.
29
30 ;;; Code:
31
32 ;;;###autoload
33 (defvar compilation-mode-hook nil
34 "*List of hook functions run by `compilation-mode' (see `run-hooks').")
35
36 ;;;###autoload
37 (defconst compilation-window-height nil
38 "*Number of lines in a compilation window. If nil, use Emacs default.")
39
40 (defvar compilation-error-list nil
41 "List of error message descriptors for visiting erring functions.
42 Each error descriptor is a cons (or nil). Its car is a marker pointing to
43 an error message. If its cdr is a marker, it points to the text of the
44 line the message is about. If its cdr is a cons, that cons's car is a cons
45 \(DIRECTORY . FILE\), specifying the file the message is about, and its cdr
46 is the number of the line the message is about. Or its cdr may be nil if
47 that error is not interesting.
48
49 The value may be t instead of a list; this means that the buffer of
50 error messages should be reparsed the next time the list of errors is wanted.
51
52 Some other commands (like `diff') use this list to control the error
53 message tracking facilites; if you change its structure, you should make
54 sure you also change those packages. Perhaps it is better not to change
55 it at all.")
56
57 (defvar compilation-old-error-list nil
58 "Value of `compilation-error-list' after errors were parsed.")
59
60 (defvar compilation-parse-errors-function 'compilation-parse-errors
61 "Function to call to parse error messages from a compilation.
62 It takes args LIMIT-SEARCH and FIND-AT-LEAST.
63 If LIMIT-SEARCH is non-nil, don't bother parsing past that location.
64 If FIND-AT-LEAST is non-nil, don't bother parsing after finding that
65 many new erros.
66 It should read in the source files which have errors and set
67 `compilation-error-list' to a list with an element for each error message
68 found. See that variable for more info.")
69
70 ;;;###autoload
71 (defvar compilation-buffer-name-function nil
72 "Function to compute the name of a compilation buffer.
73 The function receives one argument, the name of the major mode of the
74 compilation buffer. It should return a string.
75 nil means compute the name with `(concat \"*\" (downcase major-mode) \"*\")'.")
76
77 ;;;###autoload
78 (defvar compilation-finish-function nil
79 "*Function to call when a compilation process finishes.
80 It is called with two arguments: the compilation buffer, and a string
81 describing how the process finished.")
82
83 (defvar compilation-last-buffer nil
84 "The most recent compilation buffer.
85 A buffer becomes most recent when its compilation is started
86 or when it is used with \\[next-error] or \\[compile-goto-error].")
87
88 (defvar compilation-in-progress nil
89 "List of compilation processes now running.")
90 (or (assq 'compilation-in-progress minor-mode-alist)
91 (setq minor-mode-alist (cons '(compilation-in-progress " Compiling")
92 minor-mode-alist)))
93
94 (defvar compilation-parsing-end nil
95 "Position of end of buffer when last error messages were parsed.")
96
97 (defvar compilation-error-message "No more errors"
98 "Message to print when no more matches are found.")
99
100 (defvar compilation-num-errors-found)
101
102 (defvar compilation-error-regexp-alist
103 '(
104 ;; NOTE! This first one is repeated in grep-regexp-alist, below.
105
106 ;; 4.3BSD grep, cc, lint pass 1:
107 ;; /usr/src/foo/foo.c(8): warning: w may be used before set
108 ;; or GNU utilities:
109 ;; foo.c:8: error message
110 ;; or HP-UX 7.0 fc:
111 ;; foo.f :16 some horrible error message
112 ;;
113 ;; We'll insist that the number be followed by a colon or closing
114 ;; paren, because otherwise this matches just about anything
115 ;; containing a number with spaces around it.
116 ("\n\\([^:( \t\n]+\\)[:(][ \t]*\\([0-9]+\\)[:) \t]" 1 2)
117
118 ;; 4.3BSD lint pass 2
119 ;; strcmp: variable # of args. llib-lc(359) :: /usr/src/foo/foo.c(8)
120 ("[ \t:]\\([^:( \t\n]+\\)[:(](+[ \t]*\\([0-9]+\\))[:) \t]*$" 1 2)
121
122 ;; 4.3BSD lint pass 3
123 ;; bloofle defined( /users/wolfgang/foo.c(4) ), but never used
124 ;; This used to be
125 ;; ("[ \t(]+\\([^:( \t\n]+\\)[:( \t]+\\([0-9]+\\)[:) \t]+" 1 2)
126 ;; which is regexp Impressionism - it matches almost anything!
127 ("([ \t]*\\([^:( \t\n]+\\)[:(][ \t]*\\([0-9]+\\))" 1 2)
128
129 ;; Ultrix 3.0 f77:
130 ;; Error on line 3 of t.f: Execution error unclassifiable statement
131 ;; Unknown who does this:
132 ;; Line 45 of "foo.c": bloofel undefined
133 ("\n\\(Error on \\)?[Ll]ine[ \t]+\\([0-9]+\\)[ \t]+\
134 of[ \t]+\"?\\([^\"\n]+\\)\"?:" 3 2)
135
136 ;; Apollo cc, 4.3BSD fc:
137 ;; "foo.f", line 3: Error: syntax error near end of statement
138 ;; IBM RS6000:
139 ;; "vvouch.c", line 19.5: 1506-046 (S) Syntax error.
140 ("\"\\([^,\" \n\t]+\\)\", line \\([0-9]+\\)[:.]" 1 2)
141
142 ;; MIPS RISC CC - the one distributed with Ultrix:
143 ;; ccom: Error: foo.c, line 2: syntax error
144 ("rror: \\([^,\" \n\t]+\\), line \\([0-9]+\\):" 1 2)
145
146 ;; IBM AIX PS/2 C version 1.1:
147 ;; ****** Error number 140 in line 8 of file errors.c ******
148 ("in line \\([0-9]+\\) of file \\([^ \n]+[^. \n]\\)\\.? " 2 1)
149 ;; IBM AIX lint is too painful to do right this way. File name
150 ;; prefixes entire sections rather than being on each line.
151
152 )
153 "Alist that specifies how to match errors in compiler output.
154 Each element has the form (REGEXP FILE-IDX LINE-IDX).
155 If REGEXP matches, the FILE-IDX'th subexpression gives the file
156 name, and the LINE-IDX'th subexpression gives the line number.")
157
158 (defvar grep-regexp-alist
159 '(("^\\([^:( \t\n]+\\)[:( \t]+\\([0-9]+\\)[:) \t]" 1 2))
160 "Regexp used to match grep hits. See `compilation-error-regexp-alist'.")
161
162 ;;;###autoload
163 (defvar compilation-search-path '(nil)
164 "*List of directories to search for source files named in error messages.
165 Elements should be directory names, not file names of directories.
166 nil as an element means to try the default directory.")
167
168 (defvar compile-command "make -k "
169 "Last shell command used to do a compilation; default for next compilation.
170
171 Sometimes it is useful for files to supply local values for this variable.
172 You might also use mode hooks to specify it in certain modes, like this:
173
174 (setq c-mode-hook
175 '(lambda () (or (file-exists-p \"makefile\") (file-exists-p \"Makefile\")
176 (progn (make-local-variable 'compile-command)
177 (setq compile-command
178 (concat \"make -k \"
179 buffer-file-name))))))")
180
181 (defconst compilation-enter-directory-regexp
182 ": Entering directory `\\(.*\\)'$"
183 "Regular expression matching lines that indicate a new current directory.
184 This must contain one \\(, \\) pair around the directory name.
185
186 The default value matches lines printed by the `-w' option of GNU Make.")
187
188 (defconst compilation-leave-directory-regexp
189 ": Leaving directory `\\(.*\\)'$"
190 "Regular expression matching lines that indicate restoring current directory.
191 This may contain one \\(, \\) pair around the name of the directory
192 being moved from. If it does not, the last directory entered \(by a
193 line matching `compilation-enter-directory-regexp'\) is assumed.
194
195 The default value matches lines printed by the `-w' option of GNU Make.")
196
197 (defvar compilation-directory-stack nil
198 "Stack of previous directories for `compilation-leave-directory-regexp'.
199 The head element is the directory the compilation was started in.")
200
201 ;; History of compile commands.
202 (defvar compile-history nil)
203 ;; History of grep commands.
204 (defvar grep-history nil)
205
206 ;;;###autoload
207 (defun compile (command)
208 "Compile the program including the current buffer. Default: run `make'.
209 Runs COMMAND, a shell command, in a separate process asynchronously
210 with output going to the buffer `*compilation*'.
211
212 You can then use the command \\[next-error] to find the next error message
213 and move to the source code that caused it.
214
215 To run more than one compilation at once, start one and rename the
216 \`*compilation*' buffer to some other name with \\[rename-buffer].
217 Then start the next one.
218
219 The name used for the buffer is actually whatever is returned by
220 the function in `compilation-buffer-name-function', so you can set that
221 to a function that generates a unique name."
222 (interactive (list (read-from-minibuffer "Compile command: "
223 compile-command nil nil
224 '(compile-history . 1))))
225 (setq compile-command command)
226 (save-some-buffers nil nil)
227 (compile-internal compile-command "No more errors"))
228
229 ;;;###autoload
230 (defun grep (command-args)
231 "Run grep, with user-specified args, and collect output in a buffer.
232 While grep runs asynchronously, you can use the \\[next-error] command
233 to find the text that grep hits refer to.
234
235 This command uses a special history list for its arguments, so you can
236 easily repeat a grep command."
237 (interactive
238 (list (read-from-minibuffer "Run grep (like this): "
239 "grep -n " nil nil 'grep-history)))
240 (compile-internal (concat command-args " /dev/null")
241 "No more grep hits" "grep"
242 ;; Give it a simpler regexp to match.
243 nil grep-regexp-alist))
244
245 (defun compile-internal (command error-message
246 &optional name-of-mode parser regexp-alist
247 name-function)
248 "Run compilation command COMMAND (low level interface).
249 ERROR-MESSAGE is a string to print if the user asks to see another error
250 and there are no more errors. Third argument NAME-OF-MODE is the name
251 to display as the major mode in the compilation buffer.
252
253 Fourth arg PARSER is the error parser function (nil means the default). Fifth
254 arg REGEXP-ALIST is the error message regexp alist to use (nil means the
255 default). Sixth arg NAME-FUNCTION is a function called to name the buffer (nil
256 means the default). The defaults for these variables are the global values of
257 \`compilation-parse-errors-function', `compilation-error-regexp-alist', and
258 \`compilation-buffer-name-function', respectively.
259
260 Returns the compilation buffer created."
261 (let (outbuf)
262 (save-excursion
263 (or name-of-mode
264 (setq name-of-mode "Compilation"))
265 (setq outbuf
266 (get-buffer-create
267 (funcall (or name-function compilation-buffer-name-function
268 (function (lambda (mode)
269 (concat "*" (downcase mode) "*"))))
270 name-of-mode)))
271 (set-buffer outbuf)
272 (let ((comp-proc (get-buffer-process (current-buffer))))
273 (if comp-proc
274 (if (or (not (eq (process-status comp-proc) 'run))
275 (yes-or-no-p
276 (format "A %s process is running; kill it? "
277 name-of-mode)))
278 (condition-case ()
279 (progn
280 (interrupt-process comp-proc)
281 (sit-for 1)
282 (delete-process comp-proc))
283 (error nil))
284 (error "Cannot have two processes in `%s' at once"
285 (buffer-name))
286 )))
287 ;; In case the compilation buffer is current, make sure we get the global
288 ;; values of compilation-error-regexp-alist, etc.
289 (kill-all-local-variables))
290 (let ((regexp-alist (or regexp-alist compilation-error-regexp-alist))
291 (parser (or parser compilation-parse-errors-function))
292 (thisdir default-directory)
293 outwin)
294 (save-excursion
295 ;; Clear out the compilation buffer and make it writable.
296 ;; Change its default-directory to the directory where the compilation
297 ;; will happen, and insert a `cd' command to indicate this.
298 (set-buffer outbuf)
299 (setq buffer-read-only nil)
300 (erase-buffer)
301 (setq default-directory thisdir)
302 (insert "cd " thisdir "\n" command "\n")
303 (set-buffer-modified-p nil))
304 ;; If we're already in the compilation buffer, go to the end
305 ;; of the buffer, so point will track the compilation output.
306 (if (eq outbuf (current-buffer))
307 (goto-char (point-max)))
308 ;; Pop up the compilation buffer.
309 (setq outwin (display-buffer outbuf))
310 (save-excursion
311 (set-buffer outbuf)
312 (compilation-mode)
313 (buffer-disable-undo (current-buffer))
314 (setq buffer-read-only t)
315 (set (make-local-variable 'compilation-parse-errors-function) parser)
316 (set (make-local-variable 'compilation-error-message) error-message)
317 (set (make-local-variable 'compilation-error-regexp-alist) regexp-alist)
318 (setq default-directory thisdir
319 compilation-directory-stack (list default-directory))
320 (set-window-start outwin (point-min))
321 (setq mode-name name-of-mode)
322 (or (eq outwin (selected-window))
323 (set-window-point outwin (point-min)))
324 (and compilation-window-height
325 (= (window-width outwin) (frame-width))
326 (let ((w (selected-window)))
327 (unwind-protect
328 (progn
329 (select-window outwin)
330 (enlarge-window (- compilation-window-height
331 (window-height))))
332 (select-window w))))
333 ;; Start the compilation.
334 (let ((proc (start-process-shell-command (downcase mode-name)
335 outbuf
336 command)))
337 (set-process-sentinel proc 'compilation-sentinel)
338 (set-process-filter proc 'compilation-filter)
339 (set-marker (process-mark proc) (point) outbuf)
340 (setq compilation-in-progress (cons proc compilation-in-progress)))))
341 ;; Make it so the next C-x ` will use this buffer.
342 (setq compilation-last-buffer outbuf)))
343
344 (defvar compilation-minor-mode-map
345 (let ((map (make-sparse-keymap)))
346 (define-key map "\C-c\C-c" 'compile-goto-error)
347 (define-key map "\C-c\C-k" 'kill-compilation)
348 (define-key map "\M-n" 'compilation-next-error)
349 (define-key map "\M-p" 'compilation-previous-error)
350 (define-key map "\M-{" 'compilation-previous-file)
351 (define-key map "\M-}" 'compilation-next-file)
352 map)
353 "Keymap for `compilation-minor-mode'.")
354
355 (defvar compilation-mode-map
356 (let ((map (cons 'keymap compilation-minor-mode-map)))
357 (define-key map " " 'scroll-up)
358 (define-key map "\^?" 'scroll-down)
359 map)
360 "Keymap for compilation log buffers.
361 `compilation-minor-mode-map' is a cdr of this.")
362
363 (defun compilation-mode ()
364 "Major mode for compilation log buffers.
365 \\<compilation-mode-map>To visit the source for a line-numbered error,
366 move point to the error message line and type \\[compile-goto-error].
367 To kill the compilation, type \\[kill-compilation].
368
369 Runs `compilation-mode-hook' with `run-hooks' (which see)."
370 (interactive)
371 (fundamental-mode)
372 (use-local-map compilation-mode-map)
373 (setq major-mode 'compilation-mode
374 mode-name "Compilation")
375 (compilation-setup)
376 (run-hooks 'compilation-mode-hook))
377
378 ;; Prepare the buffer for the compilation parsing commands to work.
379 (defun compilation-setup ()
380 ;; Make the buffer's mode line show process state.
381 (setq mode-line-process '(": %s"))
382 (set (make-local-variable 'compilation-error-list) nil)
383 (set (make-local-variable 'compilation-old-error-list) nil)
384 (set (make-local-variable 'compilation-parsing-end) 1)
385 (set (make-local-variable 'compilation-directory-stack) nil)
386 (setq compilation-last-buffer (current-buffer)))
387
388 (defvar compilation-minor-mode nil
389 "Non-nil when in compilation-minor-mode.
390 In this minor mode, all the error-parsing commands of the
391 Compilation major mode are available.")
392
393 (or (assq 'compilation-minor-mode minor-mode-alist)
394 (setq minor-mode-alist (cons '(compilation-minor-mode " Compilation")
395 minor-mode-alist)))
396 (or (assq 'compilation-minor-mode minor-mode-map-alist)
397 (setq minor-mode-map-alist (cons (cons 'compilation-minor-mode
398 compilation-minor-mode-map)
399 minor-mode-map-alist)))
400
401 (defun compilation-minor-mode (&optional arg)
402 "Toggle compilation minor mode.
403 With arg, turn compilation mode on if and only if arg is positive.
404 See `compilation-mode'."
405 (interactive "P")
406 (if (setq compilation-minor-mode (if (null arg)
407 (null compilation-minor-mode)
408 (> (prefix-numeric-value arg) 0)))
409 (compilation-setup)))
410
411 ;; Called when compilation process changes state.
412 (defun compilation-sentinel (proc msg)
413 "Sentinel for compilation buffers."
414 (let ((buffer (process-buffer proc)))
415 (if (memq (process-status proc) '(signal exit))
416 (progn
417 (if (null (buffer-name buffer))
418 ;; buffer killed
419 (set-process-buffer proc nil)
420 (let ((obuf (current-buffer))
421 omax opoint)
422 ;; save-excursion isn't the right thing if
423 ;; process-buffer is current-buffer
424 (unwind-protect
425 (progn
426 ;; Write something in the compilation buffer
427 ;; and hack its mode line.
428 (set-buffer buffer)
429 (let ((buffer-read-only nil))
430 (setq omax (point-max)
431 opoint (point))
432 (goto-char omax)
433 ;; Record where we put the message, so we can ignore it
434 ;; later on.
435 (insert ?\n mode-name " " msg)
436 (forward-char -1)
437 (insert " at " (substring (current-time-string) 0 19))
438 (forward-char 1)
439 (setq mode-line-process
440 (concat ": "
441 (symbol-name (process-status proc))))
442 ;; Since the buffer and mode line will show that the
443 ;; process is dead, we can delete it now. Otherwise it
444 ;; will stay around until M-x list-processes.
445 (delete-process proc)
446 ;; Force mode line redisplay soon.
447 (set-buffer-modified-p (buffer-modified-p)))
448 (if (and opoint (< opoint omax))
449 (goto-char opoint))
450 (if compilation-finish-function
451 (funcall compilation-finish-function buffer msg)))
452 (set-buffer obuf))))
453 (setq compilation-in-progress (delq proc compilation-in-progress))
454 ))))
455
456 (defun compilation-filter (proc string)
457 "Process filter for compilation buffers.
458 Just inserts the text, but uses `insert-before-markers'."
459 (save-excursion
460 (set-buffer (process-buffer proc))
461 (let ((buffer-read-only nil))
462 (save-excursion
463 (goto-char (process-mark proc))
464 (insert-before-markers string)
465 (set-marker (process-mark proc) (point))))))
466
467 ;; Return the cdr of compilation-old-error-list for the error containing point.
468 (defun compile-error-at-point ()
469 (compile-reinitialize-errors nil (point))
470 (let ((errors compilation-old-error-list))
471 (while (and errors
472 (> (point) (car (car errors))))
473 (setq errors (cdr errors)))
474 errors))
475
476 (defun compilation-next-error (n)
477 "Move point to the next error in the compilation buffer.
478 Does NOT find the source line like \\[next-error]."
479 (interactive "p")
480 (or (compilation-buffer-p (current-buffer))
481 (error "Not in a compilation buffer."))
482 (setq compilation-last-buffer (current-buffer))
483
484 (let ((errors (compile-error-at-point)))
485
486 ;; Move to the error after the one containing point.
487 (goto-char (car (if (< n 0)
488 (let ((i 0)
489 (e compilation-old-error-list))
490 ;; See how many cdrs away ERRORS is from the start.
491 (while (not (eq e errors))
492 (setq i (1+ i)
493 e (cdr e)))
494 (if (> (- n) i)
495 (error "Moved back past first error")
496 (nth (+ i n) compilation-old-error-list)))
497 (let ((compilation-error-list (cdr errors)))
498 (compile-reinitialize-errors nil nil n)
499 (if compilation-error-list
500 (nth (1- n) compilation-error-list)
501 (error "Moved past last error"))))))))
502
503 (defun compilation-previous-error (n)
504 "Move point to the previous error in the compilation buffer.
505 Does NOT find the source line like \\[next-error]."
506 (interactive "p")
507 (compilation-next-error (- n)))
508
509
510 ;; Given an elt of `compilation-error-list', return an object representing
511 ;; the referenced file which is equal to (but not necessarily eq to) what
512 ;; this function would return for another error in the same file.
513 (defsubst compilation-error-filedata (data)
514 (setq data (cdr data))
515 (if (markerp data)
516 (marker-buffer data)
517 (car data)))
518
519 ;; Return a string describing a value from compilation-error-filedata.
520 ;; This value is not necessarily useful as a file name, but should be
521 ;; indicative to the user of what file's errors are being referred to.
522 (defsubst compilation-error-filedata-file-name (filedata)
523 (if (bufferp filedata)
524 (buffer-file-name filedata)
525 (car filedata)))
526
527 (defun compilation-next-file (n)
528 "Move point to the next error for a different file than the current one."
529 (interactive "p")
530 (or (compilation-buffer-p (current-buffer))
531 (error "Not in a compilation buffer."))
532 (setq compilation-last-buffer (current-buffer))
533
534 (let ((reversed (< n 0))
535 errors filedata)
536
537 (if (not reversed)
538 (setq errors (or (compile-error-at-point)
539 (error "Moved past last error")))
540
541 ;; Get a reversed list of the errors up through the one containing point.
542 (compile-reinitialize-errors nil (point))
543 (setq errors (reverse compilation-old-error-list)
544 n (- n))
545
546 ;; Ignore errors after point. (car ERRORS) will be the error
547 ;; containing point, (cadr ERRORS) the one before it.
548 (while (and errors
549 (< (point) (car (car errors))))
550 (setq errors (cdr errors))))
551
552 (while (> n 0)
553 (setq filedata (compilation-error-filedata (car errors)))
554
555 ;; Skip past the following errors for this file.
556 (while (equal filedata
557 (compilation-error-filedata
558 (car (or errors
559 (if reversed
560 (error "%s the first erring file"
561 (compilation-error-filedata-file-name
562 filedata))
563 (let ((compilation-error-list nil))
564 ;; Parse some more.
565 (compile-reinitialize-errors nil nil 2)
566 (setq errors compilation-error-list)))
567 (error "%s is the last erring file"
568 (compilation-error-filedata-file-name
569 filedata))))))
570 (setq errors (cdr errors)))
571
572 (setq n (1- n)))
573
574 ;; Move to the following error.
575 (goto-char (car (car (or errors
576 (if reversed
577 (error "This is the first erring file")
578 (let ((compilation-error-list nil))
579 ;; Parse the last one.
580 (compile-reinitialize-errors nil nil 1)
581 compilation-error-list))))))))
582
583 (defun compilation-previous-file (n)
584 "Move point to the previous error for a different file than the current one."
585 (interactive "p")
586 (compilation-next-file (- n)))
587
588
589 (defun kill-compilation ()
590 "Kill the process made by the \\[compile] command."
591 (interactive)
592 (let ((buffer (compilation-find-buffer)))
593 (if (get-buffer-process buffer)
594 (interrupt-process (get-buffer-process buffer))
595 (error "The compilation process is not running."))))
596
597
598 ;; Parse any new errors in the compilation buffer,
599 ;; or reparse from the beginning if the user has asked for that.
600 (defun compile-reinitialize-errors (argp &optional limit-search find-at-least)
601 (save-excursion
602 (set-buffer compilation-last-buffer)
603 ;; If we are out of errors, or if user says "reparse",
604 ;; discard the info we have, to force reparsing.
605 (if (or (eq compilation-error-list t)
606 (consp argp))
607 (progn (compilation-forget-errors)
608 (setq compilation-parsing-end 1)))
609 (if (and compilation-error-list
610 (or (not limit-search)
611 (> compilation-parsing-end limit-search))
612 (or (not find-at-least)
613 (> (length compilation-error-list) find-at-least)))
614 ;; Since compilation-error-list is non-nil, it points to a specific
615 ;; error the user wanted. So don't move it around.
616 nil
617 (switch-to-buffer compilation-last-buffer)
618 (set-buffer-modified-p nil)
619 (if (< compilation-parsing-end (point-max))
620 (let ((at-start (= compilation-parsing-end 1)))
621 (funcall compilation-parse-errors-function
622 limit-search find-at-least)
623 ;; Remember the entire list for compilation-forget-errors.
624 ;; If this is an incremental parse, append to previous list.
625 (if at-start
626 (setq compilation-old-error-list compilation-error-list)
627 (setq compilation-old-error-list
628 (nconc compilation-old-error-list compilation-error-list)))
629 )))))
630
631 (defun compile-goto-error (&optional argp)
632 "Visit the source for the error message point is on.
633 Use this command in a compilation log buffer.
634 \\[universal-argument] as a prefix arg means to reparse the buffer's error messages first;
635 other kinds of prefix arguments are ignored."
636 (interactive "P")
637 (or (compilation-buffer-p (current-buffer))
638 (error "Not in a compilation buffer."))
639 (setq compilation-last-buffer (current-buffer))
640 (compile-reinitialize-errors argp (point))
641
642 ;; Move to bol; the marker for the error on this line will point there.
643 (beginning-of-line)
644
645 ;; Move compilation-error-list to the elt of compilation-old-error-list
646 ;; we want.
647 (setq compilation-error-list compilation-old-error-list)
648 (while (and compilation-error-list
649 (> (point) (car (car compilation-error-list))))
650 (setq compilation-error-list (cdr compilation-error-list)))
651
652 ;; Move to another window, so that next-error's window changes
653 ;; result in the desired setup.
654 (or (one-window-p)
655 (progn
656 (other-window -1)
657 ;; other-window changed the selected buffer,
658 ;; but we didn't want to do that.
659 (set-buffer compilation-last-buffer)))
660
661 (next-error 1))
662
663 (defun compilation-buffer-p (buffer)
664 (assq 'compilation-error-list (buffer-local-variables buffer)))
665
666 ;; Return a compilation buffer.
667 ;; If the current buffer is a compilation buffer, return it.
668 ;; If compilation-last-buffer is set to a live buffer, use that.
669 ;; Otherwise, look for a compilation buffer and signal an error
670 ;; if there are none.
671 (defun compilation-find-buffer (&optional other-buffer)
672 (if (and (not other-buffer)
673 (compilation-buffer-p (current-buffer)))
674 ;; The current buffer is a compilation buffer.
675 (current-buffer)
676 (if (and compilation-last-buffer (buffer-name compilation-last-buffer)
677 (or (not other-buffer) (not (eq compilation-last-buffer
678 (current-buffer)))))
679 compilation-last-buffer
680 (let ((buffers (buffer-list)))
681 (while (and buffers (or (not (compilation-buffer-p (car buffers)))
682 (and other-buffer
683 (eq (car buffers) (current-buffer)))))
684 (setq buffers (cdr buffers)))
685 (if buffers
686 (car buffers)
687 (or (and other-buffer
688 (compilation-buffer-p (current-buffer))
689 ;; The current buffer is a compilation buffer.
690 (progn
691 (if other-buffer
692 (message "This is the only compilation buffer."))
693 (current-buffer)))
694 (error "No compilation started!")))))))
695
696 ;;;###autoload
697 (defun next-error (&optional argp)
698 "Visit next compilation error message and corresponding source code.
699 This operates on the output from the \\[compile] command.
700 If all preparsed error messages have been processed,
701 the error message buffer is checked for new ones.
702
703 A prefix arg specifies how many error messages to move;
704 negative means move back to previous error messages.
705 Just C-u as a prefix means reparse the error message buffer
706 and start at the first error.
707
708 \\[next-error] normally applies to the most recent compilation started,
709 but as long as you are in the middle of parsing errors from one compilation
710 output buffer, you stay with that compilation output buffer.
711
712 Use \\[next-error] in a compilation output buffer to switch to
713 processing errors from that compilation.
714
715 See variables `compilation-parse-errors-function' and
716 \`compilation-error-regexp-alist' for customization ideas."
717 (interactive "P")
718 (setq compilation-last-buffer (compilation-find-buffer))
719 (compile-reinitialize-errors argp nil
720 ;; We want to pass a number here only if
721 ;; we got a numeric prefix arg, not just C-u.
722 (and (not (consp argp))
723 (1- (prefix-numeric-value argp))))
724 ;; Make ARGP nil if the prefix arg was just C-u,
725 ;; since that means to reparse the errors, which the
726 ;; compile-reinitialize-errors call just did.
727 ;; Now we are only interested in a numeric prefix arg.
728 (if (consp argp)
729 (setq argp nil))
730 (let (next-errors next-error)
731 (save-excursion
732 (set-buffer compilation-last-buffer)
733 ;; compilation-error-list points to the "current" error.
734 (setq next-errors (nthcdr (1- (prefix-numeric-value argp))
735 compilation-error-list)
736 next-error (car next-errors))
737 (while
738 (progn
739 (if (null next-error)
740 (progn
741 (if argp (if (> (prefix-numeric-value argp) 0)
742 (error "Moved past last error")
743 (error "Moved back past first error")))
744 (compilation-forget-errors)
745 (error (concat compilation-error-message
746 (and (get-buffer-process (current-buffer))
747 (eq (process-status
748 (get-buffer-process
749 (current-buffer)))
750 'run)
751 " yet"))))
752 (setq compilation-error-list (cdr next-errors))
753 (if (null (cdr next-error))
754 ;; This error is boring. Go to the next.
755 t
756 (or (markerp (cdr next-error))
757 ;; This error has a filename/lineno pair.
758 ;; Find the file and turn it into a marker.
759 (let* ((fileinfo (car (cdr next-error)))
760 (buffer (compilation-find-file (cdr fileinfo)
761 (car fileinfo)
762 (car next-error))))
763 (if (null buffer)
764 ;; We can't find this error's file.
765 ;; Remove all errors in the same file.
766 (progn
767 (setq next-errors compilation-old-error-list)
768 (while next-errors
769 (and (consp (cdr (car next-errors)))
770 (equal (car (cdr (car next-errors)))
771 fileinfo)
772 (progn
773 (set-marker (car (car next-errors)) nil)
774 (setcdr (car next-errors) nil)))
775 (setq next-errors (cdr next-errors)))
776 ;; Look for the next error.
777 t)
778 ;; We found the file. Get a marker for this error.
779 ;; compilation-old-error-list is a buffer-local
780 ;; variable, so we must be careful to extract its value
781 ;; before switching to the source file buffer.
782 (let ((errors compilation-old-error-list)
783 (last-line (cdr (cdr next-error))))
784 (set-buffer buffer)
785 (save-excursion
786 (save-restriction
787 (widen)
788 (goto-line last-line)
789 (beginning-of-line)
790 (setcdr next-error (point-marker))
791 ;; Make all the other error messages referring
792 ;; to the same file have markers into the buffer.
793 (while errors
794 (and (consp (cdr (car errors)))
795 (equal (car (cdr (car errors))) fileinfo)
796 (let ((this (cdr (cdr (car errors))))
797 (lines (- (cdr (cdr (car errors)))
798 last-line)))
799 (if (eq selective-display t)
800 (if (< lines 0)
801 (re-search-backward "[\n\C-m]"
802 nil 'end
803 (- lines))
804 (re-search-forward "[\n\C-m]"
805 nil 'end
806 lines))
807 (forward-line lines))
808 (setq last-line this)
809 (setcdr (car errors) (point-marker))))
810 (setq errors (cdr errors)))))))))
811 ;; If we didn't get a marker for this error,
812 ;; go on to the next one.
813 (not (markerp (cdr next-error))))))
814 (setq next-errors compilation-error-list
815 next-error (car next-errors))))
816
817 ;; Skip over multiple error messages for the same source location,
818 ;; so the next C-x ` won't go to an error in the same place.
819 (while (and compilation-error-list
820 (equal (cdr (car compilation-error-list)) (cdr next-error)))
821 (setq compilation-error-list (cdr compilation-error-list)))
822
823 ;; We now have a marker for the position of the error.
824 (switch-to-buffer (marker-buffer (cdr next-error)))
825 (goto-char (cdr next-error))
826 ;; If narrowing got in the way of
827 ;; going to the right place, widen.
828 (or (= (point) (marker-position (cdr next-error)))
829 (progn
830 (widen)
831 (goto-char (cdr next-error))))
832
833 ;; Show compilation buffer in other window, scrolled to this error.
834 (let* ((pop-up-windows t)
835 (w (display-buffer (marker-buffer (car next-error)))))
836 (set-window-point w (car next-error))
837 (set-window-start w (car next-error)))))
838
839 ;;;###autoload
840 (define-key ctl-x-map "`" 'next-error)
841
842 ;; Find a buffer for file FILENAME.
843 ;; Search the directories in compilation-search-path.
844 ;; A nil in compilation-search-path means to try the
845 ;; current directory, which is passed in DIR.
846 ;; If FILENAME is not found at all, ask the user where to find it.
847 ;; Pop up the buffer containing MARKER and scroll to MARKER if we ask the user.
848 (defun compilation-find-file (filename dir marker)
849 (let ((dirs compilation-search-path)
850 result name)
851 (while (and dirs (null result))
852 (setq name (expand-file-name filename (or (car dirs) dir))
853 result (and (file-exists-p name)
854 (find-file-noselect name))
855 dirs (cdr dirs)))
856 (or result
857 ;; The file doesn't exist.
858 ;; Ask the user where to find it.
859 ;; If he hits C-g, then the next time he does
860 ;; next-error, he'll skip past it.
861 (progn
862 (let* ((pop-up-windows t)
863 (w (display-buffer (marker-buffer marker))))
864 (set-window-point w marker)
865 (set-window-start w marker))
866 (setq name
867 (expand-file-name
868 (read-file-name
869 (format "Find this error in: (default %s) "
870 filename) dir filename t)))
871 (if (file-directory-p name)
872 (setq name (concat (file-name-as-directory name) filename)))
873 (if (file-exists-p name)
874 (find-file-noselect name))))))
875
876 ;; Set compilation-error-list to nil, and unchain the markers that point to the
877 ;; error messages and their text, so that they no longer slow down gap motion.
878 ;; This would happen anyway at the next garbage collection, but it is better to
879 ;; do it right away.
880 (defun compilation-forget-errors ()
881 (while compilation-old-error-list
882 (let ((next-error (car compilation-old-error-list)))
883 (set-marker (car next-error) nil)
884 (if (markerp (cdr next-error))
885 (set-marker (cdr next-error) nil)))
886 (setq compilation-old-error-list (cdr compilation-old-error-list)))
887 (setq compilation-error-list nil
888 compilation-directory-stack nil))
889
890
891 (defun count-regexp-groupings (regexp)
892 "Return the number of \\( ... \\) groupings in REGEXP (a string)."
893 (let ((groupings 0)
894 (len (length regexp))
895 (i 0)
896 c)
897 (while (< i len)
898 (setq c (aref regexp i)
899 i (1+ i))
900 (cond ((= c ?\[)
901 ;; Find the end of this [...].
902 (while (and (< i len)
903 (not (= (aref regexp i) ?\])))
904 (setq i (1+ i))))
905 ((= c ?\\)
906 (if (< i len)
907 (progn
908 (setq c (aref regexp i)
909 i (1+ i))
910 (if (= c ?\))
911 ;; We found the end of a grouping,
912 ;; so bump our counter.
913 (setq groupings (1+ groupings))))))))
914 groupings))
915
916 (defun compilation-parse-errors (limit-search find-at-least)
917 "Parse the current buffer as grep, cc or lint error messages.
918 See variable `compilation-parse-errors-function' for the interface it uses."
919 (setq compilation-error-list nil)
920 (message "Parsing error messages...")
921 (let (text-buffer orig orig-expanded parent-expanded
922 regexp enter-group leave-group error-group
923 alist subexpr error-regexp-groups
924 (found-desired nil)
925 (compilation-num-errors-found 0))
926
927 ;; Don't reparse messages already seen at last parse.
928 (goto-char compilation-parsing-end)
929 ;; Don't parse the first two lines as error messages.
930 ;; This matters for grep.
931 (if (bobp)
932 (progn
933 (forward-line 2)
934 ;; Move back so point is before the newline.
935 ;; This matters because some error regexps use \n instead of ^
936 ;; to be faster.
937 (forward-char -1)))
938
939 ;; Compile all the regexps we want to search for into one.
940 (setq regexp (concat "\\(" compilation-enter-directory-regexp "\\)\\|"
941 "\\(" compilation-leave-directory-regexp "\\)\\|"
942 "\\(" (mapconcat (function
943 (lambda (elt)
944 (concat "\\(" (car elt) "\\)")))
945 compilation-error-regexp-alist
946 "\\|") "\\)"))
947
948 ;; Find out how many \(...\) groupings are in each of the regexps, and set
949 ;; *-GROUP to the grouping containing each constituent regexp (whose
950 ;; subgroups will come immediately thereafter) of the big regexp we have
951 ;; just constructed.
952 (setq enter-group 1
953 leave-group (+ enter-group
954 (count-regexp-groupings
955 compilation-enter-directory-regexp)
956 1)
957 error-group (+ leave-group
958 (count-regexp-groupings
959 compilation-leave-directory-regexp)
960 1))
961
962 ;; Compile an alist (IDX FILE LINE), where IDX is the number of the
963 ;; subexpression for an entire error-regexp, and FILE and LINE are the
964 ;; numbers for the subexpressions giving the file name and line number.
965 (setq alist (or compilation-error-regexp-alist
966 (error "compilation-error-regexp-alist is empty!"))
967 subexpr (1+ error-group))
968 (while alist
969 (setq error-regexp-groups (cons (list subexpr
970 (+ subexpr (nth 1 (car alist)))
971 (+ subexpr (nth 2 (car alist))))
972 error-regexp-groups))
973 (setq subexpr (+ subexpr 1 (count-regexp-groupings (car (car alist)))))
974 (setq alist (cdr alist)))
975
976 (setq orig default-directory)
977 (setq orig-expanded (file-truename orig))
978 (setq parent-expanded (expand-file-name "../" orig-expanded))
979
980 (while (and (not found-desired)
981 ;; We don't just pass LIMIT-SEARCH to re-search-forward
982 ;; because we want to find matches containing LIMIT-SEARCH
983 ;; but which extend past it.
984 (re-search-forward regexp nil t))
985
986 ;; Figure out which constituent regexp matched.
987 (cond ((match-beginning enter-group)
988 ;; The match was the enter-directory regexp.
989 (let ((dir
990 (file-name-as-directory
991 (expand-file-name
992 (buffer-substring (match-beginning (+ enter-group 1))
993 (match-end (+ enter-group 1)))))))
994 ;; The directory name in the "entering" message
995 ;; is a truename. Try to convert it to a form
996 ;; like what the user typed in.
997 (setq dir
998 (compile-abbreviate-directory dir orig orig-expanded
999 parent-expanded))
1000 (setq compilation-directory-stack
1001 (cons dir compilation-directory-stack))
1002 (and (file-directory-p dir)
1003 (setq default-directory dir))))
1004
1005 ((match-beginning leave-group)
1006 ;; The match was the leave-directory regexp.
1007 (let ((beg (match-beginning (+ leave-group 1)))
1008 (stack compilation-directory-stack))
1009 (if beg
1010 (let ((dir
1011 (file-name-as-directory
1012 (expand-file-name
1013 (buffer-substring beg
1014 (match-end (+ leave-group
1015 1)))))))
1016 ;; The directory name in the "entering" message
1017 ;; is a truename. Try to convert it to a form
1018 ;; like what the user typed in.
1019 (setq dir
1020 (compile-abbreviate-directory dir orig orig-expanded
1021 parent-expanded))
1022 (while (and stack
1023 (not (string-equal (car stack) dir)))
1024 (setq stack (cdr stack)))))
1025 (setq compilation-directory-stack (cdr stack))
1026 (setq stack (car compilation-directory-stack))
1027 (if stack
1028 (setq default-directory stack))
1029 ))
1030
1031 ((match-beginning error-group)
1032 ;; The match was the composite error regexp.
1033 ;; Find out which individual regexp matched.
1034 (setq alist error-regexp-groups)
1035 (while (and alist
1036 (null (match-beginning (car (car alist)))))
1037 (setq alist (cdr alist)))
1038 (if alist
1039 (setq alist (car alist))
1040 (error "compilation-parse-errors: impossible regexp match!"))
1041
1042 ;; Extract the file name and line number from the error message.
1043 (let ((beginning-of-match (match-beginning 0)) ;looking-at nukes
1044 (filename
1045 (cons default-directory
1046 (buffer-substring (match-beginning (nth 1 alist))
1047 (match-end (nth 1 alist)))))
1048 (linenum (save-restriction
1049 (narrow-to-region
1050 (match-beginning (nth 2 alist))
1051 (match-end (nth 2 alist)))
1052 (goto-char (point-min))
1053 (if (looking-at "[0-9]")
1054 (read (current-buffer))))))
1055 ;; Locate the erring file and line.
1056 ;; Cons a new elt onto compilation-error-list,
1057 ;; giving a marker for the current compilation buffer
1058 ;; location, and the file and line number of the error.
1059 (save-excursion
1060 (beginning-of-line 1)
1061 (setq compilation-error-list
1062 (cons (cons (point-marker)
1063 (cons filename linenum))
1064 compilation-error-list)))
1065 (setq compilation-num-errors-found
1066 (1+ compilation-num-errors-found))
1067 (and find-at-least (>= compilation-num-errors-found
1068 find-at-least)
1069 ;; We have found as many new errors as the user wants.
1070 ;; We continue to parse until we have seen all
1071 ;; the consecutive errors in the same file,
1072 ;; so the error positions will be recorded as markers
1073 ;; in this buffer that might change.
1074 (cdr compilation-error-list) ; Must check at least two.
1075 (not (equal (car (cdr (nth 0 compilation-error-list)))
1076 (car (cdr (nth 1 compilation-error-list)))))
1077 (progn
1078 ;; Discard the error just parsed, so that the next
1079 ;; parsing run can get it and the following errors in
1080 ;; the same file all at once. If we didn't do this, we
1081 ;; would have the same problem we are trying to avoid
1082 ;; with the test above, just delayed until the next run!
1083 (setq compilation-error-list
1084 (cdr compilation-error-list))
1085 (goto-char beginning-of-match)
1086 (setq found-desired t)))
1087 )
1088 )
1089 (t
1090 (error "compilation-parse-errors: known groups didn't match!")))
1091
1092 (message "Parsing error messages...%d (%d%% of buffer)"
1093 compilation-num-errors-found
1094 (/ (* 100 (point)) (point-max)))
1095
1096 (and limit-search (>= (point) limit-search)
1097 ;; The user wanted a specific error, and we're past it.
1098 (setq found-desired t)))
1099 (setq compilation-parsing-end (if found-desired
1100 (point)
1101 ;; We have searched the whole buffer.
1102 (point-max))))
1103 (setq compilation-error-list (nreverse compilation-error-list))
1104 (message "Parsing error messages...done"))
1105
1106 ;; If directory DIR is a subdir of ORIG or of ORIG's parent,
1107 ;; return a relative name for it starting from ORIG or its parent.
1108 ;; ORIG-EXPANDED is an expanded version of ORIG.
1109 ;; PARENT-EXPANDED is an expanded version of ORIG's parent.
1110 ;; Those two args could be computed here, but we run faster by
1111 ;; having the caller compute them just once.
1112 (defun compile-abbreviate-directory (dir orig orig-expanded parent-expanded)
1113 (if (and (> (length dir) (length orig-expanded))
1114 (string= orig-expanded
1115 (substring dir 0 (length orig-expanded))))
1116 (setq dir
1117 (concat orig
1118 (substring dir (length orig-expanded)))))
1119 (if (and (> (length dir) (length parent-expanded))
1120 (string= parent-expanded
1121 (substring dir 0 (length parent-expanded))))
1122 (setq dir
1123 (concat (file-name-directory
1124 (directory-file-name orig))
1125 (substring dir (length parent-expanded)))))
1126 dir)
1127
1128 (provide 'compile)
1129
1130 ;;; compile.el ends here