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