From: Teodor Zlatanov <tzz@lifelogs.com>
[bpt/emacs.git] / lisp / progmodes / compile.el
CommitLineData
55535639 1;;; compile.el --- run compiler as inferior of Emacs, parse error messages
fad160d5 2
7837c247 3;; Copyright (C) 1985, 86, 87, 93, 94, 95, 96, 97, 98, 1999, 2001, 03, 2004
e335e194 4;; Free Software Foundation, Inc.
3a801d0c 5
7837c247
SM
6;; Authors: Roland McGrath <roland@gnu.org>,
7;; Daniel Pfeiffer <occitan@esperanto.org>
d1c7011d 8;; Maintainer: FSF
e9571d2a 9;; Keywords: tools, processes
d1c7011d 10
55dfd2c4
RS
11;; This file is part of GNU Emacs.
12
29add8b9
RM
13;; GNU Emacs is free software; you can redistribute it and/or modify
14;; it under the terms of the GNU General Public License as published by
15;; the Free Software Foundation; either version 2, or (at your option)
16;; any later version.
17
55dfd2c4 18;; GNU Emacs is distributed in the hope that it will be useful,
29add8b9
RM
19;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21;; GNU General Public License for more details.
22
23;; You should have received a copy of the GNU General Public License
b578f267
EN
24;; along with GNU Emacs; see the file COPYING. If not, write to the
25;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26;; Boston, MA 02111-1307, USA.
55dfd2c4 27
5cc57841
ER
28;;; Commentary:
29
7837c247
SM
30;; This package provides the compile facilities documented in the Emacs user's
31;; manual.
5cc57841 32
c536bb39 33;; This mode uses some complex data-structures:
7837c247 34
c536bb39 35;; LOC (or location) is a list of (COLUMN LINE FILE-STRUCTURE)
7837c247
SM
36
37;; COLUMN and LINE are numbers parsed from an error message. COLUMN and maybe
38;; LINE will be nil for a message that doesn't contain them. Then the
39;; location refers to a indented beginning of line or beginning of file.
40;; Once any location in some file has been jumped to, the list is extended to
41;; (COLUMN LINE FILE-STRUCTURE MARKER . VISITED) for all LOCs pertaining to
42;; that file.
43;; MARKER initially points to LINE and COLUMN in a buffer visiting that file.
44;; Being a marker it sticks to some text, when the buffer grows or shrinks
45;; before that point. VISITED is t if we have jumped there, else nil.
46
c536bb39
SM
47;; FILE-STRUCTURE is a list of
48;; ((FILENAME . DIRECTORY) FORMATS (LINE LOC ...) ...)
7837c247
SM
49
50;; FILENAME is a string parsed from an error message. DIRECTORY is a string
51;; obtained by following directory change messages. DIRECTORY will be nil for
52;; an absolute filename. FORMATS is a list of formats to apply to FILENAME if
53;; a file of that name can't be found.
54;; The rest of the list is an alist of elements with LINE as key. The keys
55;; are either nil or line numbers. If present, nil comes first, followed by
56;; the numbers in decreasing order. The LOCs for each line are again an alist
57;; ordered the same way. Note that the whole file structure is referenced in
58;; every LOC.
59
c536bb39 60;; MESSAGE is a list of (LOC TYPE END-LOC)
7837c247
SM
61
62;; TYPE is 0 for info or 1 for warning if the message matcher identified it as
63;; such, 2 otherwise (for a real error). END-LOC is a LOC pointing to the
64;; other end, if the parsed message contained a range. If the end of the
65;; range didn't specify a COLUMN, it defaults to -1, meaning end of line.
66;; These are the value of the `message' text-properties in the compilation
67;; buffer.
68
24299582
DP
69;;; Code:
70
583a15bb
SM
71(eval-when-compile (require 'cl))
72
c5049fa0
RS
73(defgroup compilation nil
74 "Run compiler as inferior of Emacs, parse error messages."
75 :group 'tools
76 :group 'processes)
77
78
7c163413 79;;;###autoload
c5049fa0
RS
80(defcustom compilation-mode-hook nil
81 "*List of hook functions run by `compilation-mode' (see `run-hooks')."
82 :type 'hook
83 :group 'compilation)
7c163413
RM
84
85;;;###autoload
c5049fa0
RS
86(defcustom compilation-window-height nil
87 "*Number of lines in a compilation window. If nil, use Emacs default."
88 :type '(choice (const :tag "Default" nil)
89 integer)
90 :group 'compilation)
d3cb357b 91
7837c247
SM
92(defvar compilation-first-column 1
93 "*This is how compilers number the first column, usually 1 or 0.")
55dfd2c4 94
e335e194
GM
95(defvar compilation-parse-errors-filename-function nil
96 "Function to call to post-process filenames while parsing error messages.
97It takes one arg FILENAME which is the name of a file as found
98in the compilation output, and should return a transformed file name.")
99
49683a13
EZ
100;;;###autoload
101(defvar compilation-process-setup-function nil
102 "*Function to call to customize the compilation process.
6f5b7627 103This function is called immediately before the compilation process is
49683a13 104started. It can be used to set any variables or functions that are used
9ac57479
KS
105while processing the output of the compilation process. The function
106is called with variables `compilation-buffer' and `compilation-window'
7837c247 107bound to the compilation buffer and window, respectively.")
49683a13 108
aa228418 109;;;###autoload
d3cb357b 110(defvar compilation-buffer-name-function nil
6c43f2f9
RS
111 "Function to compute the name of a compilation buffer.
112The function receives one argument, the name of the major mode of the
113compilation buffer. It should return a string.
114nil means compute the name with `(concat \"*\" (downcase major-mode) \"*\")'.")
55dfd2c4 115
aa228418 116;;;###autoload
d3cb357b 117(defvar compilation-finish-function nil
c5049fa0 118 "Function to call when a compilation process finishes.
d3cb357b
RM
119It is called with two arguments: the compilation buffer, and a string
120describing how the process finished.")
55dfd2c4 121
4cc36b17
RS
122;;;###autoload
123(defvar compilation-finish-functions nil
c5049fa0 124 "Functions to call when a compilation process finishes.
4cc36b17
RS
125Each function is called with two arguments: the compilation buffer,
126and a string describing how the process finished.")
127
d3cb357b 128(defvar compilation-last-buffer nil
6c43f2f9
RS
129 "The most recent compilation buffer.
130A buffer becomes most recent when its compilation is started
131or when it is used with \\[next-error] or \\[compile-goto-error].")
55dfd2c4 132
ebff767c
RM
133(defvar compilation-in-progress nil
134 "List of compilation processes now running.")
135(or (assq 'compilation-in-progress minor-mode-alist)
136 (setq minor-mode-alist (cons '(compilation-in-progress " Compiling")
137 minor-mode-alist)))
138
7837c247
SM
139(defvar compilation-error "error"
140 "Stem of message to print when no matches are found.")
6c43f2f9 141
58856335 142(defvar compilation-arguments nil
7837c247 143 "Arguments that were given to `compilation-start'.")
58856335 144
6c43f2f9 145(defvar compilation-num-errors-found)
d3cb357b 146
7837c247
SM
147(defconst compilation-error-regexp-alist-alist
148 '((absoft
149 "^\\(?:[Ee]rror on \\|[Ww]arning on\\( \\)\\)?[Ll]ine[ \t]+\\([0-9]+\\)[ \t]+\
150of[ \t]+\"?\\([a-zA-Z]?:?[^\":\n]+\\)\"?:" 3 2 nil (1))
5dfa3d35 151
7837c247
SM
152 (ada
153 "\\(warning: .*\\)? at \\([^ \n]+\\):\\([0-9]+\\)$" 2 3 nil (1))
c7c5bbc0 154
7837c247
SM
155 (aix
156 " in line \\([0-9]+\\) of file \\([^ \n]+[^. \n]\\)\\.? " 2 1)
e1f540f2 157
7837c247
SM
158 (ant
159 "^[ \t]*\\[[^] \n]+\\][ \t]*\\([^: \n]+\\):\\([0-9]+\\):\\(?:\\([0-9]+\\):[0-9]+:[0-9]+:\\)?\
160\\( warning\\)?" 1 2 3 (4))
e1f540f2 161
7837c247
SM
162 (bash
163 "^\\([^: \n\t]+\\): line \\([0-9]+\\):" 1 2)
e1f540f2 164
7837c247
SM
165 (borland
166 "^\\(?:Error\\|Warnin\\(g\\)\\) \\(?:[FEW][0-9]+ \\)?\
167\\([a-zA-Z]?:?[^:( \t\n]+\\)\
168 \\([0-9]+\\)\\(?:[) \t]\\|:[^0-9\n]\\)" 2 3 nil (1))
169
170 (caml
f6164cdd
DP
171 "^ *File \\(\"?\\)\\([^,\" \n\t<>]+\\)\\1, lines? \\([0-9]+\\)-?\\([0-9]+\\)?\\(?:$\\|,\
172\\(?: characters? \\([0-9]+\\)-?\\([0-9]+\\)?:\\)?\\([ \n]Warning:\\)?\\)"
173 2 (3 . 4) (5 . 6) (7))
7837c247
SM
174
175 (comma
176 "^\"\\([^,\" \n\t]+\\)\", line \\([0-9]+\\)\
177\\(?:[(. pos]+\\([0-9]+\\))?\\)?[:.,; (-]\\( warning:\\|[-0-9 ]*(W)\\)?" 1 2 3 (4))
178
179 (epc
180 "^Error [0-9]+ at (\\([0-9]*\\):\\([^)\n]+\\))" 2 1)
181
182 (iar
183 "^\"\\(.*\\)\",\\([0-9]+\\)\\s-+\\(?:Error\\|Warnin\\(g\\)\\)\\[[0-9]+\\]:"
184 1 2 nil (3))
185
186 (ibm
187 "^\\([^( \n\t]+\\)(\\([0-9]+\\):\\([0-9]+\\)) :\
188 \\(?:warnin\\(g\\)\\|informationa\\(l\\)\\)?" 1 2 3 (4 . 5))
189
6f5b7627 190 ;; fixme: should be `mips'
7837c247 191 (irix
6f5b7627 192 "^[-[:alnum:]_/]+: \\(?:[eE]rror\\|[wW]arnin\\(g\\)\\|[iI]nf\\(o\\)\\)[0-9 ]*:\
f6164cdd 193 \\([^,\" \n\t]+\\)\\(?:, line\\|:\\) \\([0-9]+\\):" 3 4 nil (1 . 2))
7837c247
SM
194
195 (java
196 "^\\(?:[ \t]+at \\|==[0-9]+== +\\(?:at\\|b\\(y\\)\\)\\).+(\\([^()\n]+\\):\\([0-9]+\\))$" 2 3 nil (1))
197
198 (jikes-file
199 "^\\(?:Found\\|Issued\\) .* compiling \"\\(.+\\)\":$" 1 nil nil 0)
200 (jikes-line
201 "^ *\\([0-9]+\\)\\.[ \t]+.*\n +\\(<-*>\n\\*\\*\\* \\(?:Error\\|Warnin\\(g\\)\\)\\)"
202 nil 1 nil 2 0
203 (2 (compilation-face '(3))))
204
205 (gcc-include
206 "^\\(?:In file included\\| \\) from \
207\\(.+\\):\\([0-9]+\\)\\(?:\\(:\\)\\|\\(,\\)\\)?" 1 2 nil (3 . 4))
208
209 (gnu
6f5b7627 210 "^\\(?:[[:alpha:]][-[:alnum:].]+: ?\\)?\
7837c247
SM
211\\([/.]*[a-zA-Z]:?[^ \t\n:]*\\): ?\
212\\([0-9]+\\)\\([.:]?\\)\\([0-9]+\\)?\
213\\(?:-\\(?:\\([0-9]+\\)\\3\\)?\\.?\\([0-9]+\\)?\\)?:\
214\\(?: *\\(\\(?:Future\\|Runtime\\)?[Ww]arning\\|W:\\)\\|\
215 *\\([Ii]nfo\\(?:\\>\\|rmationa?l?\\)\\|I:\\)\\)?"
216 1 (2 . 5) (4 . 6) (7 . 8))
217
218 (lcc
219 "^\\(?:E\\|\\(W\\)\\), \\([^(\n]+\\)(\\([0-9]+\\),[ \t]*\\([0-9]+\\)"
220 2 3 4 (1))
221
222 (makepp
0cb687c0 223 "^makepp: \\(?:\\(?:warning\\(:\\).*?\\|\\(Scanning\\|[LR]e?l?oading makefile\\) \\|.*?\\)\
7837c247
SM
224`\\(\\(\\S +?\\)\\(?::\\([0-9]+\\)\\)?\\)'\\)"
225 4 5 nil (1 . 2) 3
226 ("`\\(\\(\\S +?\\)\\(?::\\([0-9]+\\)\\)?\\)'" nil nil
227 (2 compilation-info-face)
228 (3 compilation-line-face nil t)
51c8ad03 229 (1 (compilation-error-properties 2 3 nil nil nil 0 nil)
7837c247
SM
230 append)))
231
6f5b7627 232 ;; Should be lint-1, lint-2 (SysV lint)
7837c247
SM
233 (mips-1
234 " (\\([0-9]+\\)) in \\([^ \n]+\\)" 2 1)
235 (mips-2
236 " in \\([^()\n ]+\\)(\\([0-9]+\\))$" 1 2)
237
238 (msft
239 "^\\(\\(?:[a-zA-Z]:\\)?[^:(\t\n]+\\)(\\([0-9]+\\)) \
240: \\(?:error\\|warnin\\(g\\)\\) C[0-9]+:" 1 2 nil (3))
241
242 (oracle
243 "^Semantic error at line \\([0-9]+\\), column \\([0-9]+\\), file \\(.*\\):$"
244 3 1 2)
40d63d1f 245
7837c247
SM
246 (perl
247 " at \\([^ \n]+\\) line \\([0-9]+\\)\\(?:[,.]\\|$\\)" 1 2)
248
249 (rxp
250 "^\\(?:Error\\|Warnin\\(g\\)\\):.*\n.* line \\([0-9]+\\) char\
251 \\([0-9]+\\) of file://\\(.+\\)"
252 4 2 3 (1))
253
254 (sparc-pascal-file
255 "^\\w\\w\\w \\w\\w\\w +[0-3]?[0-9] +[0-2][0-9]:[0-5][0-9]:[0-5][0-9]\
256 [12][09][0-9][0-9] +\\(.*\\):$"
257 1 nil nil 0)
258 (sparc-pascal-line
259 "^\\(\\(?:E\\|\\(w\\)\\) +[0-9]+\\) line \\([0-9]+\\) - "
260 nil 3 nil (2) nil (1 (compilation-face '(2))))
261 (sparc-pascal-example
262 "^ +\\([0-9]+\\) +.*\n\\(\\(?:e\\|\\(w\\)\\) [0-9]+\\)-+"
263 nil 1 nil (3) nil (2 (compilation-face '(3))))
264
265 (sun
6f5b7627 266 ": \\(?:ERROR\\|WARNIN\\(G\\)\\|REMAR\\(K\\)\\) \\(?:[[:alnum:] ]+, \\)?\
7837c247
SM
267File = \\(.+\\), Line = \\([0-9]+\\)\\(?:, Column = \\([0-9]+\\)\\)?"
268 3 4 5 (1 . 2))
269
270 (sun-ada
271 "^\\([^, \n\t]+\\), line \\([0-9]+\\), char \\([0-9]+\\)[:., \(-]" 1 2 3)
272
6f5b7627
SM
273 ;; Redundant with `mips'
274;; (ultrix
275;; "^\\(?:cfe\\|fort\\): \\(Warning\\)?[^:\n]*: \\([^ \n]*\\), line \\([0-9]+\\):" 2 3 nil (1))
7837c247
SM
276
277 (4bsd
278 "\\(?:^\\|:: \\|\\S ( \\)\\(/[^ \n\t()]+\\)(\\([0-9]+\\))\
279\\(?:: \\(warning:\\)?\\|$\\| ),\\)" 1 2 nil (3)))
280 "Alist of values for `compilation-error-regexp-alist'.")
281
282(defcustom compilation-error-regexp-alist
283 (mapcar 'car compilation-error-regexp-alist-alist)
6c43f2f9 284 "Alist that specifies how to match errors in compiler output.
6f5b7627 285Note that on Unix everything is a valid filename, so these
7837c247
SM
286matchers must make some common sense assumptions, which catch
287normal cases. A shorter list will be lighter on resource usage.
288
289Instead of an alist element, you can use a symbol, which is
290looked up in `compilation-error-regexp-alist-alist'. You can see
291the predefined symbols and their effects in the file
6f5b7627 292`etc/compilation.txt' (linked below if you are customizing this).
7837c247
SM
293
294Each elt has the form (REGEXP FILE [LINE COLUMN TYPE HYPERLINK
295HIGHLIGHT...]). If REGEXP matches, the FILE'th subexpression
296gives the file name, and the LINE'th subexpression gives the line
297number. The COLUMN'th subexpression gives the column number on
298that line.
299
300If FILE, LINE or COLUMN are nil or that index didn't match, that
301information is not present on the matched line. In that case the
302file name is assumed to be the same as the previous one in the
303buffer, line number defaults to 1 and column defaults to
304beginning of line's indentation.
305
306FILE can also have the form (FILE FORMAT...), where the FORMATs
307\(e.g. \"%s.c\") will be applied in turn to the recognized file
308name, until a file of that name is found. Or FILE can also be a
309function to return the filename.
310
311LINE can also be of the form (LINE . END-LINE) meaning a range
312of lines. COLUMN can also be of the form (COLUMN . END-COLUMN)
313meaning a range of columns starting on LINE and ending on
314END-LINE, if that matched.
315
316TYPE is 2 or nil for a real error or 1 for warning or 0 for info.
317TYPE can also be of the form (WARNING . INFO). In that case this
318will be equivalent to 1 if the WARNING'th subexpression matched
319or else equivalent to 0 if the INFO'th subexpression matched.
320See `compilation-error-face', `compilation-warning-face',
321`compilation-info-face' and `compilation-skip-threshold'.
322
323What matched the HYPERLINK'th subexpression has `mouse-face' and
324`compilation-message-face' applied. If this is nil, the text
325matched by the whole REGEXP becomes the hyperlink.
326
327Additional HIGHLIGHTs as described under `font-lock-keywords' can
328be added."
329 :type `(set :menu-tag "Pick"
330 ,@(mapcar (lambda (elt)
331 (list 'const (car elt)))
332 compilation-error-regexp-alist-alist))
333 :link `(file-link :tag "example file"
334 ,(concat doc-directory "compilation.txt"))
335 :group 'compilation)
55dfd2c4 336
ebb8cb68
EZ
337(defvar compilation-directory nil
338 "Directory to restore to when doing `recompile'.")
339
7837c247
SM
340(defvar compilation-directory-matcher
341 '("\\(?:Entering\\|Leavin\\(g\\)\\) directory `\\(.+\\)'$" (2 . 1))
342 "A list for tracking when directories are entered or left.
343Nil means not to track directories, e.g. if all file names are absolute. The
344first element is the REGEXP matching these messages. It can match any number
345of variants, e.g. different languages. The remaining elements are all of the
346form (DIR . LEAVE). If for any one of these the DIR'th subexpression
347matches, that is a directory name. If LEAVE is nil or the corresponding
348LEAVE'th subexpression doesn't match, this message is about going into another
349directory. If it does match anything, this message is about going back to the
350directory we were in before the last entering message. If you change this,
351you may also want to change `compilation-page-delimiter'.")
352
353(defvar compilation-page-delimiter
354 "^\\(?:\f\\|.*\\(?:Entering\\|Leaving\\) directory `.+'\n\\)+"
355 "Value of `page-delimiter' in Compilation mode.")
356
357(defvar compilation-mode-font-lock-keywords
358 '(;; configure output lines.
359 ("^[Cc]hecking \\(?:[Ff]or \\|[Ii]f \\|[Ww]hether \\(?:to \\)?\\)?\\(.+\\)\\.\\.\\. *\\(?:(cached) *\\)?\\(\\(yes\\(?: .+\\)?\\)\\|no\\|\\(.*\\)\\)$"
360 (1 font-lock-variable-name-face)
361 (2 (compilation-face '(4 . 3))))
362 ;; Command output lines. Recognize `make[n]:' lines too.
6f5b7627 363 ("^\\([[:alnum:]_/.+-]+\\)\\(\\[\\([0-9]+\\)\\]\\)?[ \t]*:"
7837c247
SM
364 (1 font-lock-function-name-face) (3 compilation-line-face nil t))
365 (" --?o\\(?:utfile\\|utput\\)?[= ]?\\(\\S +\\)" . 1)
366 ("^Compilation finished" . compilation-info-face)
367 ("^Compilation exited abnormally" . compilation-error-face))
368 "Additional things to highlight in Compilation mode.
369This gets tacked on the end of the generated expressions.")
a24770bc 370
9ac57479
KS
371(defvar compilation-highlight-regexp t
372 "Regexp matching part of visited source lines to highlight temporarily.
373Highlight entire line if t; don't highlight source lines if nil.")
374
375(defvar compilation-highlight-overlay nil
376 "Overlay used to temporarily highlight compilation matches.")
377
f8e03ecb
AS
378(defcustom compilation-error-screen-columns t
379 "*If non-nil, column numbers in error messages are screen columns.
380Otherwise they are interpreted as character positions, with
381each character occupying one column.
382The default is to use screen columns, which requires that the compilation
383program and Emacs agree about the display width of the characters,
384especially the TAB character."
385 :type 'boolean
386 :group 'compilation
387 :version "20.4")
388
c5049fa0 389(defcustom compilation-read-command t
851231e9
DL
390 "*Non-nil means \\[compile] reads the compilation command to use.
391Otherwise, \\[compile] just uses the value of `compile-command'."
c5049fa0
RS
392 :type 'boolean
393 :group 'compilation)
90016295 394
e83be080 395;;;###autoload
c5049fa0 396(defcustom compilation-ask-about-save t
851231e9 397 "*Non-nil means \\[compile] asks which buffers to save before compiling.
c5049fa0
RS
398Otherwise, it saves all modified buffers without asking."
399 :type 'boolean
400 :group 'compilation)
90016295 401
7c163413 402;;;###autoload
c5049fa0 403(defcustom compilation-search-path '(nil)
7c163413 404 "*List of directories to search for source files named in error messages.
d3cb357b 405Elements should be directory names, not file names of directories.
c5049fa0
RS
406nil as an element means to try the default directory."
407 :type '(repeat (choice (const :tag "Default" nil)
408 (string :tag "Directory")))
409 :group 'compilation)
55dfd2c4 410
c5049fa0
RS
411(defcustom compile-command "make -k "
412 "*Last shell command used to do a compilation; default for next compilation.
55dfd2c4
RS
413
414Sometimes it is useful for files to supply local values for this variable.
415You might also use mode hooks to specify it in certain modes, like this:
416
61c4aaf8 417 (add-hook 'c-mode-hook
61c4aaf8
RS
418 (lambda ()
419 (unless (or (file-exists-p \"makefile\")
420 (file-exists-p \"Makefile\"))
5b6858da
SM
421 (set (make-local-variable 'compile-command)
422 (concat \"make -k \"
7837c247 423 (file-name-sans-extension buffer-file-name))))))"
c5049fa0
RS
424 :type 'string
425 :group 'compilation)
55dfd2c4 426
7837c247
SM
427;; A weak per-compilation-buffer hash indexed by (FILENAME . DIRECTORY). Each
428;; value is a FILE-STRUCTURE as described above, with the car eq to the hash
429;; key. This holds the tree seen from root, for storing new nodes.
430(defvar compilation-locs ())
431
432(defvar compilation-debug nil
6f5b7627 433 "*Set this to t before creating a *compilation* buffer.
7837c247
SM
434Then every error line will have a debug text property with the matcher that
435fit this line and the match data. Use `describe-text-properties'.")
d3cb357b 436
01f89d11
RM
437(defvar compilation-exit-message-function nil "\
438If non-nil, called when a compilation process dies to return a status message.
fd5e58d7
RM
439This should be a function of three arguments: process status, exit status,
440and exit message; it returns a cons (MESSAGE . MODELINE) of the strings to
441write into the compilation buffer, and to put in its mode line.")
01f89d11 442
c20f961b
JPW
443(defvar compilation-environment nil
444 "*List of environment variables for compilation to inherit.
445Each element should be a string of the form ENVVARNAME=VALUE.
446This list is temporarily prepended to `process-environment' prior to
447starting the compilation process.")
448
770970cb
RS
449;; History of compile commands.
450(defvar compile-history nil)
770970cb 451
7837c247
SM
452(defface compilation-warning-face
453 '((((type tty) (class color)) (:foreground "cyan" :weight bold))
454 (((class color)) (:foreground "Orange" :weight bold))
455 (t (:weight bold)))
456 "Face used to highlight compiler warnings."
f6164cdd
DP
457 :group 'font-lock-highlighting-faces
458 :version "21.4")
7837c247
SM
459
460(defface compilation-info-face
461 '((((type tty) (class color)) (:foreground "green" :weight bold))
462 (((class color) (background light)) (:foreground "Green3" :weight bold))
463 (((class color) (background dark)) (:foreground "Green" :weight bold))
464 (t (:weight bold)))
465 "Face used to highlight compiler warnings."
f6164cdd
DP
466 :group 'font-lock-highlighting-faces
467 :version "21.4")
7837c247
SM
468
469(defvar compilation-message-face nil
470 "Face name to use for whole messages.
471Faces `compilation-error-face', `compilation-warning-face',
472`compilation-info-face', `compilation-line-face' and
473`compilation-column-face' get prepended to this, when applicable.")
474
475(defvar compilation-error-face 'font-lock-warning-face
476 "Face name to use for file name in error messages.")
477
478(defvar compilation-warning-face 'compilation-warning-face
479 "Face name to use for file name in warning messages.")
480
481(defvar compilation-info-face 'compilation-info-face
482 "Face name to use for file name in informational messages.")
483
484(defvar compilation-line-face 'font-lock-variable-name-face
485 "Face name to use for line number in message.")
486
487(defvar compilation-column-face 'font-lock-type-face
488 "Face name to use for column number in message.")
489
490;; same faces as dired uses
491(defvar compilation-enter-directory-face 'font-lock-function-name-face
492 "Face name to use for column number in message.")
493
494(defvar compilation-leave-directory-face 'font-lock-type-face
495 "Face name to use for column number in message.")
496
497
498
c536bb39 499;; Used for compatibility with the old compile.el.
6f5b7627 500(defvar compilation-parsing-end (make-marker))
c536bb39
SM
501(defvar compilation-parse-errors-function nil)
502(defvar compilation-error-list nil)
503(defvar compilation-old-error-list nil)
504
7837c247
SM
505(defun compilation-face (type)
506 (or (and (car type) (match-end (car type)) compilation-warning-face)
507 (and (cdr type) (match-end (cdr type)) compilation-info-face)
508 compilation-error-face))
509
510(defun compilation-directory-properties (idx leave)
511 (if leave (setq leave (match-end leave)))
512 ;; find previous stack, and push onto it, or if `leave' pop it
513 (let ((dir (previous-single-property-change (point) 'directory)))
514 (setq dir (if dir (or (get-text-property (1- dir) 'directory)
515 (get-text-property dir 'directory))))
516 `(face ,(if leave
517 compilation-leave-directory-face
518 compilation-enter-directory-face)
519 directory ,(if leave
520 (or (cdr dir)
521 '(nil)) ; nil only isn't a property-change
522 (cons (match-string-no-properties idx) dir))
523 mouse-face highlight
6f5b7627 524 keymap compilation-button-map
7837c247
SM
525 help-echo "mouse-2: visit current directory")))
526
527;; Data type `reverse-ordered-alist' retriever. This function retrieves the
528;; KEY element from the ALIST, creating it in the right position if not already
529;; present. ALIST structure is
530;; '(ANCHOR (KEY1 ...) (KEY2 ...)... (KEYn ALIST ...))
531;; ANCHOR is ignored, but necessary so that elements can be inserted. KEY1
532;; may be nil. The other KEYs are ordered backwards so that growing line
533;; numbers can be inserted in front and searching can abort after half the
534;; list on average.
6f5b7627 535(eval-when-compile ;Don't keep it at runtime if not needed.
7837c247
SM
536(defmacro compilation-assq (key alist)
537 `(let* ((l1 ,alist)
538 (l2 (cdr l1)))
539 (car (if (if (null ,key)
540 (if l2 (null (caar l2)))
541 (while (if l2 (if (caar l2) (< ,key (caar l2)) t))
542 (setq l1 l2
543 l2 (cdr l1)))
544 (if l2 (eq ,key (caar l2))))
545 l2
6f5b7627 546 (setcdr l1 (cons (list ,key) l2)))))))
7837c247
SM
547
548
549;; This function is the central driver, called when font-locking to gather
550;; all information needed to later jump to corresponding source code.
551;; Return a property list with all meta information on this error location.
552(defun compilation-error-properties (file line end-line col end-col type fmt)
553 (unless (< (next-single-property-change (match-beginning 0) 'directory nil (point))
554 (point))
555 (if file
556 (if (functionp file)
557 (setq file (funcall file))
558 (let (dir)
559 (setq file (match-string-no-properties file))
560 (unless (file-name-absolute-p file)
561 (setq dir (previous-single-property-change (point) 'directory)
562 dir (if dir (or (get-text-property (1- dir) 'directory)
563 (get-text-property dir 'directory)))))
efb0e677 564 (setq file (cons file (car dir)))))
7837c247
SM
565 ;; This message didn't mention one, get it from previous
566 (setq file (previous-single-property-change (point) 'message)
567 file (or (if file
efb0e677
SM
568 (car (nth 2 (car (or (get-text-property (1- file) 'message)
569 (get-text-property file 'message))))))
570 '("*unknown*"))))
7837c247
SM
571 ;; All of these fields are optional, get them only if we have an index, and
572 ;; it matched some part of the message.
573 (and line
574 (setq line (match-string-no-properties line))
575 (setq line (string-to-number line)))
576 (and end-line
577 (setq end-line (match-string-no-properties end-line))
578 (setq end-line (string-to-number end-line)))
579 (and col
580 (setq col (match-string-no-properties col))
581 (setq col (- (string-to-number col) compilation-first-column)))
582 (if (and end-col (setq end-col (match-string-no-properties end-col)))
583 (setq end-col (- (string-to-number end-col) compilation-first-column))
584 (if end-line (setq end-col -1)))
eb6fb6e2 585 (if (consp type) ; not a static type, check what it is.
7837c247
SM
586 (setq type (or (and (car type) (match-end (car type)) 1)
587 (and (cdr type) (match-end (cdr type)) 0)
588 2)))
efb0e677
SM
589 (compilation-internal-error-properties file line end-line col end-col type fmt)))
590
591(defun compilation-internal-error-properties (file line end-line col end-col type fmt)
592 "Get the meta-info that will be added as text-properties.
593LINE, END-LINE, COL, END-COL are integers or nil.
594TYPE can be 0, 1, or 2.
595FILE should be (FILENAME . DIRNAME) or nil."
596 (unless file (setq file '("*unknown*")))
597 (setq file (or (gethash file compilation-locs)
598 (puthash file (list file fmt) compilation-locs)))
599 ;; Get first already existing marker (if any has one, all have one).
600 ;; Do this first, as the compilation-assq`s may create new nodes.
601 (let* ((marker-line (car (cddr file))) ; a line structure
602 (marker (nth 3 (cadr marker-line))) ; its marker
603 (compilation-error-screen-columns compilation-error-screen-columns)
604 end-marker loc end-loc)
605 (if (not (and marker (marker-buffer marker)))
606 (setq marker) ; no valid marker for this file
607 (setq loc (or line 1) ; normalize no linenumber to line 1
608 marker-line)
609 (catch 'marker ; find nearest loc, at least one exists
610 (dolist (x (cddr file)) ; loop over lines
611 (if (> (or (car x) 1) loc) ; still bigger
612 (setq marker-line x)
613 (if (or (not marker-line) ; first in list
614 (> (- (or (car marker-line) 1) loc)
615 (- loc (or (car x) 1)))) ; current line is nearer
616 (setq marker-line x))
617 (throw 'marker t))))
618 (setq marker (nth 3 (cadr marker-line))
619 marker-line (car marker-line))
620 (with-current-buffer (marker-buffer marker)
621 (save-restriction
622 (widen)
623 (goto-char (marker-position marker))
624 (when (or end-col end-line)
625 (beginning-of-line (- (or end-line line) marker-line -1))
626 (if (< end-col 0)
627 (end-of-line)
628 (if compilation-error-screen-columns
629 (move-to-column end-col)
630 (forward-char end-col)))
631 (setq end-marker (list (point-marker))))
632 (beginning-of-line (if end-line
633 (- end-line line -1)
634 (- loc marker-line -1)))
635 (if col
636 (if compilation-error-screen-columns
637 (move-to-column col)
638 (forward-char col))
639 (forward-to-indentation 0))
640 (setq marker (list (point-marker))))))
641
642 (setq loc (compilation-assq line (cdr file)))
643 (if end-line
644 (setq end-loc (compilation-assq end-line (cdr file))
645 end-loc (compilation-assq end-col end-loc))
646 (if end-col ; use same line element
647 (setq end-loc (compilation-assq end-col loc))))
648 (setq loc (compilation-assq col loc))
649 ;; If they are new, make the loc(s) reference the file they point to.
650 (or (cdr loc) (setcdr loc `(,line ,file ,@marker)))
651 (if end-loc
652 (or (cdr end-loc) (setcdr end-loc `(,(or end-line line) ,file ,@end-marker))))
653
654 ;; Must start with face
655 `(face ,compilation-message-face
656 message (,loc ,type ,end-loc)
657 ,@(if compilation-debug
658 `(debug (,(assoc (with-no-warnings matcher) font-lock-keywords)
659 ,@(match-data))))
660 help-echo ,(if col
661 "mouse-2: visit this file, line and column"
662 (if line
663 "mouse-2: visit this file and line"
664 "mouse-2: visit this file"))
665 keymap compilation-button-map
666 mouse-face highlight)))
7837c247 667
e93b2a55
SM
668(defun compilation-mode-font-lock-keywords ()
669 "Return expressions to highlight in Compilation mode."
91fa27cd
SM
670 (if compilation-parse-errors-function
671 ;; An old package! Try the compatibility code.
672 '((compilation-compat-parse-errors))
673 (append
674 ;; make directory tracking
675 (if compilation-directory-matcher
676 `((,(car compilation-directory-matcher)
677 ,@(mapcar (lambda (elt)
678 `(,(car elt)
679 (compilation-directory-properties
680 ,(car elt) ,(cdr elt))
681 t))
682 (cdr compilation-directory-matcher)))))
683
684 ;; Compiler warning/error lines.
685 (mapcar
686 (lambda (item)
687 (if (symbolp item)
688 (setq item (cdr (assq item
689 compilation-error-regexp-alist-alist))))
690 (let ((file (nth 1 item))
691 (line (nth 2 item))
692 (col (nth 3 item))
693 (type (nth 4 item))
694 end-line end-col fmt)
b3a7f48f
DP
695 (if (consp file) (setq fmt (cdr file) file (car file)))
696 (if (consp line) (setq end-line (cdr line) line (car line)))
91fa27cd 697 (if (consp col) (setq end-col (cdr col) col (car col)))
b3a7f48f 698
544dccaa 699 (if (functionp line)
91fa27cd
SM
700 ;; The old compile.el had here an undocumented hook that
701 ;; allowed `line' to be a function that computed the actual
702 ;; error location. Let's do our best.
703 `(,(car item)
704 (0 (compilation-compat-error-properties
6f5b7627
SM
705 (funcall ',line (cons (match-string ,file)
706 (cons default-directory
707 ',(nthcdr 4 item)))
91fa27cd
SM
708 ,(if col `(match-string ,col)))))
709 (,file compilation-error-face t))
b3a7f48f 710
91fa27cd
SM
711 `(,(nth 0 item)
712
713 ,@(when (integerp file)
714 `((,file ,(if (consp type)
715 `(compilation-face ',type)
716 (aref [compilation-info-face
717 compilation-warning-face
718 compilation-error-face]
719 (or type 2))))))
720
721 ,@(when line
722 `((,line compilation-line-face nil t)))
723 ,@(when end-line
724 `((,end-line compilation-line-face nil t)))
725
726 ,@(when col
727 `((,col compilation-column-face nil t)))
728 ,@(when end-col
729 `((,end-col compilation-column-face nil t)))
730
731 ,@(nthcdr 6 item)
732 (,(or (nth 5 item) 0)
733 (compilation-error-properties ',file ,line ,end-line
734 ,col ,end-col ',(or type 2)
735 ',fmt)
736 append))))) ; for compilation-message-face
737 compilation-error-regexp-alist)
738
739 compilation-mode-font-lock-keywords)))
7837c247 740
01f89d11 741\f
d3cb357b 742;;;###autoload
7837c247 743(defun compile (command &optional comint)
55dfd2c4
RS
744 "Compile the program including the current buffer. Default: run `make'.
745Runs COMMAND, a shell command, in a separate process asynchronously
746with output going to the buffer `*compilation*'.
d3cb357b 747
6f5b7627 748If optional second arg COMINT is t the buffer will be in Comint mode with
7837c247
SM
749`compilation-shell-minor-mode'.
750
55dfd2c4
RS
751You can then use the command \\[next-error] to find the next error message
752and move to the source code that caused it.
753
08b1edf4
RM
754Interactively, prompts for the command if `compilation-read-command' is
755non-nil; otherwise uses `compile-command'. With prefix arg, always prompts.
756
c72095b3
RS
757To run more than one compilation at once, start one and rename
758the \`*compilation*' buffer to some other name with
759\\[rename-buffer]. Then start the next one. On most systems,
760termination of the main compilation process kills its
761subprocesses.
d3cb357b
RM
762
763The name used for the buffer is actually whatever is returned by
764the function in `compilation-buffer-name-function', so you can set that
765to a function that generates a unique name."
90016295 766 (interactive
08b1edf4 767 (if (or compilation-read-command current-prefix-arg)
90016295 768 (list (read-from-minibuffer "Compile command: "
7837c247
SM
769 (eval compile-command) nil nil
770 '(compile-history . 1)))
5b6858da
SM
771 (list (eval compile-command))))
772 (unless (equal command (eval compile-command))
773 (setq compile-command command))
90016295 774 (save-some-buffers (not compilation-ask-about-save) nil)
ebb8cb68 775 (setq compilation-directory default-directory)
7837c247 776 (compilation-start command comint))
55dfd2c4 777
5b6858da 778;; run compile with the default command line
e60476ca 779(defun recompile ()
6867356a 780 "Re-compile the program including the current buffer.
6f5b7627
SM
781If this is run in a Compilation mode buffer, re-use the arguments from the
782original use. Otherwise, recompile using `compile-command'."
e60476ca
RS
783 (interactive)
784 (save-some-buffers (not compilation-ask-about-save) nil)
ebb8cb68 785 (let ((default-directory (or compilation-directory default-directory)))
7837c247
SM
786 (apply 'compilation-start (or compilation-arguments
787 `(,(eval compile-command))))))
09843b4a 788
b5812513
DL
789(defcustom compilation-scroll-output nil
790 "*Non-nil to scroll the *compilation* buffer window as output appears.
791
6f5b7627 792Setting it causes the Compilation mode commands to put point at the
b5812513 793end of their output window so that the end of the output is always
6f5b7627 794visible rather than the beginning."
b5812513 795 :type 'boolean
a46fddeb 796 :version "20.3"
b5812513
DL
797 :group 'compilation)
798
7bdb67b2
GM
799
800(defun compilation-buffer-name (mode-name name-function)
801 "Return the name of a compilation buffer to use.
802If NAME-FUNCTION is non-nil, call it with one argument MODE-NAME
803to determine the buffer name.
804Likewise if `compilation-buffer-name-function' is non-nil.
805If current buffer is in Compilation mode for the same mode name
806return the name of the current buffer, so that it gets reused.
807Otherwise, construct a buffer name from MODE-NAME."
dc2feacf 808 (cond (name-function
7bdb67b2 809 (funcall name-function mode-name))
dc2feacf 810 (compilation-buffer-name-function
7bdb67b2
GM
811 (funcall compilation-buffer-name-function mode-name))
812 ((and (eq major-mode 'compilation-mode)
813 (equal mode-name (nth 2 compilation-arguments)))
814 (buffer-name))
815 (t
816 (concat "*" (downcase mode-name) "*"))))
817
7837c247
SM
818;; This is a rough emulation of the old hack, until the transition to new
819;; compile is complete.
55dfd2c4 820(defun compile-internal (command error-message
a24770bc
RS
821 &optional name-of-mode parser
822 error-regexp-alist name-function
823 enter-regexp-alist leave-regexp-alist
23b0c5fc 824 file-regexp-alist nomessage-regexp-alist
9ac57479 825 no-async highlight-regexp local-map)
7837c247
SM
826 (if parser
827 (error "Compile now works very differently, see `compilation-error-regexp-alist'"))
828 (let ((compilation-error-regexp-alist
829 (append file-regexp-alist (or error-regexp-alist
830 compilation-error-regexp-alist)))
831 (compilation-error (replace-regexp-in-string "^No more \\(.+\\)s\\.?"
832 "\\1" error-message)))
833 (compilation-start command nil name-function highlight-regexp)))
834(make-obsolete 'compile-internal 'compilation-start)
835
836(defun compilation-start (command &optional mode name-function highlight-regexp)
55dfd2c4 837 "Run compilation command COMMAND (low level interface).
9ac57479
KS
838The rest of the arguments are optional; for them, nil means use the default.
839
7837c247 840MODE is the major mode to set in the compilation buffer. Mode
6f5b7627 841may also be t meaning use `compilation-shell-minor-mode' under `comint-mode'.
9ac57479 842NAME-FUNCTION is a function called to name the buffer.
23b0c5fc 843
9ac57479 844If HIGHLIGHT-REGEXP is non-nil, `next-error' will temporarily highlight
6f5b7627 845the matching section of the visited source line; the default is to use the
9ac57479
KS
846global value of `compilation-highlight-regexp'.
847
646bd331 848Returns the compilation buffer created."
7837c247
SM
849 (or mode (setq mode 'compilation-mode))
850 (let ((name-of-mode
851 (if (eq mode t)
852 (prog1 "compilation" (require 'comint))
853 (replace-regexp-in-string "-mode$" "" (symbol-name mode))))
854 (process-environment
855 (append
856 compilation-environment
6f5b7627
SM
857 (if (if (boundp 'system-uses-terminfo) ; `if' for compiler warning
858 system-uses-terminfo)
7837c247
SM
859 (list "TERM=dumb" "TERMCAP="
860 (format "COLUMNS=%d" (window-width)))
861 (list "TERM=emacs"
862 (format "TERMCAP=emacs:co#%d:tc=unknown:"
863 (window-width))))
864 ;; Set the EMACS variable, but
865 ;; don't override users' setting of $EMACS.
866 (unless (getenv "EMACS") '("EMACS=t"))
867 process-environment))
868 (thisdir default-directory)
869 outwin outbuf)
c536bb39
SM
870 (with-current-buffer
871 (setq outbuf
872 (get-buffer-create
873 (compilation-buffer-name name-of-mode name-function)))
d3cb357b
RM
874 (let ((comp-proc (get-buffer-process (current-buffer))))
875 (if comp-proc
876 (if (or (not (eq (process-status comp-proc) 'run))
877 (yes-or-no-p
bea1d57a
JB
878 (format "A %s process is running; kill it? "
879 name-of-mode)))
d3cb357b
RM
880 (condition-case ()
881 (progn
882 (interrupt-process comp-proc)
883 (sit-for 1)
884 (delete-process comp-proc))
885 (error nil))
886 (error "Cannot have two processes in `%s' at once"
7837c247
SM
887 (buffer-name)))))
888 ;; Clear out the compilation buffer and make it writable.
889 ;; Change its default-directory to the directory where the compilation
890 ;; will happen, and insert a `cd' command to indicate this.
891 (setq buffer-read-only nil)
892 (buffer-disable-undo (current-buffer))
893 (erase-buffer)
894 (buffer-enable-undo (current-buffer))
895 (setq default-directory thisdir)
896 ;; output a mode setter, for saving and later reloading this buffer
897 (insert "cd " thisdir " # -*-" name-of-mode
898 "-*-\nEntering directory `" thisdir "'\n" command "\n")
899 (set-buffer-modified-p nil))
900 ;; If we're already in the compilation buffer, go to the end
901 ;; of the buffer, so point will track the compilation output.
902 (if (eq outbuf (current-buffer))
903 (goto-char (point-max)))
904 ;; Pop up the compilation buffer.
905 (setq outwin (display-buffer outbuf nil t))
906 (with-current-buffer outbuf
907 (if (not (eq mode t))
908 (funcall mode)
909 (with-no-warnings (comint-mode))
910 (compilation-shell-minor-mode))
911 ;; In what way is it non-ergonomic ? -stef
912 ;; (toggle-read-only 1) ;;; Non-ergonomic.
913 (if highlight-regexp
914 (set (make-local-variable 'compilation-highlight-regexp)
915 highlight-regexp))
916 (set (make-local-variable 'compilation-arguments)
917 (list command mode name-function highlight-regexp))
918 (set (make-local-variable 'revert-buffer-function)
919 'compilation-revert-buffer)
920 (set-window-start outwin (point-min))
921 (or (eq outwin (selected-window))
fe4dda18
AS
922 (set-window-point outwin (if compilation-scroll-output
923 (point)
924 (point-min))))
7837c247
SM
925 ;; The setup function is called before compilation-set-window-height
926 ;; so it can set the compilation-window-height buffer locally.
927 (if compilation-process-setup-function
928 (funcall compilation-process-setup-function))
929 (compilation-set-window-height outwin)
930 ;; Start the compilation.
931 (if (fboundp 'start-process)
932 (let ((proc (if (eq mode t)
933 (get-buffer-process
934 (with-no-warnings
935 (comint-exec outbuf (downcase mode-name)
936 shell-file-name nil `("-c" ,command))))
937 (start-process-shell-command (downcase mode-name)
938 outbuf command))))
939 ;; Make the buffer's mode line show process state.
940 (setq mode-line-process '(":%s"))
941 (set-process-sentinel proc 'compilation-sentinel)
942 (set-process-filter proc 'compilation-filter)
943 (set-marker (process-mark proc) (point) outbuf)
944 (setq compilation-in-progress
945 (cons proc compilation-in-progress)))
946 ;; No asynchronous processes available.
947 (message "Executing `%s'..." command)
948 ;; Fake modeline display as if `start-process' were run.
949 (setq mode-line-process ":run")
950 (force-mode-line-update)
951 (let ((status (call-process shell-file-name nil outbuf nil "-c"
952 command)))
953 (cond ((numberp status)
954 (compilation-handle-exit 'exit status
955 (if (zerop status)
956 "finished\n"
957 (format "\
fd5e58d7 958exited abnormally with code %d\n"
7837c247
SM
959 status))))
960 ((stringp status)
961 (compilation-handle-exit 'signal status
962 (concat status "\n")))
963 (t
964 (compilation-handle-exit 'bizarre status status))))
965 (message "Executing `%s'...done" command)))
966 (if (buffer-local-value 'compilation-scroll-output outbuf)
967 (save-selected-window
968 (select-window outwin)
043442b4
KS
969 (goto-char (point-max))))
970 ;; Make it so the next C-x ` will use this buffer.
971 (setq compilation-last-buffer outbuf)))
55dfd2c4 972
c94b02d6 973(defun compilation-set-window-height (window)
851231e9 974 "Set the height of WINDOW according to `compilation-window-height'."
9ac57479
KS
975 (let ((height (buffer-local-value 'compilation-window-height (window-buffer window))))
976 (and height
977 (= (window-width window) (frame-width (window-frame window)))
978 ;; If window is alone in its frame, aside from a minibuffer,
979 ;; don't change its height.
980 (not (eq window (frame-root-window (window-frame window))))
981 ;; This save-current-buffer prevents us from changing the current
982 ;; buffer, which might not be the same as the selected window's buffer.
983 (save-current-buffer
984 (save-selected-window
985 (select-window window)
986 (enlarge-window (- height (window-height))))))))
c94b02d6 987
4282eba1
SM
988(defvar compilation-menu-map
989 (let ((map (make-sparse-keymap "Errors")))
990 (define-key map [stop-subjob]
37bf89ab 991 '("Stop Compilation" . kill-compilation))
4282eba1
SM
992 (define-key map [compilation-mode-separator2]
993 '("----" . nil))
9ac57479 994 (define-key map [compilation-first-error]
4282eba1 995 '("First Error" . first-error))
9ac57479 996 (define-key map [compilation-previous-error]
4282eba1 997 '("Previous Error" . previous-error))
9ac57479 998 (define-key map [compilation-next-error]
4282eba1
SM
999 '("Next Error" . next-error))
1000 map))
1001
0b18a8f6 1002(defvar compilation-minor-mode-map
55dfd2c4 1003 (let ((map (make-sparse-keymap)))
9da85ee5 1004 (define-key map [mouse-2] 'compile-goto-error)
55dfd2c4 1005 (define-key map "\C-c\C-c" 'compile-goto-error)
4e7ce12e 1006 (define-key map "\C-m" 'compile-goto-error)
d3cb357b 1007 (define-key map "\C-c\C-k" 'kill-compilation)
646bd331
RM
1008 (define-key map "\M-n" 'compilation-next-error)
1009 (define-key map "\M-p" 'compilation-previous-error)
d1ed4475
RM
1010 (define-key map "\M-{" 'compilation-previous-file)
1011 (define-key map "\M-}" 'compilation-next-file)
4282eba1
SM
1012 ;; Set up the menu-bar
1013 (define-key map [menu-bar compilation]
1014 (cons "Errors" compilation-menu-map))
55dfd2c4 1015 map)
4f6e4ad6 1016 "Keymap for `compilation-minor-mode'.")
0b18a8f6 1017
a24770bc
RS
1018(defvar compilation-shell-minor-mode-map
1019 (let ((map (make-sparse-keymap)))
a24770bc
RS
1020 (define-key map "\M-\C-m" 'compile-goto-error)
1021 (define-key map "\M-\C-n" 'compilation-next-error)
1022 (define-key map "\M-\C-p" 'compilation-previous-error)
1023 (define-key map "\M-{" 'compilation-previous-file)
1024 (define-key map "\M-}" 'compilation-next-file)
1025 ;; Set up the menu-bar
4282eba1
SM
1026 (define-key map [menu-bar compilation]
1027 (cons "Errors" compilation-menu-map))
a24770bc
RS
1028 map)
1029 "Keymap for `compilation-shell-minor-mode'.")
1030
60470fd2
SM
1031(defvar compilation-button-map
1032 (let ((map (make-sparse-keymap)))
1033 (define-key map [mouse-2] 'compile-goto-error)
1034 (define-key map "\C-m" 'compile-goto-error)
1035 map)
1036 "Keymap for compilation-message buttons.")
1037(fset 'compilation-button-map compilation-button-map)
1038
0b18a8f6 1039(defvar compilation-mode-map
4282eba1
SM
1040 (let ((map (make-sparse-keymap)))
1041 (set-keymap-parent map compilation-minor-mode-map)
0b18a8f6
RM
1042 (define-key map " " 'scroll-up)
1043 (define-key map "\^?" 'scroll-down)
9ac57479 1044
e60476ca 1045 ;; Set up the menu-bar
4282eba1 1046 (define-key map [menu-bar compilation]
e60476ca 1047 (cons "Compile" (make-sparse-keymap "Compile")))
4282eba1 1048 (define-key map [menu-bar compilation compilation-separator2]
e60476ca 1049 '("----" . nil))
9ac57479 1050 (define-key map [menu-bar compilation compilation-grep]
7933678b 1051 '("Search Files (grep)" . grep))
9ac57479 1052 (define-key map [menu-bar compilation compilation-recompile]
e60476ca 1053 '("Recompile" . recompile))
9ac57479 1054 (define-key map [menu-bar compilation compilation-compile]
32f4ab17 1055 '("Compile..." . compile))
0b18a8f6
RM
1056 map)
1057 "Keymap for compilation log buffers.
4282eba1 1058`compilation-minor-mode-map' is a parent of this.")
55dfd2c4 1059
0a35bd79
RS
1060(put 'compilation-mode 'mode-class 'special)
1061
c536bb39
SM
1062(defvar compilation-skip-to-next-location t
1063 "*If non-nil, skip multiple error messages for the same source location.")
1064
1065(defcustom compilation-skip-threshold 1
1066 "*Compilation motion commands skip less important messages.
1067The value can be either 2 -- skip anything less than error, 1 --
1068skip anything less than warning or 0 -- don't skip any messages.
1069Note that all messages not positively identified as warning or
1070info, are considered errors."
1071 :type '(choice (const :tag "Warnings and info" 2)
1072 (const :tag "Info" 1)
1073 (const :tag "None" 0))
f6164cdd
DP
1074 :group 'compilation
1075 :version "21.4")
c536bb39
SM
1076
1077(defcustom compilation-skip-visited nil
1078 "*Compilation motion commands skip visited messages if this is t.
1079Visited messages are ones for which the file, line and column have been jumped
1080to from the current content in the current compilation buffer, even if it was
1081from a different message."
1082 :type 'boolean
f6164cdd
DP
1083 :group 'compilation
1084 :version "21.4")
c536bb39 1085
501cf428 1086;;;###autoload
7837c247 1087(defun compilation-mode ()
55dfd2c4
RS
1088 "Major mode for compilation log buffers.
1089\\<compilation-mode-map>To visit the source for a line-numbered error,
d3cb357b 1090move point to the error message line and type \\[compile-goto-error].
7c163413
RM
1091To kill the compilation, type \\[kill-compilation].
1092
1093Runs `compilation-mode-hook' with `run-hooks' (which see)."
55dfd2c4 1094 (interactive)
9af0d309 1095 (kill-all-local-variables)
55dfd2c4 1096 (use-local-map compilation-mode-map)
0b18a8f6 1097 (setq major-mode 'compilation-mode
7837c247
SM
1098 mode-name "Compilation")
1099 (set (make-local-variable 'page-delimiter)
1100 compilation-page-delimiter)
0b18a8f6 1101 (compilation-setup)
7837c247
SM
1102 (run-mode-hooks 'compilation-mode-hook))
1103
1104(defmacro define-compilation-mode (mode name doc &rest body)
1105 "This is like `define-derived-mode' without the PARENT argument.
1106The parent is always `compilation-mode' and the customizable `compilation-...'
1107variables are also set from the name of the mode you have chosen, by replacing
1108the fist word, e.g `compilation-scroll-output' from `grep-scroll-output' if that
1109variable exists."
1110 (let ((mode-name (replace-regexp-in-string "-mode\\'" "" (symbol-name mode))))
1111 `(define-derived-mode ,mode compilation-mode ,name
1112 ,doc
1113 ,@(mapcar (lambda (v)
1114 (setq v (cons v
1115 (intern-soft (replace-regexp-in-string
1116 "^compilation" mode-name
1117 (symbol-name v)))))
1118 (and (cdr v)
1119 (or (boundp (cdr v))
1120 (if (boundp 'byte-compile-bound-variables)
1121 (memq (cdr v) byte-compile-bound-variables)))
1122 `(set (make-local-variable ',(car v)) ,(cdr v))))
1123 '(compilation-buffer-name-function
1124 compilation-directory-matcher
1125 compilation-error
1126 compilation-error-regexp-alist
1127 compilation-error-regexp-alist-alist
1128 compilation-error-screen-columns
1129 compilation-finish-function
1130 compilation-finish-functions
1131 compilation-first-column
1132 compilation-mode-font-lock-keywords
1133 compilation-page-delimiter
1134 compilation-parse-errors-filename-function
1135 compilation-process-setup-function
1136 compilation-scroll-output
1137 compilation-search-path
1138 compilation-skip-threshold
1139 compilation-window-height))
1140 ,@body)))
0b18a8f6 1141
58856335 1142(defun compilation-revert-buffer (ignore-auto noconfirm)
9ed2ab9f
RS
1143 (if buffer-file-name
1144 (let (revert-buffer-function)
9ac57479 1145 (revert-buffer ignore-auto noconfirm))
9ed2ab9f 1146 (if (or noconfirm (yes-or-no-p (format "Restart compilation? ")))
7837c247
SM
1147 (apply 'compilation-start compilation-arguments))))
1148
c536bb39
SM
1149(defvar compilation-current-error nil
1150 "Marker to the location from where the next error will be found.
1151The global commands next/previous/first-error/goto-error use this.")
51c8ad03 1152
7837c247
SM
1153;; A function name can't be a hook, must be something with a value.
1154(defconst compilation-turn-on-font-lock 'turn-on-font-lock)
58856335 1155
7837c247 1156(defun compilation-setup (&optional minor)
6f5b7627
SM
1157 "Prepare the buffer for the compilation parsing commands to work.
1158Optional argument MINOR indicates this is called from
1159`compilation-minor-mode'."
51c8ad03 1160 (make-local-variable 'compilation-current-error)
18aac618 1161 (make-local-variable 'compilation-error-screen-columns)
b3a7f48f 1162 (make-local-variable 'overlay-arrow-position)
7837c247 1163 (setq compilation-last-buffer (current-buffer))
7837c247
SM
1164 (set (make-local-variable 'font-lock-extra-managed-props)
1165 '(directory message help-echo mouse-face debug))
1166 (set (make-local-variable 'compilation-locs)
1167 (make-hash-table :test 'equal :weakness 'value))
6f5b7627 1168 ;; lazy-lock would never find the message unless it's scrolled to.
c536bb39
SM
1169 ;; jit-lock might fontify some things too late.
1170 (set (make-local-variable 'font-lock-support-mode) nil)
7837c247 1171 (set (make-local-variable 'font-lock-maximum-size) nil)
f6164cdd
DP
1172 (let ((fld font-lock-defaults))
1173 (if (and minor fld)
1174 (font-lock-add-keywords nil (compilation-mode-font-lock-keywords))
1175 (setq font-lock-defaults '(compilation-mode-font-lock-keywords t)))
1176 (if minor
1177 (if font-lock-mode
1178 (if fld
1179 (font-lock-fontify-buffer)
1180 (font-lock-change-mode)
1181 (turn-on-font-lock))
1182 (turn-on-font-lock))
1183 ;; maybe defer font-lock till after derived mode is set up
1184 (run-mode-hooks 'compilation-turn-on-font-lock))))
0b18a8f6 1185
7052680b 1186;;;###autoload
4282eba1 1187(define-minor-mode compilation-shell-minor-mode
7052680b
RS
1188 "Toggle compilation shell minor mode.
1189With arg, turn compilation mode on if and only if arg is positive.
4282eba1
SM
1190In this minor mode, all the error-parsing commands of the
1191Compilation major mode are available but bound to keys that don't
1192collide with Shell mode. See `compilation-mode'.
7052680b 1193Turning the mode on runs the normal hook `compilation-shell-minor-mode-hook'."
7837c247 1194 nil " Shell-Compile"
d408fed8 1195 :group 'compilation
7837c247
SM
1196 (if compilation-shell-minor-mode
1197 (compilation-setup t)
1198 (font-lock-remove-keywords nil (compilation-mode-font-lock-keywords))
1199 (font-lock-fontify-buffer)))
7052680b 1200
d6bd8dca 1201;;;###autoload
4282eba1 1202(define-minor-mode compilation-minor-mode
0b18a8f6
RM
1203 "Toggle compilation minor mode.
1204With arg, turn compilation mode on if and only if arg is positive.
4282eba1
SM
1205In this minor mode, all the error-parsing commands of the
1206Compilation major mode are available. See `compilation-mode'.
fee3f63a 1207Turning the mode on runs the normal hook `compilation-minor-mode-hook'."
7837c247 1208 nil " Compilation"
d408fed8 1209 :group 'compilation
7837c247
SM
1210 (if compilation-minor-mode
1211 (compilation-setup t)
1212 (font-lock-remove-keywords nil (compilation-mode-font-lock-keywords))
1213 (font-lock-fontify-buffer)))
55dfd2c4 1214
fd5e58d7 1215(defun compilation-handle-exit (process-status exit-status msg)
6f5b7627 1216 "Write MSG in the current buffer and hack its mode-line-process."
fd5e58d7
RM
1217 (let ((buffer-read-only nil)
1218 (status (if compilation-exit-message-function
1219 (funcall compilation-exit-message-function
1220 process-status exit-status msg)
1221 (cons msg exit-status)))
1222 (omax (point-max))
1223 (opoint (point)))
b3a7f48f 1224 ;; Record where we put the message, so we can ignore it later on.
fd5e58d7
RM
1225 (goto-char omax)
1226 (insert ?\n mode-name " " (car status))
0eac1faa 1227 (if (and (numberp compilation-window-height)
7837c247
SM
1228 (zerop compilation-window-height))
1229 (message "%s" (cdr status)))
01c50447
RS
1230 (if (bolp)
1231 (forward-char -1))
fd5e58d7 1232 (insert " at " (substring (current-time-string) 0 19))
01c50447 1233 (goto-char (point-max))
47092737
RS
1234 ;; Prevent that message from being recognized as a compilation error.
1235 (add-text-properties omax (point)
1236 (append '(compilation-handle-exit t) nil))
52f84622 1237 (setq mode-line-process (format ":%s [%s]" process-status (cdr status)))
fd5e58d7
RM
1238 ;; Force mode line redisplay soon.
1239 (force-mode-line-update)
1240 (if (and opoint (< opoint omax))
1241 (goto-char opoint))
1242 (if compilation-finish-function
4cc36b17
RS
1243 (funcall compilation-finish-function (current-buffer) msg))
1244 (let ((functions compilation-finish-functions))
1245 (while functions
1246 (funcall (car functions) (current-buffer) msg)
1247 (setq functions (cdr functions))))))
fd5e58d7 1248
55dfd2c4 1249;; Called when compilation process changes state.
55dfd2c4 1250(defun compilation-sentinel (proc msg)
d3cb357b 1251 "Sentinel for compilation buffers."
b3a7f48f
DP
1252 (if (memq (process-status proc) '(exit signal))
1253 (let ((buffer (process-buffer proc)))
1254 (if (null (buffer-name buffer))
1255 ;; buffer killed
1256 (set-process-buffer proc nil)
1257 (with-current-buffer buffer
1258 ;; Write something in the compilation buffer
1259 ;; and hack its mode line.
1260 (compilation-handle-exit (process-status proc)
1261 (process-exit-status proc)
1262 msg)
1263 ;; Since the buffer and mode line will show that the
1264 ;; process is dead, we can delete it now. Otherwise it
1265 ;; will stay around until M-x list-processes.
1266 (delete-process proc)))
1267 (setq compilation-in-progress (delq proc compilation-in-progress)))))
55dfd2c4 1268
ad62b7f1
RM
1269(defun compilation-filter (proc string)
1270 "Process filter for compilation buffers.
4f6e4ad6 1271Just inserts the text, but uses `insert-before-markers'."
991c70f8 1272 (if (buffer-name (process-buffer proc))
c536bb39
SM
1273 (with-current-buffer (process-buffer proc)
1274 (let ((inhibit-read-only t))
991c70f8
RS
1275 (save-excursion
1276 (goto-char (process-mark proc))
1277 (insert-before-markers string)
7837c247 1278 (run-hooks 'compilation-filter-hook))))))
b5bb472e 1279
51ba27e7 1280(defsubst compilation-buffer-p (buffer)
7837c247
SM
1281 (local-variable-p 'compilation-locs buffer))
1282
1283(defmacro compilation-loop (< property-change 1+ error)
1284 `(while (,< n 0)
1285 (or (setq pt (,property-change pt 'message))
1286 (error ,error compilation-error))
1287 ;; prop 'message usually has 2 changes, on and off, so re-search if off
1288 (or (setq msg (get-text-property pt 'message))
1289 (if (setq pt (,property-change pt 'message))
1290 (setq msg (get-text-property pt 'message)))
1291 (error ,error compilation-error))
1292 (or (< (cadr msg) compilation-skip-threshold)
1293 (if different-file
1294 (eq (prog1 last (setq last (nth 2 (car msg))))
1295 last))
1296 (if compilation-skip-visited
1297 (nthcdr 4 (car msg)))
1298 (if compilation-skip-to-next-location
1299 (eq (car msg) loc))
1300 ;; count this message only if none of the above are true
1301 (setq n (,1+ n)))))
1302
51c8ad03 1303(defun compilation-next-error (n &optional different-file pt)
646bd331 1304 "Move point to the next error in the compilation buffer.
851231e9
DL
1305Prefix arg N says how many error messages to move forwards (or
1306backwards, if negative).
646bd331
RM
1307Does NOT find the source line like \\[next-error]."
1308 (interactive "p")
1309 (or (compilation-buffer-p (current-buffer))
851231e9 1310 (error "Not in a compilation buffer"))
51c8ad03 1311 (or pt (setq pt (point)))
646bd331 1312 (setq compilation-last-buffer (current-buffer))
51c8ad03
DP
1313 (let* ((msg (get-text-property pt 'message))
1314 (loc (car msg))
1315 last)
7837c247
SM
1316 (if (zerop n)
1317 (unless (or msg ; find message near here
c536bb39
SM
1318 (setq msg (get-text-property (max (1- pt) (point-min))
1319 'message)))
7837c247 1320 (setq pt (previous-single-property-change pt 'message nil
c536bb39 1321 (line-beginning-position)))
b3a7f48f 1322 (unless (setq msg (get-text-property (max (1- pt) (point-min)) 'message))
7837c247 1323 (setq pt (next-single-property-change pt 'message nil
c536bb39 1324 (line-end-position)))
b3a7f48f
DP
1325 (or (setq msg (get-text-property pt 'message))
1326 (setq pt (point)))))
7837c247 1327 (setq last (nth 2 (car msg)))
51c8ad03
DP
1328 (if (>= n 0)
1329 (compilation-loop > next-single-property-change 1-
1330 (if (get-buffer-process (current-buffer))
1331 "No more %ss yet"
1332 "Moved past last %s"))
c536bb39
SM
1333 ;; Don't move "back" to message at or before point.
1334 ;; Pass an explicit (point-min) to make sure pt is non-nil.
1335 (setq pt (previous-single-property-change pt 'message nil (point-min)))
51c8ad03
DP
1336 (compilation-loop < previous-single-property-change 1+
1337 "Moved back before first %s")))
7837c247
SM
1338 (goto-char pt)
1339 (or msg
1340 (error "No %s here" compilation-error))))
646bd331
RM
1341
1342(defun compilation-previous-error (n)
1343 "Move point to the previous error in the compilation buffer.
851231e9
DL
1344Prefix arg N says how many error messages to move backwards (or
1345forwards, if negative).
7837c247 1346Does NOT find the source line like \\[previous-error]."
646bd331
RM
1347 (interactive "p")
1348 (compilation-next-error (- n)))
1349
9ac57479
KS
1350(defun next-error-no-select (n)
1351 "Move point to the next error in the compilation buffer and highlight match.
24299582
DP
1352Prefix arg N says how many error messages to move forwards (or
1353backwards, if negative).
9ac57479
KS
1354Finds and highlights the source line like \\[next-error], but does not
1355select the source buffer."
1356 (interactive "p")
1357 (next-error n)
1358 (pop-to-buffer compilation-last-buffer))
1359
1360(defun previous-error-no-select (n)
6f5b7627 1361 "Move point to previous error in compilation buffer and highlight match.
24299582
DP
1362Prefix arg N says how many error messages to move backwards (or
1363forwards, if negative).
7837c247 1364Finds and highlights the source line like \\[previous-error], but does not
9ac57479
KS
1365select the source buffer."
1366 (interactive "p")
7837c247 1367 (next-error-no-select (- n)))
fc0094d7 1368
b5bb472e 1369(defun compilation-next-file (n)
24299582
DP
1370 "Move point to the next error for a different file than the current one.
1371Prefix arg N says how many files to move forwards (or backwards, if negative)."
b5bb472e 1372 (interactive "p")
7837c247 1373 (compilation-next-error n t))
b5bb472e
RM
1374
1375(defun compilation-previous-file (n)
24299582
DP
1376 "Move point to the previous error for a different file than the current one.
1377Prefix arg N says how many files to move backwards (or forwards, if negative)."
b5bb472e
RM
1378 (interactive "p")
1379 (compilation-next-file (- n)))
1380
55dfd2c4 1381(defun kill-compilation ()
b765ba64 1382 "Kill the process made by the \\[compile] or \\[grep] commands."
55dfd2c4 1383 (interactive)
d3cb357b 1384 (let ((buffer (compilation-find-buffer)))
55dfd2c4 1385 (if (get-buffer-process buffer)
d3cb357b 1386 (interrupt-process (get-buffer-process buffer))
851231e9 1387 (error "The compilation process is not running"))))
d3cb357b 1388
9da85ee5 1389(defalias 'compile-mouse-goto-error 'compile-goto-error)
c536bb39 1390
9da85ee5
SM
1391(defun compile-goto-error (&optional event)
1392 "Visit the source for the error message at point.
7837c247 1393Use this command in a compilation log buffer. Sets the mark at point there."
9da85ee5 1394 (interactive (list last-input-event))
a6cd3f65 1395 (if event (posn-set-point (event-end event)))
d3cb357b 1396 (or (compilation-buffer-p (current-buffer))
851231e9 1397 (error "Not in a compilation buffer"))
b3a7f48f
DP
1398 (if (get-text-property (point) 'directory)
1399 (dired-other-window (car (get-text-property (point) 'directory)))
1400 (push-mark)
1401 (setq compilation-current-error (point))
bfd271b5 1402 (next-error 0)))
55dfd2c4 1403
d3cb357b
RM
1404;; Return a compilation buffer.
1405;; If the current buffer is a compilation buffer, return it.
1406;; If compilation-last-buffer is set to a live buffer, use that.
1407;; Otherwise, look for a compilation buffer and signal an error
1408;; if there are none.
4746118a
JB
1409(defun compilation-find-buffer (&optional other-buffer)
1410 (if (and (not other-buffer)
1411 (compilation-buffer-p (current-buffer)))
d3cb357b
RM
1412 ;; The current buffer is a compilation buffer.
1413 (current-buffer)
4746118a 1414 (if (and compilation-last-buffer (buffer-name compilation-last-buffer)
95d219b5 1415 (compilation-buffer-p compilation-last-buffer)
4746118a
JB
1416 (or (not other-buffer) (not (eq compilation-last-buffer
1417 (current-buffer)))))
d3cb357b
RM
1418 compilation-last-buffer
1419 (let ((buffers (buffer-list)))
4746118a
JB
1420 (while (and buffers (or (not (compilation-buffer-p (car buffers)))
1421 (and other-buffer
1422 (eq (car buffers) (current-buffer)))))
d3cb357b
RM
1423 (setq buffers (cdr buffers)))
1424 (if buffers
1425 (car buffers)
4746118a
JB
1426 (or (and other-buffer
1427 (compilation-buffer-p (current-buffer))
1428 ;; The current buffer is a compilation buffer.
1429 (progn
1430 (if other-buffer
1431 (message "This is the only compilation buffer."))
1432 (current-buffer)))
1433 (error "No compilation started!")))))))
d3cb357b
RM
1434
1435;;;###autoload
24299582 1436(defun next-error (&optional n)
55dfd2c4 1437 "Visit next compilation error message and corresponding source code.
24299582
DP
1438Prefix arg N says how many error messages to move forwards (or
1439backwards, if negative).
55dfd2c4 1440
966c0a72
RS
1441\\[next-error] normally uses the most recently started compilation or
1442grep buffer. However, it can operate on any buffer with output from
1443the \\[compile] and \\[grep] commands, or, more generally, on any
1444buffer in Compilation mode or with Compilation Minor mode enabled. To
1445specify use of a particular buffer for error messages, type
1446\\[next-error] in that buffer.
55dfd2c4 1447
966c0a72
RS
1448Once \\[next-error] has chosen the buffer for error messages,
1449it stays with that buffer until you use it in some other buffer which
1450uses Compilation mode or Compilation Minor mode.
55dfd2c4 1451
7837c247
SM
1452See variable `compilation-error-regexp-alist' for customization ideas."
1453 (interactive "p")
1454 (set-buffer (setq compilation-last-buffer (compilation-find-buffer)))
1455 (let* ((columns compilation-error-screen-columns) ; buffer's local value
1456 (last 1)
51c8ad03
DP
1457 (loc (compilation-next-error (or n 1) nil
1458 (or compilation-current-error (point-min))))
7837c247
SM
1459 (end-loc (nth 2 loc))
1460 (marker (point-marker)))
51c8ad03 1461 (setq compilation-current-error (point-marker)
b3a7f48f
DP
1462 overlay-arrow-position
1463 (if (bolp)
1464 compilation-current-error
1465 (save-excursion
1466 (beginning-of-line)
1467 (point-marker)))
51c8ad03 1468 loc (car loc))
7837c247
SM
1469 ;; If loc contains no marker, no error in that file has been visited. If
1470 ;; the marker is invalid the buffer has been killed. So, recalculate all
1471 ;; markers for that file.
eb6fb6e2 1472 (unless (and (nth 3 loc) (marker-buffer (nth 3 loc)))
c536bb39
SM
1473 (with-current-buffer (compilation-find-file marker (caar (nth 2 loc))
1474 (or (cdar (nth 2 loc))
1475 default-directory))
7837c247
SM
1476 (save-restriction
1477 (widen)
c536bb39 1478 (goto-char (point-min))
7837c247
SM
1479 ;; Treat file's found lines in forward order, 1 by 1.
1480 (dolist (line (reverse (cddr (nth 2 loc))))
1481 (when (car line) ; else this is a filename w/o a line#
1482 (beginning-of-line (- (car line) last -1))
1483 (setq last (car line)))
1484 ;; Treat line's found columns and store/update a marker for each.
1485 (dolist (col (cdr line))
1486 (if (car col)
1487 (if (eq (car col) -1) ; special case for range end
1488 (end-of-line)
1489 (if columns
1490 (move-to-column (car col))
1491 (beginning-of-line)
1492 (forward-char (car col))))
1493 (beginning-of-line)
1494 (skip-chars-forward " \t"))
eb6fb6e2 1495 (if (nth 3 col)
7837c247
SM
1496 (set-marker (nth 3 col) (point))
1497 (setcdr (nthcdr 2 col) `(,(point-marker)))))))))
1498 (compilation-goto-locus marker (nth 3 loc) (nth 3 end-loc))
1499 (setcdr (nthcdr 3 loc) t))) ; Set this one as visited.
1500
eaa3cac5
RM
1501;;;###autoload (define-key ctl-x-map "`" 'next-error)
1502
24299582 1503(defun previous-error (n)
e60476ca 1504 "Visit previous compilation error message and corresponding source code.
24299582
DP
1505Prefix arg N says how many error messages to move backwards (or
1506forwards, if negative).
00c8f418
EZ
1507
1508This operates on the output from the \\[compile] and \\[grep] commands."
24299582
DP
1509 (interactive "p")
1510 (next-error (- n)))
e60476ca 1511
24299582 1512(defun first-error (n)
7837c247 1513 "Restart at the first error.
e60476ca 1514Visit corresponding source code.
24299582 1515With prefix arg N, visit the source code of the Nth error.
e60476ca 1516This operates on the output from the \\[compile] command."
7837c247
SM
1517 (interactive "p")
1518 (set-buffer (setq compilation-last-buffer (compilation-find-buffer)))
c536bb39 1519 (setq compilation-current-error nil)
24299582 1520 (next-error n))
e60476ca 1521
eb6fb6e2
DP
1522(defun compilation-fake-loc (marker file &optional line col)
1523 "Preassociate MARKER with FILE.
1524This is useful when you compile temporary files, but want
1525automatic translation of the messages to the real buffer from
1526which the temporary file came. This only works if done before a
1527message about FILE appears!
1528
1529Optional args LINE and COL default to 1 and beginning of
1530indentation respectively. The marker is expected to reflect
1531this. In the simplest case the marker points to the first line
1532of the region that was saved to the temp file.
1533
1534If you concatenate several regions into the temp file (e.g. a
1535header with variable assignments and a code region), you must
1536call this several times, once each for the last line of one
1537region and the first line of the next region."
1538 (or (consp file) (setq file (list file)))
1539 (setq file (or (gethash file compilation-locs)
1540 (puthash file (list file nil) compilation-locs)))
1541 (let ((loc (compilation-assq (or line 1) (cdr file))))
1542 (setq loc (compilation-assq col loc))
1543 (if (cdr loc)
1544 (setcdr (cddr loc) (list marker))
1545 (setcdr loc (list (or line 1) file marker)))
1546 loc))
1547
7837c247
SM
1548(defcustom compilation-context-lines next-screen-context-lines
1549 "*Display this many lines of leading context before message."
1550 :type 'integer
f6164cdd
DP
1551 :group 'compilation
1552 :version "21.4")
7837c247
SM
1553
1554(defsubst compilation-set-window (w mk)
6f5b7627 1555 "Align the compilation output window W with marker MK near top."
7837c247
SM
1556 (set-window-start w (save-excursion
1557 (goto-char mk)
1558 (beginning-of-line (- 1 compilation-context-lines))
1559 (point)))
1560 (set-window-point w mk))
1561
1562(defun compilation-goto-locus (msg mk end-mk)
6f5b7627
SM
1563 "Jump to an error corresponding to MSG at MK.
1564All arguments are markers. If END-MK is non nil, mark is set there."
d28701c7 1565 (if (eq (window-buffer (selected-window))
7837c247 1566 (marker-buffer msg))
d28701c7
RS
1567 ;; If the compilation buffer window is selected,
1568 ;; keep the compilation buffer in this window;
1569 ;; display the source in another window.
1570 (let ((pop-up-windows t))
7837c247 1571 (pop-to-buffer (marker-buffer mk)))
8f36a284 1572 (if (window-dedicated-p (selected-window))
7837c247
SM
1573 (pop-to-buffer (marker-buffer mk))
1574 (switch-to-buffer (marker-buffer mk))))
1575 ;; If narrowing gets in the way of going to the right place, widen.
1576 (unless (eq (goto-char mk) (point))
1577 (widen)
1578 (goto-char mk))
1579 (if end-mk
1580 (push-mark end-mk nil t)
1581 (if mark-active (setq mark-active)))
721cfafe
TTN
1582 ;; If hideshow got in the way of
1583 ;; seeing the right place, open permanently.
7837c247
SM
1584 (dolist (ov (overlays-at (point)))
1585 (when (eq 'hs (overlay-get ov 'invisible))
1586 (delete-overlay ov)
1587 (goto-char mk)))
eaa3cac5
RM
1588
1589 ;; Show compilation buffer in other window, scrolled to this error.
1590 (let* ((pop-up-windows t)
eae2c972 1591 ;; Use an existing window if it is in a visible frame.
7837c247 1592 (w (or (get-buffer-window (marker-buffer msg) 'visible)
eae2c972 1593 ;; Pop up a window.
7837c247
SM
1594 (display-buffer (marker-buffer msg))))
1595 (highlight-regexp (with-current-buffer (marker-buffer msg)
1596 ;; also do this while we change buffer
1597 (compilation-set-window w msg)
9ac57479 1598 compilation-highlight-regexp)))
9ac57479
KS
1599 (compilation-set-window-height w)
1600
7837c247
SM
1601 (when (and highlight-regexp
1602 (not (and end-mk transient-mark-mode)))
9ac57479 1603 (unless compilation-highlight-overlay
c536bb39
SM
1604 (setq compilation-highlight-overlay
1605 (make-overlay (point-min) (point-min)))
9ac57479 1606 (overlay-put compilation-highlight-overlay 'face 'region))
7837c247 1607 (with-current-buffer (marker-buffer mk)
9ac57479
KS
1608 (save-excursion
1609 (end-of-line)
c536bb39 1610 (let ((end (point)))
9ac57479
KS
1611 (beginning-of-line)
1612 (if (and (stringp highlight-regexp)
7837c247 1613 (re-search-forward highlight-regexp end t))
9ac57479
KS
1614 (progn
1615 (goto-char (match-beginning 0))
1616 (move-overlay compilation-highlight-overlay (match-beginning 0) (match-end 0)))
1617 (move-overlay compilation-highlight-overlay (point) end))
c536bb39 1618 (sit-for 0.5)
9ac57479
KS
1619 (delete-overlay compilation-highlight-overlay)))))))
1620
eaa3cac5 1621\f
20c1daec 1622(defun compilation-find-file (marker filename dir &rest formats)
851231e9 1623 "Find a buffer for file FILENAME.
ffb4b7a1
SM
1624Search the directories in `compilation-search-path'.
1625A nil in `compilation-search-path' means to try the
851231e9
DL
1626current directory, which is passed in DIR.
1627If FILENAME is not found at all, ask the user where to find it.
1628Pop up the buffer containing MARKER and scroll to MARKER if we ask the user."
20c1daec 1629 (or formats (setq formats '("%s")))
721cfafe
TTN
1630 (save-excursion
1631 (let ((dirs compilation-search-path)
1632 buffer thisdir fmts name)
1633 (if (file-name-absolute-p filename)
5b6858da
SM
1634 ;; The file name is absolute. Use its explicit directory as
1635 ;; the first in the search path, and strip it from FILENAME.
1636 (setq filename (abbreviate-file-name (expand-file-name filename))
1637 dirs (cons (file-name-directory filename) dirs)
1638 filename (file-name-nondirectory filename)))
721cfafe
TTN
1639 ;; Now search the path.
1640 (while (and dirs (null buffer))
1641 (setq thisdir (or (car dirs) dir)
1642 fmts formats)
1643 ;; For each directory, try each format string.
1644 (while (and fmts (null buffer))
1645 (setq name (expand-file-name (format (car fmts) filename) thisdir)
1646 buffer (and (file-exists-p name)
ffb4b7a1 1647 (find-file-noselect name))
721cfafe
TTN
1648 fmts (cdr fmts)))
1649 (setq dirs (cdr dirs)))
1650 (or buffer
7837c247
SM
1651 ;; The file doesn't exist. Ask the user where to find it.
1652 (let ((pop-up-windows t))
1653 (compilation-set-window (display-buffer (marker-buffer marker))
1654 marker)
721cfafe
TTN
1655 (let ((name (expand-file-name
1656 (read-file-name
1657 (format "Find this error in: (default %s) "
1658 filename)
1659 dir filename t))))
1660 (if (file-directory-p name)
1661 (setq name (expand-file-name filename name)))
1662 (setq buffer (and (file-exists-p name)
1663 (find-file name))))))
1664 ;; Make intangible overlays tangible.
1665 (mapcar (function (lambda (ov)
1666 (when (overlay-get ov 'intangible)
1667 (overlay-put ov 'intangible nil))))
1668 (overlays-in (point-min) (point-max)))
1669 buffer)))
1670
56ce04a3 1671(defun compilation-normalize-filename (filename)
6f5b7627 1672 "Convert FILENAME string found in an error message to make it usable."
56ce04a3
RS
1673
1674 ;; Check for a comint-file-name-prefix and prepend it if
1675 ;; appropriate. (This is very useful for
1676 ;; compilation-minor-mode in an rlogin-mode buffer.)
1677 (and (boundp 'comint-file-name-prefix)
1678 ;; If file name is relative, default-directory will
1679 ;; already contain the comint-file-name-prefix (done
1680 ;; by compile-abbreviate-directory).
1681 (file-name-absolute-p filename)
1682 (setq filename
7837c247 1683 (concat (with-no-warnings 'comint-file-name-prefix) filename)))
56ce04a3
RS
1684
1685 ;; If compilation-parse-errors-filename-function is
1686 ;; defined, use it to process the filename.
1687 (when compilation-parse-errors-filename-function
1688 (setq filename
1689 (funcall compilation-parse-errors-filename-function
1690 filename)))
1691
1692 ;; Some compilers (e.g. Sun's java compiler, reportedly)
1693 ;; produce bogus file names like "./bar//foo.c" for file
1694 ;; "bar/foo.c"; expand-file-name will collapse these into
1695 ;; "/foo.c" and fail to find the appropriate file. So we
1696 ;; look for doubled slashes in the file name and fix them
1697 ;; up in the buffer.
1698 (setq filename (command-line-normalize-file-name filename)))
d3cb357b 1699
55dfd2c4 1700
51501e54
RS
1701;; If directory DIR is a subdir of ORIG or of ORIG's parent,
1702;; return a relative name for it starting from ORIG or its parent.
1703;; ORIG-EXPANDED is an expanded version of ORIG.
1704;; PARENT-EXPANDED is an expanded version of ORIG's parent.
1705;; Those two args could be computed here, but we run faster by
1706;; having the caller compute them just once.
1707(defun compile-abbreviate-directory (dir orig orig-expanded parent-expanded)
cd494de4
RM
1708 ;; Apply canonical abbreviations to DIR first thing.
1709 ;; Those abbreviations are already done in the other arguments passed.
1710 (setq dir (abbreviate-file-name dir))
1711
1e0e614d
RM
1712 ;; Check for a comint-file-name-prefix and prepend it if appropriate.
1713 ;; (This is very useful for compilation-minor-mode in an rlogin-mode
1714 ;; buffer.)
1715 (if (boundp 'comint-file-name-prefix)
1716 (setq dir (concat comint-file-name-prefix dir)))
1717
51501e54
RS
1718 (if (and (> (length dir) (length orig-expanded))
1719 (string= orig-expanded
1720 (substring dir 0 (length orig-expanded))))
1721 (setq dir
1722 (concat orig
1723 (substring dir (length orig-expanded)))))
1724 (if (and (> (length dir) (length parent-expanded))
1725 (string= parent-expanded
1726 (substring dir 0 (length parent-expanded))))
1727 (setq dir
1728 (concat (file-name-directory
1729 (directory-file-name orig))
1730 (substring dir (length parent-expanded)))))
1731 dir)
1732
7837c247 1733(add-to-list 'debug-ignored-errors "^No more [-a-z ]+s yet$")
f1ed9461 1734
c536bb39
SM
1735;;; Compatibility with the old compile.el.
1736
1737(defun compile-buffer-substring (n) (if n (match-string n)))
1738
1739(defun compilation-compat-error-properties (err)
6f5b7627 1740 "Map old-style error ERR to new-style message."
efb0e677
SM
1741 ;; Old-style structure is (MARKER (FILE DIR) LINE COL) or
1742 ;; (MARKER . MARKER).
1743 (let ((dst (cdr err)))
1744 (if (markerp dst)
1745 ;; Must start with a face, for font-lock.
1746 `(face nil
1747 message ,(list (list nil nil nil dst) 2)
1748 help-echo "mouse-2: visit the source location"
1749 keymap compilation-button-map
1750 mouse-face highlight)
1751 ;; Too difficult to do it by hand: dispatch to the normal code.
1752 (let* ((file (pop dst))
1753 (line (pop dst))
1754 (col (pop dst))
1755 (filename (pop file))
1756 (dirname (pop file))
1757 (fmt (pop file)))
1758 (compilation-internal-error-properties
1759 (cons filename dirname) line nil col nil 2 fmt)))))
c536bb39
SM
1760
1761(defun compilation-compat-parse-errors (limit)
1762 (when compilation-parse-errors-function
1763 ;; FIXME: We should remove the rest of the compilation keywords
1764 ;; but we can't do that from here because font-lock is using
1765 ;; the value right now. --stef
1766 (save-excursion
1767 (setq compilation-error-list nil)
1768 ;; Reset compilation-parsing-end each time because font-lock
1769 ;; might force us the re-parse many times (typically because
1770 ;; some code adds some text-property to the output that we
1771 ;; already parsed). You might say "why reparse", well:
1772 ;; because font-lock has just removed the `message' property so
1773 ;; have to do it all over again.
1774 (if compilation-parsing-end
1775 (set-marker compilation-parsing-end (point))
1776 (setq compilation-parsing-end (point-marker)))
1777 (condition-case nil
1778 ;; Ignore any error: we're calling this function earlier than
1779 ;; in the old compile.el so things might not all be setup yet.
1780 (funcall compilation-parse-errors-function limit nil)
1781 (error nil))
1782 (dolist (err (if (listp compilation-error-list) compilation-error-list))
1783 (let* ((src (car err))
1784 (dst (cdr err))
1785 (loc (cond ((markerp dst) (list nil nil nil dst))
1786 ((consp dst)
1787 (list (nth 2 dst) (nth 1 dst)
1788 (cons (cdar dst) (caar dst)))))))
1789 (when loc
1790 (goto-char src)
1791 ;; (put-text-property src (line-end-position) 'font-lock-face 'font-lock-warning-face)
1792 (put-text-property src (line-end-position)
1793 'message (list loc 2)))))))
1794 (goto-char limit)
1795 nil)
1796
1797(defun compilation-forget-errors ()
1798 ;; In case we hit the same file/line specs, we want to recompute a new
1799 ;; marker for them, so flush our cache.
b3a7f48f 1800 (setq compilation-locs (make-hash-table :test 'equal :weakness 'value))
c536bb39
SM
1801 ;; FIXME: the old code reset the directory-stack, so maybe we should
1802 ;; put a `directory change' marker of some sort, but where? -stef
b3a7f48f 1803 ;;
c536bb39
SM
1804 ;; FIXME: The old code moved compilation-current-error (which was
1805 ;; virtually represented by a mix of compilation-parsing-end and
1806 ;; compilation-error-list) to point-min, but that was only meaningful for
1807 ;; the internal uses of compilation-forget-errors: all calls from external
1808 ;; packages seem to be followed by a move of compilation-parsing-end to
1809 ;; something equivalent to point-max. So we speculatively move
1810 ;; compilation-current-error to point-max (since the external package
1811 ;; won't know that it should do it). --stef
b3a7f48f 1812 (setq compilation-current-error (point-max)))
c536bb39 1813
4746118a 1814(provide 'compile)
fad160d5 1815
ab5796a9 1816;;; arch-tag: 12465727-7382-4f72-b234-79855a00dd8c
fad160d5 1817;;; compile.el ends here