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