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