Remove several obsolete vars and functions unlikely to be still in use.
[bpt/emacs.git] / lisp / progmodes / compile.el
CommitLineData
55535639 1;;; compile.el --- run compiler as inferior of Emacs, parse error messages
fad160d5 2
acaf905b 3;; Copyright (C) 1985-1987, 1993-1999, 2001-2012
049dcb6f 4;; Free Software Foundation, Inc.
3a801d0c 5
7837c247
SM
6;; Authors: Roland McGrath <roland@gnu.org>,
7;; Daniel Pfeiffer <occitan@esperanto.org>
d1c7011d 8;; Maintainer: FSF
e9571d2a 9;; Keywords: tools, processes
d1c7011d 10
55dfd2c4
RS
11;; This file is part of GNU Emacs.
12
b1fc2b50 13;; GNU Emacs is free software: you can redistribute it and/or modify
29add8b9 14;; it under the terms of the GNU General Public License as published by
b1fc2b50
GM
15;; the Free Software Foundation, either version 3 of the License, or
16;; (at your option) any later version.
29add8b9 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
b1fc2b50 24;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
55dfd2c4 25
5cc57841
ER
26;;; Commentary:
27
7837c247
SM
28;; This package provides the compile facilities documented in the Emacs user's
29;; manual.
5cc57841 30
24299582
DP
31;;; Code:
32
a464a6c7 33(eval-when-compile (require 'cl-lib))
c45e48d2 34(require 'tool-bar)
72fcf382 35(require 'comint)
583a15bb 36
c5049fa0
RS
37(defgroup compilation nil
38 "Run compiler as inferior of Emacs, parse error messages."
39 :group 'tools
40 :group 'processes)
41
42
7c163413 43;;;###autoload
c5049fa0 44(defcustom compilation-mode-hook nil
813fb3fe 45 "List of hook functions run by `compilation-mode' (see `run-mode-hooks')."
c5049fa0
RS
46 :type 'hook
47 :group 'compilation)
7c163413 48
dd93e6da
SS
49;;;###autoload
50(defcustom compilation-start-hook nil
51 "List of hook functions run by `compilation-start' on the compilation process.
52\(See `run-hook-with-args').
53If you use \"omake -P\" and do not want \\[save-buffers-kill-terminal] to ask whether you want
54the compilation to be killed, you can use this hook:
55 (add-hook 'compilation-start-hook
56 (lambda (process) (set-process-query-on-exit-flag process nil)) nil t)"
57 :type 'hook
58 :group 'compilation)
59
7c163413 60;;;###autoload
c5049fa0 61(defcustom compilation-window-height nil
813fb3fe 62 "Number of lines in a compilation window. If nil, use Emacs default."
c5049fa0
RS
63 :type '(choice (const :tag "Default" nil)
64 integer)
65 :group 'compilation)
d3cb357b 66
d9c54a06
CY
67(defvar compilation-filter-hook nil
68 "Hook run after `compilation-filter' has inserted a string into the buffer.
69It is called with the variable `compilation-filter-start' bound
70to the position of the start of the inserted text, and point at
9bedd73a
CY
71its end.
72
73If Emacs lacks asynchronous process support, this hook is run
74after `call-process' inserts the grep output into the buffer.")
d9c54a06
CY
75
76(defvar compilation-filter-start nil
34c071c6
GM
77 "Position of the start of the text inserted by `compilation-filter'.
78This is bound before running `compilation-filter-hook'.")
d9c54a06 79
7837c247 80(defvar compilation-first-column 1
fb7ada5f 81 "This is how compilers number the first column, usually 1 or 0.
83274125
GM
82If this is buffer-local in the destination buffer, Emacs obeys
83that value, otherwise it uses the value in the *compilation*
84buffer. This enables a major-mode to specify its own value.")
55dfd2c4 85
e335e194
GM
86(defvar compilation-parse-errors-filename-function nil
87 "Function to call to post-process filenames while parsing error messages.
88It takes one arg FILENAME which is the name of a file as found
89in the compilation output, and should return a transformed file name.")
90
49683a13
EZ
91;;;###autoload
92(defvar compilation-process-setup-function nil
fb7ada5f 93 "Function to call to customize the compilation process.
6f5b7627 94This function is called immediately before the compilation process is
49683a13 95started. It can be used to set any variables or functions that are used
8fe52384 96while processing the output of the compilation process.")
49683a13 97
aa228418 98;;;###autoload
d3cb357b 99(defvar compilation-buffer-name-function nil
6c43f2f9
RS
100 "Function to compute the name of a compilation buffer.
101The function receives one argument, the name of the major mode of the
102compilation buffer. It should return a string.
f441be5b 103If nil, compute the name with `(concat \"*\" (downcase major-mode) \"*\")'.")
55dfd2c4 104
aa228418 105;;;###autoload
d3cb357b 106(defvar compilation-finish-function nil
c5049fa0 107 "Function to call when a compilation process finishes.
d3cb357b 108It is called with two arguments: the compilation buffer, and a string
620d3304 109describing how the process finished.")
3c9e7f42
RS
110
111(make-obsolete-variable 'compilation-finish-function
f441be5b 112 "use `compilation-finish-functions', but it works a little differently."
3c9e7f42 113 "22.1")
55dfd2c4 114
4cc36b17
RS
115;;;###autoload
116(defvar compilation-finish-functions nil
c5049fa0 117 "Functions to call when a compilation process finishes.
4cc36b17
RS
118Each function is called with two arguments: the compilation buffer,
119and a string describing how the process finished.")
120
ebff767c
RM
121(defvar compilation-in-progress nil
122 "List of compilation processes now running.")
123(or (assq 'compilation-in-progress minor-mode-alist)
124 (setq minor-mode-alist (cons '(compilation-in-progress " Compiling")
125 minor-mode-alist)))
126
7837c247
SM
127(defvar compilation-error "error"
128 "Stem of message to print when no matches are found.")
6c43f2f9 129
58856335 130(defvar compilation-arguments nil
7837c247 131 "Arguments that were given to `compilation-start'.")
58856335 132
6c43f2f9 133(defvar compilation-num-errors-found)
d3cb357b 134
4c44026c
CY
135;; If you make any changes to `compilation-error-regexp-alist-alist',
136;; be sure to run the ERT test in test/automated/compile-tests.el.
137
331b2b90 138(defvar compilation-error-regexp-alist-alist
7837c247
SM
139 '((absoft
140 "^\\(?:[Ee]rror on \\|[Ww]arning on\\( \\)\\)?[Ll]ine[ \t]+\\([0-9]+\\)[ \t]+\
141of[ \t]+\"?\\([a-zA-Z]?:?[^\":\n]+\\)\"?:" 3 2 nil (1))
5dfa3d35 142
7837c247
SM
143 (ada
144 "\\(warning: .*\\)? at \\([^ \n]+\\):\\([0-9]+\\)$" 2 3 nil (1))
c7c5bbc0 145
7837c247
SM
146 (aix
147 " in line \\([0-9]+\\) of file \\([^ \n]+[^. \n]\\)\\.? " 2 1)
e1f540f2 148
7837c247 149 (ant
4c44026c 150 "^[ \t]*\\[[^] \n]+\\][ \t]*\\([^: \n]+\\):\\([0-9]+\\):\\(?:\\([0-9]+\\):\\([0-9]+\\):\\([0-9]+\\):\\)?\
02e5c89e 151\\( warning\\)?" 1 (2 . 4) (3 . 5) (6))
e1f540f2 152
7837c247
SM
153 (bash
154 "^\\([^: \n\t]+\\): line \\([0-9]+\\):" 1 2)
e1f540f2 155
7837c247
SM
156 (borland
157 "^\\(?:Error\\|Warnin\\(g\\)\\) \\(?:[FEW][0-9]+ \\)?\
158\\([a-zA-Z]?:?[^:( \t\n]+\\)\
159 \\([0-9]+\\)\\(?:[) \t]\\|:[^0-9\n]\\)" 2 3 nil (1))
160
60a406cf
SM
161 (python-tracebacks-and-caml
162 "^[ \t]*File \\(\"?\\)\\([^,\" \n\t<>]+\\)\\1, lines? \\([0-9]+\\)-?\\([0-9]+\\)?\\(?:$\\|,\
d9ac1a1e 163\\(?: characters? \\([0-9]+\\)-?\\([0-9]+\\)?:\\)?\\([ \n]Warning\\(?: [0-9]+\\)?:\\)?\\)"
f6164cdd 164 2 (3 . 4) (5 . 6) (7))
7837c247
SM
165
166 (comma
167 "^\"\\([^,\" \n\t]+\\)\", line \\([0-9]+\\)\
168\\(?:[(. pos]+\\([0-9]+\\))?\\)?[:.,; (-]\\( warning:\\|[-0-9 ]*(W)\\)?" 1 2 3 (4))
169
dce34635
AG
170 (cucumber
171 "\\(?:^cucumber\\(?: -p [^[:space:]]+\\)?\\|#\\)\
172\\(?: \\)\\([^\(].*\\):\\([1-9][0-9]*\\)" 1 2)
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)
4c44026c
CY
206
207
208 ;; This used to be pathologically slow on long lines (Bug#3441),
209 ;; due to matching filenames via \\(.*?\\). This might be faster.
210 (maven
211 ;; Maven is a popular free software build tool for Java.
5814f126 212 "\\([^ \n]\\(?:[^\n :]\\| [^-/\n]\\|:[^ \n]\\)*?\\):\\[\\([0-9]+\\),\\([0-9]+\\)\\] " 1 2 3)
4c44026c 213
7837c247
SM
214 (jikes-line
215 "^ *\\([0-9]+\\)\\.[ \t]+.*\n +\\(<-*>\n\\*\\*\\* \\(?:Error\\|Warnin\\(g\\)\\)\\)"
216 nil 1 nil 2 0
217 (2 (compilation-face '(3))))
218
13ef65a4
CY
219 (gcc-include
220 "^\\(?:In file included \\| \\|\t\\)from \
7c837933
AS
221\\([0-9]*[^0-9\n]\\(?:[^\n :]\\| [^-/\n]\\|:[^ \n]\\)*?\\):\
222\\([0-9]+\\)\\(?::\\([0-9]+\\)\\)?\\(?:\\(:\\)\\|\\(,\\|$\\)\\)?"
223 1 2 3 (4 . 5))
13ef65a4 224
4c44026c
CY
225 (ruby-Test::Unit
226 "^[\t ]*\\[\\([^\(].*\\):\\([1-9][0-9]*\\)\\(\\]\\)?:in " 1 2)
227
7837c247 228 (gnu
6807d8ca
CY
229 ;; The first line matches the program name for
230
231 ;; PROGRAM:SOURCE-FILE-NAME:LINENO: MESSAGE
232
233 ;; format, which is used for non-interactive programs other than
234 ;; compilers (e.g. the "jade:" entry in compilation.txt).
235
236 ;; This first line makes things ambiguous with output such as
237 ;; "foo:344:50:blabla" since the "foo" part can match this first
238 ;; line (in which case the file name as "344"). To avoid this,
239 ;; the second line disallows filenames exclusively composed of
240 ;; digits.
241
0ab31e4a
SM
242 ;; Similarly, we get lots of false positives with messages including
243 ;; times of the form "HH:MM:SS" where MM is taken as a line number, so
244 ;; the last line tries to rule out message where the info after the
245 ;; line number starts with "SS". --Stef
bb6da2f8
SM
246
247 ;; The core of the regexp is the one with *?. It says that a file name
248 ;; can be composed of any non-newline char, but it also rules out some
249 ;; valid but unlikely cases, such as a trailing space or a space
331b2b90
SM
250 ;; followed by a -, or a colon followed by a space.
251
252 ;; The "in \\|from " exception was added to handle messages from Ruby.
13ef65a4 253 "^\\(?:[[:alpha:]][-[:alnum:].]+: ?\\|[ \t]+\\(?:in \\|from \\)\\)?\
331b2b90 254\\([0-9]*[^0-9\n]\\(?:[^\n :]\\| [^-/\n]\\|:[^ \n]\\)*?\\): ?\
6c7ec171 255\\([0-9]+\\)\\(?:[.:]\\([0-9]+\\)\\)?\
721451bc 256\\(?:-\\([0-9]+\\)?\\(?:\\.\\([0-9]+\\)\\)?\\)?:\
c79598ef 257\\(?: *\\(\\(?:Future\\|Runtime\\)?[Ww]arning\\|W:\\)\\|\
d40a86f9 258 *\\([Ii]nfo\\(?:\\>\\|rmationa?l?\\)\\|I:\\|instantiated from\\|[Nn]ote\\)\\|\
c79598ef 259 *[Ee]rror\\|\[0-9]?\\(?:[^0-9\n]\\|$\\)\\|[0-9][0-9][0-9]\\)"
6c7ec171 260 1 (2 . 4) (3 . 5) (6 . 7))
7837c247
SM
261
262 (lcc
263 "^\\(?:E\\|\\(W\\)\\), \\([^(\n]+\\)(\\([0-9]+\\),[ \t]*\\([0-9]+\\)"
264 2 3 4 (1))
265
266 (makepp
250540cd 267 "^makepp\\(?:\\(?:: warning\\(:\\).*?\\|\\(: Scanning\\|: [LR]e?l?oading makefile\\|: Imported\\|log:.*?\\) \\|: .*?\\)\
3b79dd20 268`\\(\\(\\S +?\\)\\(?::\\([0-9]+\\)\\)?\\)['(]\\)"
7837c247 269 4 5 nil (1 . 2) 3
55fb9013
SM
270 (0 (progn (save-match-data
271 (compilation-parse-errors
272 (match-end 0) (line-end-position)
273 `("`\\(\\(\\S +?\\)\\(?::\\([0-9]+\\)\\)?\\)['(]"
274 2 3 nil
275 ,(cond ((match-end 1) 1) ((match-end 2) 0) (t 2))
276 1)))
277 (end-of-line)
278 nil)))
7837c247 279
6f5b7627 280 ;; Should be lint-1, lint-2 (SysV lint)
7837c247
SM
281 (mips-1
282 " (\\([0-9]+\\)) in \\([^ \n]+\\)" 2 1)
283 (mips-2
284 " in \\([^()\n ]+\\)(\\([0-9]+\\))$" 1 2)
285
286 (msft
951802d0
CY
287 ;; The message may be a "warning", "error", or "fatal error" with
288 ;; an error code, or "see declaration of" without an error code.
289 "^ *\\([0-9]+>\\)?\\(\\(?:[a-zA-Z]:\\)?[^:(\t\n]+\\)(\\([0-9]+\\)) \
290: \\(?:see declaration\\|\\(?:warnin\\(g\\)\\|[a-z ]+\\) C[0-9]+:\\)"
291 2 3 nil (4))
7837c247 292
0fdb20bb
SS
293 (omake
294 ;; "omake -P" reports "file foo changed"
295 ;; (useful if you do "cvs up" and want to see what has changed)
8fe52384
SM
296 "omake: file \\(.*\\) changed" 1 nil nil nil nil
297 ;; FIXME-omake: This tries to prevent reusing pre-existing markers
298 ;; for subsequent messages, since those messages's line numbers
299 ;; are about another version of the file.
300 (0 (progn (compilation--flush-file-structure (match-string 1))
301 nil)))
0fdb20bb 302
7837c247 303 (oracle
b3ef54c5
DP
304 "^\\(?:Semantic error\\|Error\\|PCC-[0-9]+:\\).* line \\([0-9]+\\)\
305\\(?:\\(?:,\\| at\\)? column \\([0-9]+\\)\\)?\
306\\(?:,\\| in\\| of\\)? file \\(.*?\\):?$"
7837c247 307 3 1 2)
40d63d1f 308
049dcb6f
GM
309 ;; "during global destruction": This comes out under "use
310 ;; warnings" in recent perl when breaking circular references
311 ;; during program or thread exit.
7837c247 312 (perl
049dcb6f
GM
313 " at \\([^ \n]+\\) line \\([0-9]+\\)\\(?:[,.]\\|$\\| \
314during global destruction\\.$\\)" 1 2)
7837c247 315
fa2a4e7d
MH
316 (php
317 "\\(?:Parse\\|Fatal\\) error: \\(.*\\) in \\(.*\\) on line \\([0-9]+\\)"
318 2 3 nil nil)
319
7837c247
SM
320 (rxp
321 "^\\(?:Error\\|Warnin\\(g\\)\\):.*\n.* line \\([0-9]+\\) char\
322 \\([0-9]+\\) of file://\\(.+\\)"
323 4 2 3 (1))
324
325 (sparc-pascal-file
326 "^\\w\\w\\w \\w\\w\\w +[0-3]?[0-9] +[0-2][0-9]:[0-5][0-9]:[0-5][0-9]\
327 [12][09][0-9][0-9] +\\(.*\\):$"
328 1 nil nil 0)
329 (sparc-pascal-line
330 "^\\(\\(?:E\\|\\(w\\)\\) +[0-9]+\\) line \\([0-9]+\\) - "
331 nil 3 nil (2) nil (1 (compilation-face '(2))))
332 (sparc-pascal-example
333 "^ +\\([0-9]+\\) +.*\n\\(\\(?:e\\|\\(w\\)\\) [0-9]+\\)-+"
334 nil 1 nil (3) nil (2 (compilation-face '(3))))
335
336 (sun
6f5b7627 337 ": \\(?:ERROR\\|WARNIN\\(G\\)\\|REMAR\\(K\\)\\) \\(?:[[:alnum:] ]+, \\)?\
7837c247
SM
338File = \\(.+\\), Line = \\([0-9]+\\)\\(?:, Column = \\([0-9]+\\)\\)?"
339 3 4 5 (1 . 2))
340
341 (sun-ada
342 "^\\([^, \n\t]+\\), line \\([0-9]+\\), char \\([0-9]+\\)[:., \(-]" 1 2 3)
343
9d8a1add 344 (watcom
3e39928c 345 "^[ \t]*\\(\\(?:[a-zA-Z]:\\)?[^:(\t\n]+\\)(\\([0-9]+\\)): ?\
ed66ce21
CY
346\\(?:\\(Error! E[0-9]+\\)\\|\\(Warning! W[0-9]+\\)\\):"
347 1 2 nil (4))
9d8a1add 348
7837c247
SM
349 (4bsd
350 "\\(?:^\\|:: \\|\\S ( \\)\\(/[^ \n\t()]+\\)(\\([0-9]+\\))\
0c9a01ff
MY
351\\(?:: \\(warning:\\)?\\|$\\| ),\\)" 1 2 nil (3))
352
353 (gcov-file
b8fa0ffd 354 "^ *-: *\\(0\\):Source:\\(.+\\)$"
55fb9013 355 2 1 nil 0 nil)
eb3d9609
MY
356 (gcov-header
357 "^ *-: *\\(0\\):\\(?:Object\\|Graph\\|Data\\|Runs\\|Programs\\):.+$"
55fb9013 358 nil 1 nil 0 nil)
eb3d9609
MY
359 ;; Underlines over all lines of gcov output are too uncomfortable to read.
360 ;; However, hyperlinks embedded in the lines are useful.
361 ;; So I put default face on the lines; and then put
362 ;; compilation-*-face by manually to eliminate the underlines.
363 ;; The hyperlinks are still effective.
364 (gcov-nomark
365 "^ *-: *\\([1-9]\\|[0-9]\\{2,\\}\\):.*$"
366 nil 1 nil 0 nil
55fb9013
SM
367 (0 'default)
368 (1 compilation-line-face))
0c9a01ff 369 (gcov-called-line
eb3d9609 370 "^ *\\([0-9]+\\): *\\([0-9]+\\):.*$"
b8fa0ffd 371 nil 2 nil 0 nil
55fb9013
SM
372 (0 'default)
373 (1 compilation-info-face) (2 compilation-line-face))
eb3d9609 374 (gcov-never-called
b8fa0ffd 375 "^ *\\(#####\\): *\\([0-9]+\\):.*$"
eb3d9609 376 nil 2 nil 2 nil
55fb9013
SM
377 (0 'default)
378 (1 compilation-error-face) (2 compilation-line-face))
ddab7705 379
3dc4febd 380 (perl--Pod::Checker
ddab7705
VJL
381 ;; podchecker error messages, per Pod::Checker.
382 ;; The style is from the Pod::Checker::poderror() function, eg.
383 ;; *** ERROR: Spurious text after =cut at line 193 in file foo.pm
384 ;;
385 ;; Plus end_pod() can give "at line EOF" instead of a
386 ;; number, so for that match "on line N" which is the
387 ;; originating spot, eg.
388 ;; *** ERROR: =over on line 37 without closing =back at line EOF in file bar.pm
389 ;;
390 ;; Plus command() can give both "on line N" and "at line N";
391 ;; the latter is desired and is matched because the .* is
392 ;; greedy.
393 ;; *** ERROR: =over on line 1 without closing =back (at head1) at line 3 in file x.pod
394 ;;
395 "^\\*\\*\\* \\(?:ERROR\\|\\(WARNING\\)\\).* \\(?:at\\|on\\) line \
396\\([0-9]+\\) \\(?:.* \\)?in file \\([^ \t\n]+\\)"
397 3 2 nil (1))
3dc4febd 398 (perl--Test
ddab7705
VJL
399 ;; perl Test module error messages.
400 ;; Style per the ok() function "$context", eg.
401 ;; # Failed test 1 in foo.t at line 6
402 ;;
403 "^# Failed test [0-9]+ in \\([^ \t\r\n]+\\) at line \\([0-9]+\\)"
404 1 2)
3dc4febd 405 (perl--Test2
6cbbc20c 406 ;; Or when comparing got/want values, with a "fail #n" if repeated
01f179de 407 ;; # Test 2 got: "xx" (t-compilation-perl-2.t at line 10)
6cbbc20c 408 ;; # Test 3 got: "xx" (t-compilation-perl-2.t at line 10 fail #2)
01f179de
GM
409 ;;
410 ;; And under Test::Harness they're preceded by progress stuff with
411 ;; \r and "NOK",
412 ;; ... NOK 1# Test 1 got: "1234" (t/foo.t at line 46)
413 ;;
414 "^\\(.*NOK.*\\)?# Test [0-9]+ got:.* (\\([^ \t\r\n]+\\) at line \
6cbbc20c 415\\([0-9]+\\)\\( fail #[0-9]+\\)?)"
01f179de 416 2 3)
3dc4febd 417 (perl--Test::Harness
ddab7705
VJL
418 ;; perl Test::Harness output, eg.
419 ;; NOK 1# Test 1 got: "1234" (t/foo.t at line 46)
420 ;;
421 ;; Test::Harness is slightly designed for tty output, since
422 ;; it prints CRs to overwrite progress messages, but if you
423 ;; run it in with M-x compile this pattern can at least step
424 ;; through the failures.
425 ;;
426 "^.*NOK.* \\([^ \t\r\n]+\\) at line \\([0-9]+\\)"
427 1 2)
3dc4febd 428 (weblint
ddab7705
VJL
429 ;; The style comes from HTML::Lint::Error::as_string(), eg.
430 ;; index.html (13:1) Unknown element <fdjsk>
431 ;;
432 ;; The pattern only matches filenames without spaces, since that
433 ;; should be usual and should help reduce the chance of a false
434 ;; match of a message from some unrelated program.
435 ;;
436 ;; This message style is quite close to the "ibm" entry which is
437 ;; for IBM C, though that ibm bit doesn't put a space after the
438 ;; filename.
439 ;;
440 "^\\([^ \t\r\n(]+\\) (\\([0-9]+\\):\\([0-9]+\\)) "
441 1 2 3)
eb3d9609 442 )
7837c247
SM
443 "Alist of values for `compilation-error-regexp-alist'.")
444
445(defcustom compilation-error-regexp-alist
446 (mapcar 'car compilation-error-regexp-alist-alist)
6c43f2f9 447 "Alist that specifies how to match errors in compiler output.
7957baea 448On GNU and Unix, any string is a valid filename, so these
7837c247
SM
449matchers must make some common sense assumptions, which catch
450normal cases. A shorter list will be lighter on resource usage.
451
452Instead of an alist element, you can use a symbol, which is
453looked up in `compilation-error-regexp-alist-alist'. You can see
454the predefined symbols and their effects in the file
6f5b7627 455`etc/compilation.txt' (linked below if you are customizing this).
7837c247
SM
456
457Each elt has the form (REGEXP FILE [LINE COLUMN TYPE HYPERLINK
458HIGHLIGHT...]). If REGEXP matches, the FILE'th subexpression
459gives the file name, and the LINE'th subexpression gives the line
460number. The COLUMN'th subexpression gives the column number on
461that line.
462
463If FILE, LINE or COLUMN are nil or that index didn't match, that
464information is not present on the matched line. In that case the
465file name is assumed to be the same as the previous one in the
466buffer, line number defaults to 1 and column defaults to
467beginning of line's indentation.
468
469FILE can also have the form (FILE FORMAT...), where the FORMATs
470\(e.g. \"%s.c\") will be applied in turn to the recognized file
471name, until a file of that name is found. Or FILE can also be a
4aede2f2
RS
472function that returns (FILENAME) or (RELATIVE-FILENAME . DIRNAME).
473In the former case, FILENAME may be relative or absolute.
7837c247
SM
474
475LINE can also be of the form (LINE . END-LINE) meaning a range
476of lines. COLUMN can also be of the form (COLUMN . END-COLUMN)
477meaning a range of columns starting on LINE and ending on
478END-LINE, if that matched.
479
480TYPE is 2 or nil for a real error or 1 for warning or 0 for info.
481TYPE can also be of the form (WARNING . INFO). In that case this
482will be equivalent to 1 if the WARNING'th subexpression matched
483or else equivalent to 0 if the INFO'th subexpression matched.
484See `compilation-error-face', `compilation-warning-face',
485`compilation-info-face' and `compilation-skip-threshold'.
486
487What matched the HYPERLINK'th subexpression has `mouse-face' and
488`compilation-message-face' applied. If this is nil, the text
489matched by the whole REGEXP becomes the hyperlink.
490
c584eaf9
CY
491Additional HIGHLIGHTs take the shape (SUBMATCH FACE), where
492SUBMATCH is the number of a submatch and FACE is an expression
f1be615c
CY
493which evaluates to a face name (a symbol or string).
494Alternatively, FACE can evaluate to a property list of the
495form (face FACE PROP1 VAL1 PROP2 VAL2 ...), in which case all the
496listed text properties PROP# are given values VAL# as well."
d00b05c9
GM
497 :type '(repeat (choice (symbol :tag "Predefined symbol")
498 (sexp :tag "Error specification")))
7837c247 499 :link `(file-link :tag "example file"
eeb3ede4 500 ,(expand-file-name "compilation.txt" data-directory))
7837c247 501 :group 'compilation)
55dfd2c4 502
98d4c36f 503;;;###autoload(put 'compilation-directory 'safe-local-variable 'stringp)
ebb8cb68
EZ
504(defvar compilation-directory nil
505 "Directory to restore to when doing `recompile'.")
506
7837c247
SM
507(defvar compilation-directory-matcher
508 '("\\(?:Entering\\|Leavin\\(g\\)\\) directory `\\(.+\\)'$" (2 . 1))
509 "A list for tracking when directories are entered or left.
434520fa 510If nil, do not track directories, e.g. if all file names are absolute. The
7837c247
SM
511first element is the REGEXP matching these messages. It can match any number
512of variants, e.g. different languages. The remaining elements are all of the
513form (DIR . LEAVE). If for any one of these the DIR'th subexpression
514matches, that is a directory name. If LEAVE is nil or the corresponding
515LEAVE'th subexpression doesn't match, this message is about going into another
516directory. If it does match anything, this message is about going back to the
517directory we were in before the last entering message. If you change this,
518you may also want to change `compilation-page-delimiter'.")
519
520(defvar compilation-page-delimiter
521 "^\\(?:\f\\|.*\\(?:Entering\\|Leaving\\) directory `.+'\n\\)+"
522 "Value of `page-delimiter' in Compilation mode.")
523
524(defvar compilation-mode-font-lock-keywords
0ab31e4a 525 '(;; configure output lines.
7837c247
SM
526 ("^[Cc]hecking \\(?:[Ff]or \\|[Ii]f \\|[Ww]hether \\(?:to \\)?\\)?\\(.+\\)\\.\\.\\. *\\(?:(cached) *\\)?\\(\\(yes\\(?: .+\\)?\\)\\|no\\|\\(.*\\)\\)$"
527 (1 font-lock-variable-name-face)
38dbf92b 528 (2 (compilation-face '(4 . 3))))
7837c247 529 ;; Command output lines. Recognize `make[n]:' lines too.
6f5b7627 530 ("^\\([[:alnum:]_/.+-]+\\)\\(\\[\\([0-9]+\\)\\]\\)?[ \t]*:"
7837c247 531 (1 font-lock-function-name-face) (3 compilation-line-face nil t))
56ee679c 532 (" --?o\\(?:utfile\\|utput\\)?[= ]\\(\\S +\\)" . 1)
47f97084 533 ("^Compilation \\(finished\\).*"
07b741a7 534 (0 '(face nil compilation-message nil help-echo nil mouse-face nil) t)
314b410b 535 (1 compilation-info-face))
0ab31e4a 536 ("^Compilation \\(exited abnormally\\|interrupt\\|killed\\|terminated\\|segmentation fault\\)\\(?:.*with code \\([0-9]+\\)\\)?.*"
07b741a7 537 (0 '(face nil compilation-message nil help-echo nil mouse-face nil) t)
314b410b
JL
538 (1 compilation-error-face)
539 (2 compilation-error-face nil t)))
7837c247
SM
540 "Additional things to highlight in Compilation mode.
541This gets tacked on the end of the generated expressions.")
a24770bc 542
9ac57479
KS
543(defvar compilation-highlight-regexp t
544 "Regexp matching part of visited source lines to highlight temporarily.
545Highlight entire line if t; don't highlight source lines if nil.")
546
547(defvar compilation-highlight-overlay nil
548 "Overlay used to temporarily highlight compilation matches.")
549
f8e03ecb 550(defcustom compilation-error-screen-columns t
813fb3fe 551 "If non-nil, column numbers in error messages are screen columns.
f8e03ecb
AS
552Otherwise they are interpreted as character positions, with
553each character occupying one column.
554The default is to use screen columns, which requires that the compilation
555program and Emacs agree about the display width of the characters,
83274125
GM
556especially the TAB character.
557If this is buffer-local in the destination buffer, Emacs obeys
558that value, otherwise it uses the value in the *compilation*
559buffer. This enables a major-mode to specify its own value."
f8e03ecb
AS
560 :type 'boolean
561 :group 'compilation
562 :version "20.4")
563
c5049fa0 564(defcustom compilation-read-command t
813fb3fe 565 "Non-nil means \\[compile] reads the compilation command to use.
4d9bbfa6
CY
566Otherwise, \\[compile] just uses the value of `compile-command'.
567
568Note that changing this to nil may be a security risk, because a
569file might define a malicious `compile-command' as a file local
570variable, and you might not notice. Therefore, `compile-command'
571is considered unsafe if this variable is nil."
c5049fa0
RS
572 :type 'boolean
573 :group 'compilation)
90016295 574
e83be080 575;;;###autoload
c5049fa0 576(defcustom compilation-ask-about-save t
813fb3fe 577 "Non-nil means \\[compile] asks which buffers to save before compiling.
c5049fa0
RS
578Otherwise, it saves all modified buffers without asking."
579 :type 'boolean
580 :group 'compilation)
90016295 581
9e86ab0b
SS
582(defcustom compilation-save-buffers-predicate nil
583 "The second argument (PRED) passed to `save-some-buffers' before compiling.
584E.g., one can set this to
585 (lambda ()
586 (string-prefix-p my-compilation-root (file-truename (buffer-file-name))))
587to limit saving to files located under `my-compilation-root'.
588Note, that, in general, `compilation-directory' cannot be used instead
589of `my-compilation-root' here."
590 :type '(choice
591 (const :tag "Default (save all file-visiting buffers)" nil)
592 (const :tag "Save all buffers" t)
593 function)
ba33df00
GM
594 :group 'compilation
595 :version "24.1")
9e86ab0b 596
7c163413 597;;;###autoload
c5049fa0 598(defcustom compilation-search-path '(nil)
813fb3fe 599 "List of directories to search for source files named in error messages.
d3cb357b 600Elements should be directory names, not file names of directories.
f441be5b 601The value nil as an element means to try the default directory."
c5049fa0
RS
602 :type '(repeat (choice (const :tag "Default" nil)
603 (string :tag "Directory")))
604 :group 'compilation)
55dfd2c4 605
7957baea 606;;;###autoload
aaa448c9 607(defcustom compile-command (purecopy "make -k ")
813fb3fe 608 "Last shell command used to do a compilation; default for next compilation.
55dfd2c4
RS
609
610Sometimes it is useful for files to supply local values for this variable.
611You might also use mode hooks to specify it in certain modes, like this:
612
61c4aaf8 613 (add-hook 'c-mode-hook
61c4aaf8
RS
614 (lambda ()
615 (unless (or (file-exists-p \"makefile\")
616 (file-exists-p \"Makefile\"))
5b6858da
SM
617 (set (make-local-variable 'compile-command)
618 (concat \"make -k \"
7837c247 619 (file-name-sans-extension buffer-file-name))))))"
c5049fa0
RS
620 :type 'string
621 :group 'compilation)
fa7b5f7b 622;;;###autoload(put 'compile-command 'safe-local-variable (lambda (a) (and (stringp a) (or (not (boundp 'compilation-read-command)) compilation-read-command))))
55dfd2c4 623
7957baea 624;;;###autoload
93ef35e4 625(defcustom compilation-disable-input nil
813fb3fe 626 "If non-nil, send end-of-file as compilation process input.
3fa37cd1 627This only affects platforms that support asynchronous processes (see
bac3a1c9 628`start-process'); synchronous compilation processes never accept input."
3fa37cd1
EZ
629 :type 'boolean
630 :group 'compilation
631 :version "22.1")
632
7837c247
SM
633;; A weak per-compilation-buffer hash indexed by (FILENAME . DIRECTORY). Each
634;; value is a FILE-STRUCTURE as described above, with the car eq to the hash
4fffd73b 635;; key. This holds the tree seen from root, for storing new nodes.
7837c247
SM
636(defvar compilation-locs ())
637
638(defvar compilation-debug nil
fb7ada5f 639 "Set this to t before creating a *compilation* buffer.
7837c247
SM
640Then every error line will have a debug text property with the matcher that
641fit this line and the match data. Use `describe-text-properties'.")
d3cb357b 642
01f89d11
RM
643(defvar compilation-exit-message-function nil "\
644If non-nil, called when a compilation process dies to return a status message.
fd5e58d7
RM
645This should be a function of three arguments: process status, exit status,
646and exit message; it returns a cons (MESSAGE . MODELINE) of the strings to
647write into the compilation buffer, and to put in its mode line.")
01f89d11 648
97f05794
JL
649(defcustom compilation-environment nil
650 "List of environment variables for compilation to inherit.
c20f961b
JPW
651Each element should be a string of the form ENVVARNAME=VALUE.
652This list is temporarily prepended to `process-environment' prior to
97f05794
JL
653starting the compilation process."
654 :type '(repeat (string :tag "ENVVARNAME=VALUE"))
655 :options '(("LANG=C"))
656 :group 'compilation
657 :version "24.1")
c20f961b 658
770970cb
RS
659;; History of compile commands.
660(defvar compile-history nil)
770970cb 661
fa947ef3 662(defface compilation-error
bc987f8b 663 '((t :inherit error))
fa947ef3 664 "Face used to highlight compiler errors."
da742205 665 :group 'compilation
fa947ef3
JL
666 :version "22.1")
667
541a6d0d 668(defface compilation-warning
bc987f8b 669 '((t :inherit warning))
7837c247 670 "Face used to highlight compiler warnings."
da742205 671 :group 'compilation
bf247b6e 672 :version "22.1")
7837c247 673
541a6d0d 674(defface compilation-info
bc987f8b 675 '((t :inherit success))
fa947ef3 676 "Face used to highlight compiler information."
da742205 677 :group 'compilation
bf247b6e 678 :version "22.1")
7837c247 679
5205d6f6
CY
680;; The next three faces must be able to stand out against the
681;; `mode-line' and `mode-line-inactive' faces.
682
683(defface compilation-mode-line-fail
684 '((default :inherit compilation-error)
685 (((class color) (min-colors 16)) (:foreground "Red1" :weight bold))
686 (((class color) (min-colors 8)) (:foreground "red"))
687 (t (:inverse-video t :weight bold)))
688 "Face for Compilation mode's \"error\" mode line indicator."
689 :group 'compilation
2a1e2476 690 :version "24.3")
5205d6f6
CY
691
692(defface compilation-mode-line-run
693 '((t :inherit compilation-warning))
694 "Face for Compilation mode's \"running\" mode line indicator."
695 :group 'compilation
2a1e2476 696 :version "24.3")
5205d6f6
CY
697
698(defface compilation-mode-line-exit
699 '((default :inherit compilation-info)
700 (((class color) (min-colors 16))
701 (:foreground "ForestGreen" :weight bold))
702 (((class color)) (:foreground "green" :weight bold))
703 (t (:weight bold)))
704 "Face for Compilation mode's \"exit\" mode line indicator."
705 :group 'compilation
2a1e2476 706 :version "24.3")
5205d6f6 707
a5f1c37e 708(defface compilation-line-number
90db975f 709 '((t :inherit font-lock-keyword-face))
fa947ef3 710 "Face for displaying line numbers in compiler messages."
da742205 711 :group 'compilation
a5f1c37e
RS
712 :version "22.1")
713
714(defface compilation-column-number
90db975f 715 '((t :inherit font-lock-doc-face))
fa947ef3 716 "Face for displaying column numbers in compiler messages."
da742205 717 :group 'compilation
a5f1c37e
RS
718 :version "22.1")
719
f4beca06 720(defcustom compilation-message-face 'underline
7837c247
SM
721 "Face name to use for whole messages.
722Faces `compilation-error-face', `compilation-warning-face',
723`compilation-info-face', `compilation-line-face' and
f4beca06
RS
724`compilation-column-face' get prepended to this, when applicable."
725 :type 'face
726 :group 'compilation
727 :version "22.1")
7837c247 728
38dbf92b 729(defvar compilation-error-face 'compilation-error
7837c247
SM
730 "Face name to use for file name in error messages.")
731
38dbf92b 732(defvar compilation-warning-face 'compilation-warning
7837c247
SM
733 "Face name to use for file name in warning messages.")
734
38dbf92b 735(defvar compilation-info-face 'compilation-info
7837c247
SM
736 "Face name to use for file name in informational messages.")
737
a5f1c37e 738(defvar compilation-line-face 'compilation-line-number
38dbf92b 739 "Face name to use for line numbers in compiler messages.")
7837c247 740
a5f1c37e 741(defvar compilation-column-face 'compilation-column-number
fa947ef3 742 "Face name to use for column numbers in compiler messages.")
7837c247
SM
743
744;; same faces as dired uses
745(defvar compilation-enter-directory-face 'font-lock-function-name-face
fa947ef3 746 "Face name to use for entering directory messages.")
7837c247 747
90db975f 748(defvar compilation-leave-directory-face 'font-lock-builtin-face
fa947ef3 749 "Face name to use for leaving directory messages.")
7837c247 750
c536bb39 751;; Used for compatibility with the old compile.el.
c536bb39 752(defvar compilation-parse-errors-function nil)
a5f2b6ec
CY
753(make-obsolete-variable 'compilation-parse-errors-function
754 'compilation-error-regexp-alist "24.1")
c536bb39 755
813fb3fe 756(defcustom compilation-auto-jump-to-first-error nil
6cc725cd 757 "If non-nil, automatically jump to the first error during compilation."
765831a0
DN
758 :type 'boolean
759 :group 'compilation
760 :version "23.1")
813fb3fe
SM
761
762(defvar compilation-auto-jump-to-next nil
763 "If non-nil, automatically jump to the next error encountered.")
764(make-variable-buffer-local 'compilation-auto-jump-to-next)
765
8fe52384
SM
766;; (defvar compilation-buffer-modtime nil
767;; "The buffer modification time, for buffers not associated with files.")
768;; (make-variable-buffer-local 'compilation-buffer-modtime)
97546017
DN
769
770(defvar compilation-skip-to-next-location t
fb7ada5f 771 "If non-nil, skip multiple error messages for the same source location.")
97546017
DN
772
773(defcustom compilation-skip-threshold 1
774 "Compilation motion commands skip less important messages.
775The value can be either 2 -- skip anything less than error, 1 --
776skip anything less than warning or 0 -- don't skip any messages.
777Note that all messages not positively identified as warning or
778info, are considered errors."
331b2b90
SM
779 :type '(choice (const :tag "Skip warnings and info" 2)
780 (const :tag "Skip info" 1)
781 (const :tag "No skip" 0))
97546017
DN
782 :group 'compilation
783 :version "22.1")
784
331b2b90
SM
785(defun compilation-set-skip-threshold (level)
786 "Switch the `compilation-skip-threshold' level."
787 (interactive
788 (list
789 (mod (if current-prefix-arg
790 (prefix-numeric-value current-prefix-arg)
791 (1+ compilation-skip-threshold))
792 3)))
793 (setq compilation-skip-threshold level)
794 (message "Skipping %s"
a464a6c7 795 (pcase compilation-skip-threshold
331b2b90
SM
796 (0 "Nothing")
797 (1 "Info messages")
798 (2 "Warnings and info"))))
799
97546017
DN
800(defcustom compilation-skip-visited nil
801 "Compilation motion commands skip visited messages if this is t.
802Visited messages are ones for which the file, line and column have been jumped
803to from the current content in the current compilation buffer, even if it was
804from a different message."
805 :type 'boolean
806 :group 'compilation
807 :version "22.1")
808
7837c247
SM
809(defun compilation-face (type)
810 (or (and (car type) (match-end (car type)) compilation-warning-face)
811 (and (cdr type) (match-end (cdr type)) compilation-info-face)
812 compilation-error-face))
813
8fe52384
SM
814;; LOC (or location) is a list of (COLUMN LINE FILE-STRUCTURE nil nil)
815
816;; COLUMN and LINE are numbers parsed from an error message. COLUMN and maybe
817;; LINE will be nil for a message that doesn't contain them. Then the
818;; location refers to a indented beginning of line or beginning of file.
819;; Once any location in some file has been jumped to, the list is extended to
820;; (COLUMN LINE FILE-STRUCTURE MARKER TIMESTAMP . VISITED)
821;; for all LOCs pertaining to that file.
822;; MARKER initially points to LINE and COLUMN in a buffer visiting that file.
823;; Being a marker it sticks to some text, when the buffer grows or shrinks
824;; before that point. VISITED is t if we have jumped there, else nil.
825;; FIXME-omake: TIMESTAMP was used to try and handle "incremental compilation":
826;; `omake -P' polls filesystem for changes and recompiles when a file is
827;; modified using the same *compilation* buffer. this necessitates
828;; re-parsing markers.
829
a464a6c7 830;; (cl-defstruct (compilation--loc
8fe52384
SM
831;; (:constructor nil)
832;; (:copier nil)
833;; (:constructor compilation--make-loc
834;; (file-struct line col marker))
835;; (:conc-name compilation--loc->))
836;; col line file-struct marker timestamp visited)
837
838;; FIXME: We don't use a defstruct because of compilation-assq which looks up
839;; and creates part of the LOC (only the first cons cell containing the COL).
840
841(defmacro compilation--make-cdrloc (line file-struct marker)
842 `(list ,line ,file-struct ,marker nil))
843(defmacro compilation--loc->col (loc) `(car ,loc))
844(defmacro compilation--loc->line (loc) `(cadr ,loc))
845(defmacro compilation--loc->file-struct (loc) `(nth 2 ,loc))
846(defmacro compilation--loc->marker (loc) `(nth 3 ,loc))
847;; (defmacro compilation--loc->timestamp (loc) `(nth 4 ,loc))
848(defmacro compilation--loc->visited (loc) `(nthcdr 5 ,loc))
849
850;; FILE-STRUCTURE is a list of
851;; ((FILENAME DIRECTORY) FORMATS (LINE LOC ...) ...)
852
853;; FILENAME is a string parsed from an error message. DIRECTORY is a string
854;; obtained by following directory change messages. DIRECTORY will be nil for
855;; an absolute filename. FORMATS is a list of formats to apply to FILENAME if
856;; a file of that name can't be found.
857;; The rest of the list is an alist of elements with LINE as key. The keys
858;; are either nil or line numbers. If present, nil comes first, followed by
859;; the numbers in decreasing order. The LOCs for each line are again an alist
860;; ordered the same way. Note that the whole file structure is referenced in
861;; every LOC.
862
863(defmacro compilation--make-file-struct (file-spec formats &optional loc-tree)
864 `(cons ,file-spec (cons ,formats ,loc-tree)))
865(defmacro compilation--file-struct->file-spec (fs) `(car ,fs))
866(defmacro compilation--file-struct->formats (fs) `(cadr ,fs))
867;; The FORMATS field plays the role of ANCHOR in the loc-tree.
868(defmacro compilation--file-struct->loc-tree (fs) `(cdr ,fs))
869
870;; MESSAGE is a list of (LOC TYPE END-LOC)
871
872;; TYPE is 0 for info or 1 for warning if the message matcher identified it as
873;; such, 2 otherwise (for a real error). END-LOC is a LOC pointing to the
874;; other end, if the parsed message contained a range. If the end of the
875;; range didn't specify a COLUMN, it defaults to -1, meaning end of line.
876;; These are the value of the `compilation-message' text-properties in the
877;; compilation buffer.
878
a464a6c7 879(cl-defstruct (compilation--message
8fe52384
SM
880 (:constructor nil)
881 (:copier nil)
882 ;; (:type list) ;Old representation.
883 (:constructor compilation--make-message (loc type end-loc))
884 (:conc-name compilation--message->))
885 loc type end-loc)
886
9e11271c
SM
887(defvar compilation--previous-directory-cache nil
888 "A pair (POS . RES) caching the result of previous directory search.
889Basically, this pair says that calling
890 (previous-single-property-change POS 'compilation-directory)
891returned RES, i.e. there is no change of `compilation-directory' between
892POS and RES.")
e52f87a1 893(make-variable-buffer-local 'compilation--previous-directory-cache)
9e11271c 894
e02f48d7 895(defun compilation--flush-directory-cache (start _end)
9e11271c
SM
896 (cond
897 ((or (not compilation--previous-directory-cache)
898 (<= (car compilation--previous-directory-cache) start)))
899 ((or (not (cdr compilation--previous-directory-cache))
3ab713fd 900 (null (marker-buffer (cdr compilation--previous-directory-cache)))
9e11271c
SM
901 (<= (cdr compilation--previous-directory-cache) start))
902 (set-marker (car compilation--previous-directory-cache) start))
903 (t (setq compilation--previous-directory-cache nil))))
904
e52f87a1
SM
905(defun compilation--previous-directory (pos)
906 "Like (previous-single-property-change POS 'compilation-directory), but faster."
907 ;; This avoids an N² behavior when there's no/few compilation-directory
908 ;; entries, in which case each call to previous-single-property-change
909 ;; ends up having to walk very far back to find the last change.
9e11271c
SM
910 (if (and compilation--previous-directory-cache
911 (< pos (car compilation--previous-directory-cache))
1dc4075f
SM
912 (or (null (cdr compilation--previous-directory-cache))
913 (< (cdr compilation--previous-directory-cache) pos)))
9e11271c
SM
914 ;; No need to call previous-single-property-change.
915 (cdr compilation--previous-directory-cache)
abef340a 916
9e11271c
SM
917 (let* ((cache (and compilation--previous-directory-cache
918 (<= (car compilation--previous-directory-cache) pos)
919 (car compilation--previous-directory-cache)))
920 (prev
921 (previous-single-property-change
94642599
SM
922 pos 'compilation-directory nil cache))
923 (res
924 (cond
925 ((null cache)
926 (setq compilation--previous-directory-cache
927 (cons (copy-marker pos) (if prev (copy-marker prev))))
928 prev)
929 ((and prev (= prev cache))
930 (if cache
931 (set-marker (car compilation--previous-directory-cache) pos)
932 (setq compilation--previous-directory-cache
933 (cons (copy-marker pos) nil)))
934 (cdr compilation--previous-directory-cache))
935 (t
936 (if cache
937 (progn
938 (set-marker cache pos)
939 (setcdr compilation--previous-directory-cache
940 (copy-marker prev)))
941 (setq compilation--previous-directory-cache
942 (cons (copy-marker pos) (if prev (copy-marker prev)))))
943 prev))))
944 (if (markerp res) (marker-position res) res))))
e52f87a1 945
deda0c65 946;; Internal function for calculating the text properties of a directory
8fe52384
SM
947;; change message. The compilation-directory property is important, because it
948;; is the stack of nested enter-messages. Relative filenames on the following
deda0c65 949;; lines are relative to the top of the stack.
7837c247
SM
950(defun compilation-directory-properties (idx leave)
951 (if leave (setq leave (match-end leave)))
952 ;; find previous stack, and push onto it, or if `leave' pop it
94642599 953 (let ((dir (compilation--previous-directory (match-beginning 0))))
07b741a7
SM
954 (setq dir (if dir (or (get-text-property (1- dir) 'compilation-directory)
955 (get-text-property dir 'compilation-directory))))
55fb9013
SM
956 `(font-lock-face ,(if leave
957 compilation-leave-directory-face
958 compilation-enter-directory-face)
07b741a7
SM
959 compilation-directory ,(if leave
960 (or (cdr dir)
961 '(nil)) ; nil only isn't a property-change
962 (cons (match-string-no-properties idx) dir))
55fb9013
SM
963 ;; Place a `compilation-message' everywhere we change text-properties
964 ;; so compilation--remove-properties can know what to remove.
965 compilation-message ,(compilation--make-message nil 0 nil)
7837c247 966 mouse-face highlight
6f5b7627 967 keymap compilation-button-map
5ae48997 968 help-echo "mouse-2: visit destination directory")))
7837c247 969
4fffd73b 970;; Data type `reverse-ordered-alist' retriever. This function retrieves the
7837c247
SM
971;; KEY element from the ALIST, creating it in the right position if not already
972;; present. ALIST structure is
973;; '(ANCHOR (KEY1 ...) (KEY2 ...)... (KEYn ALIST ...))
974;; ANCHOR is ignored, but necessary so that elements can be inserted. KEY1
4fffd73b 975;; may be nil. The other KEYs are ordered backwards so that growing line
7837c247
SM
976;; numbers can be inserted in front and searching can abort after half the
977;; list on average.
6f5b7627 978(eval-when-compile ;Don't keep it at runtime if not needed.
7837c247
SM
979(defmacro compilation-assq (key alist)
980 `(let* ((l1 ,alist)
981 (l2 (cdr l1)))
982 (car (if (if (null ,key)
983 (if l2 (null (caar l2)))
984 (while (if l2 (if (caar l2) (< ,key (caar l2)) t))
985 (setq l1 l2
986 l2 (cdr l1)))
987 (if l2 (eq ,key (caar l2))))
988 l2
6f5b7627 989 (setcdr l1 (cons (list ,key) l2)))))))
7837c247 990
813fb3fe
SM
991(defun compilation-auto-jump (buffer pos)
992 (with-current-buffer buffer
993 (goto-char pos)
93c0985f
JL
994 (let ((win (get-buffer-window buffer 0)))
995 (if win (set-window-point win pos)))
78dc87a2
JL
996 (if compilation-auto-jump-to-first-error
997 (compile-goto-error))))
7837c247
SM
998
999;; This function is the central driver, called when font-locking to gather
1000;; all information needed to later jump to corresponding source code.
1001;; Return a property list with all meta information on this error location.
f0685ed1 1002
7837c247 1003(defun compilation-error-properties (file line end-line col end-col type fmt)
07b741a7
SM
1004 (unless (text-property-not-all (match-beginning 0) (point)
1005 'compilation-message nil)
7837c247 1006 (if file
07b741a7
SM
1007 (when (stringp
1008 (setq file (if (functionp file) (funcall file)
1009 (match-string-no-properties file))))
1010 (let ((dir
7837c247 1011 (unless (file-name-absolute-p file)
94642599
SM
1012 (let ((pos (compilation--previous-directory
1013 (match-beginning 0))))
07b741a7
SM
1014 (when pos
1015 (or (get-text-property (1- pos) 'compilation-directory)
1016 (get-text-property pos 'compilation-directory)))))))
efb0e677 1017 (setq file (cons file (car dir)))))
7837c247 1018 ;; This message didn't mention one, get it from previous
f0685ed1
RS
1019 (let ((prev-pos
1020 ;; Find the previous message.
07b741a7 1021 (previous-single-property-change (point) 'compilation-message)))
f0685ed1
RS
1022 (if prev-pos
1023 ;; Get the file structure that belongs to it.
1024 (let* ((prev
07b741a7
SM
1025 (or (get-text-property (1- prev-pos) 'compilation-message)
1026 (get-text-property prev-pos 'compilation-message)))
ee31aabc
CY
1027 (prev-file-struct
1028 (and prev
1029 (compilation--loc->file-struct
1030 (compilation--message->loc prev)))))
1031
f0685ed1 1032 ;; Construct FILE . DIR from that.
ee31aabc
CY
1033 (if prev-file-struct
1034 (setq file (cons (caar prev-file-struct)
1035 (cadr (car prev-file-struct)))))))
f0685ed1
RS
1036 (unless file
1037 (setq file '("*unknown*")))))
7837c247
SM
1038 ;; All of these fields are optional, get them only if we have an index, and
1039 ;; it matched some part of the message.
1040 (and line
1041 (setq line (match-string-no-properties line))
1042 (setq line (string-to-number line)))
1043 (and end-line
1044 (setq end-line (match-string-no-properties end-line))
1045 (setq end-line (string-to-number end-line)))
9dc3a46a
JL
1046 (if col
1047 (if (functionp col)
1048 (setq col (funcall col))
1049 (and
1050 (setq col (match-string-no-properties col))
6944dbc1 1051 (setq col (string-to-number col)))))
9dc3a46a
JL
1052 (if (and end-col (functionp end-col))
1053 (setq end-col (funcall end-col))
1054 (if (and end-col (setq end-col (match-string-no-properties end-col)))
6944dbc1 1055 (setq end-col (- (string-to-number end-col) -1))
9dc3a46a 1056 (if end-line (setq end-col -1))))
eb6fb6e2 1057 (if (consp type) ; not a static type, check what it is.
7837c247
SM
1058 (setq type (or (and (car type) (match-end (car type)) 1)
1059 (and (cdr type) (match-end (cdr type)) 0)
1060 2)))
813fb3fe
SM
1061
1062 (when (and compilation-auto-jump-to-next
1063 (>= type compilation-skip-threshold))
1064 (kill-local-variable 'compilation-auto-jump-to-next)
1065 (run-with-timer 0 nil 'compilation-auto-jump
1066 (current-buffer) (match-beginning 0)))
1067
07b741a7
SM
1068 (compilation-internal-error-properties
1069 file line end-line col end-col type fmt)))
efb0e677 1070
9c8e6c85
SM
1071(defun compilation-move-to-column (col screen)
1072 "Go to column COL on the current line.
1073If SCREEN is non-nil, columns are screen columns, otherwise, they are
1074just char-counts."
6944dbc1 1075 (setq col (- col compilation-first-column))
9c8e6c85 1076 (if screen
ee15d759 1077 (move-to-column (max col 0))
9c8e6c85
SM
1078 (goto-char (min (+ (line-beginning-position) col) (line-end-position)))))
1079
7957baea 1080(defun compilation-internal-error-properties (file line end-line col end-col type fmts)
efb0e677
SM
1081 "Get the meta-info that will be added as text-properties.
1082LINE, END-LINE, COL, END-COL are integers or nil.
7957baea
RS
1083TYPE can be 0, 1, or 2, meaning error, warning, or just info.
1084FILE should be (FILENAME) or (RELATIVE-FILENAME . DIRNAME) or nil.
1085FMTS is a list of format specs for transforming the file name.
1086 (See `compilation-error-regexp-alist'.)"
efb0e677 1087 (unless file (setq file '("*unknown*")))
7957baea
RS
1088 (let* ((file-struct (compilation-get-file-structure file fmts))
1089 ;; Get first already existing marker (if any has one, all have one).
1090 ;; Do this first, as the compilation-assq`s may create new nodes.
8fe52384
SM
1091 (marker-line ; a line structure
1092 (cadr (compilation--file-struct->loc-tree file-struct)))
1093 (marker
1094 (if marker-line (compilation--loc->marker (cadr marker-line))))
1dce7193 1095 (screen-columns compilation-error-screen-columns)
6035be52 1096 (first-column compilation-first-column)
efb0e677
SM
1097 end-marker loc end-loc)
1098 (if (not (and marker (marker-buffer marker)))
7957baea 1099 (setq marker nil) ; no valid marker for this file
52b61776 1100 (unless line (setq line 1)) ; normalize no linenumber to line 1
dbd97672 1101 (catch 'marker ; find nearest loc, at least one exists
8fe52384
SM
1102 (dolist (x (cddr (compilation--file-struct->loc-tree
1103 file-struct))) ; Loop over remaining lines.
52b61776 1104 (if (> (car x) line) ; Still bigger.
efb0e677 1105 (setq marker-line x)
52b61776
TN
1106 (if (> (- (or (car marker-line) 1) line)
1107 (- line (car x))) ; Current line is nearer.
efb0e677
SM
1108 (setq marker-line x))
1109 (throw 'marker t))))
8fe52384 1110 (setq marker (compilation--loc->marker (cadr marker-line))
dbd97672 1111 marker-line (or (car marker-line) 1))
efb0e677 1112 (with-current-buffer (marker-buffer marker)
1dce7193
SM
1113 (let ((screen-columns
1114 ;; Obey the compilation-error-screen-columns of the target
1115 ;; buffer if its major mode set it buffer-locally.
1116 (if (local-variable-p 'compilation-error-screen-columns)
6035be52
GM
1117 compilation-error-screen-columns screen-columns))
1118 (compilation-first-column
1119 (if (local-variable-p 'compilation-first-column)
1120 compilation-first-column first-column)))
1dce7193 1121 (save-excursion
8dfb3e16
RS
1122 (save-restriction
1123 (widen)
1124 (goto-char (marker-position marker))
52b61776
TN
1125 ;; Set end-marker if appropriate and go to line.
1126 (if (not (or end-col end-line))
1127 (beginning-of-line (- line marker-line -1))
8dfb3e16
RS
1128 (beginning-of-line (- (or end-line line) marker-line -1))
1129 (if (or (null end-col) (< end-col 0))
1130 (end-of-line)
1dce7193 1131 (compilation-move-to-column end-col screen-columns))
52b61776
TN
1132 (setq end-marker (point-marker))
1133 (when end-line (beginning-of-line (- line end-line -1))))
8dfb3e16 1134 (if col
1dce7193 1135 (compilation-move-to-column col screen-columns)
8dfb3e16 1136 (forward-to-indentation 0))
1dce7193 1137 (setq marker (point-marker)))))))
efb0e677 1138
8fe52384
SM
1139 (setq loc (compilation-assq line (compilation--file-struct->loc-tree
1140 file-struct)))
1141 (setq end-loc
efb0e677 1142 (if end-line
8fe52384
SM
1143 (compilation-assq
1144 end-col (compilation-assq
1145 end-line (compilation--file-struct->loc-tree
1146 file-struct)))
efb0e677 1147 (if end-col ; use same line element
8fe52384 1148 (compilation-assq end-col loc))))
efb0e677
SM
1149 (setq loc (compilation-assq col loc))
1150 ;; If they are new, make the loc(s) reference the file they point to.
8fe52384
SM
1151 ;; FIXME-omake: there's a problem with timestamps here: the markers
1152 ;; relative to which we computed the current `marker' have a timestamp
1153 ;; almost guaranteed to be different from compilation-buffer-modtime, so if
1154 ;; we use their timestamp, we'll never use `loc' since the timestamp won't
1155 ;; match compilation-buffer-modtime, and if we use
1156 ;; compilation-buffer-modtime then we have different timestamps for
1157 ;; locations that were computed together, which doesn't make sense either.
1158 ;; I think this points to a fundamental problem in our approach to the
1159 ;; "omake -P" problem. --Stef
1160 (or (cdr loc)
1161 (setcdr loc (compilation--make-cdrloc line file-struct marker)))
efb0e677 1162 (if end-loc
7957baea 1163 (or (cdr end-loc)
8fe52384
SM
1164 (setcdr end-loc
1165 (compilation--make-cdrloc (or end-line line) file-struct
1166 end-marker))))
efb0e677
SM
1167
1168 ;; Must start with face
55fb9013 1169 `(font-lock-face ,compilation-message-face
8fe52384 1170 compilation-message ,(compilation--make-message loc type end-loc)
07b741a7
SM
1171 help-echo ,(if col
1172 "mouse-2: visit this file, line and column"
1173 (if line
1174 "mouse-2: visit this file and line"
1175 "mouse-2: visit this file"))
1176 keymap compilation-button-map
1177 mouse-face highlight)))
7837c247 1178
55fb9013
SM
1179(defun compilation--put-prop (matchnum prop val)
1180 (when (and (integerp matchnum) (match-beginning matchnum))
1181 (put-text-property
1182 (match-beginning matchnum) (match-end matchnum)
1183 prop val)))
1184
1185(defun compilation--remove-properties (&optional start end)
1186 (with-silent-modifications
1187 ;; When compile.el used font-lock directly, we could just remove all
1188 ;; our text-properties in one go, but now that we manually place
1189 ;; font-lock-face, we have to be careful to only remove the font-lock-face
1190 ;; we placed.
1191 ;; (remove-list-of-text-properties
1192 ;; (or start (point-min)) (or end (point-max))
1193 ;; '(compilation-debug compilation-directory compilation-message
1194 ;; font-lock-face help-echo mouse-face))
1195 (let (next)
1196 (unless start (setq start (point-min)))
1197 (unless end (setq end (point-max)))
9e11271c 1198 (compilation--flush-directory-cache start end)
55fb9013
SM
1199 (while
1200 (progn
1201 (setq next (or (next-single-property-change
1202 start 'compilation-message nil end)
1203 end))
1204 (when (get-text-property start 'compilation-message)
1205 (remove-list-of-text-properties
1206 start next
1207 '(compilation-debug compilation-directory compilation-message
1208 font-lock-face help-echo mouse-face)))
1209 (< next end))
1210 (setq start next)))))
1211
1212(defun compilation--parse-region (start end)
1213 (goto-char end)
1214 (unless (bolp)
1215 ;; We generally don't like to parse partial lines.
a464a6c7 1216 (cl-assert (eobp))
55fb9013
SM
1217 (when (let ((proc (get-buffer-process (current-buffer))))
1218 (and proc (memq (process-status proc) '(run open))))
1219 (setq end (line-beginning-position))))
1220 (compilation--remove-properties start end)
91fa27cd
SM
1221 (if compilation-parse-errors-function
1222 ;; An old package! Try the compatibility code.
55fb9013
SM
1223 (progn
1224 (goto-char start)
1225 (compilation--compat-parse-errors end))
1226
1227 ;; compilation-directory-matcher is the only part that really needs to be
1228 ;; parsed sequentially. So we could split it out, handle directories
1229 ;; like syntax-propertize, and the rest as font-lock-keywords. But since
1230 ;; we want to have it work even when font-lock is off, we'd then need to
1231 ;; use our own compilation-parsed text-property to keep track of the parts
1232 ;; that have already been parsed.
1233 (goto-char start)
1234 (while (re-search-forward (car compilation-directory-matcher)
1235 end t)
9e11271c 1236 (compilation--flush-directory-cache (match-beginning 0) (match-end 0))
55fb9013
SM
1237 (when compilation-debug
1238 (font-lock-append-text-property
1239 (match-beginning 0) (match-end 0)
1240 'compilation-debug
1241 (vector 'directory compilation-directory-matcher)))
1242 (dolist (elt (cdr compilation-directory-matcher))
1243 (add-text-properties (match-beginning (car elt))
1244 (match-end (car elt))
1245 (compilation-directory-properties
1246 (car elt) (cdr elt)))))
1247
1248 (compilation-parse-errors start end)))
1249
1250(defun compilation-parse-errors (start end &rest rules)
1251 "Parse errors between START and END.
1252The errors recognized are the ones specified in RULES which default
1253to `compilation-error-regexp-alist' if RULES is nil."
55fb9013
SM
1254 (dolist (item (or rules compilation-error-regexp-alist))
1255 (if (symbolp item)
1256 (setq item (cdr (assq item
1257 compilation-error-regexp-alist-alist))))
1258 (let ((file (nth 1 item))
1259 (line (nth 2 item))
1260 (col (nth 3 item))
1261 (type (nth 4 item))
1262 (pat (car item))
1263 end-line end-col fmt
1264 props)
1265
1266 ;; omake reports some error indented, so skip the indentation.
1267 ;; another solution is to modify (some?) regexps in
1268 ;; `compilation-error-regexp-alist'.
1269 ;; note that omake usage is not limited to ocaml and C (for stubs).
1270 ;; FIXME-omake: Doing it here seems wrong, at least it should depend on
1271 ;; whether or not omake's own error messages are recognized.
1272 (cond
1273 ((not (memq 'omake compilation-error-regexp-alist)) nil)
1274 ((string-match "\\`\\([^^]\\|^\\( \\*\\|\\[\\)\\)" pat)
1275 nil) ;; Not anchored or anchored but already allows empty spaces.
1276 (t (setq pat (concat "^ *" (substring pat 1)))))
1277
1278 (if (consp file) (setq fmt (cdr file) file (car file)))
1279 (if (consp line) (setq end-line (cdr line) line (car line)))
1280 (if (consp col) (setq end-col (cdr col) col (car col)))
1281
1282 (if (functionp line)
1283 ;; The old compile.el had here an undocumented hook that
1284 ;; allowed `line' to be a function that computed the actual
1285 ;; error location. Let's do our best.
1286 (progn
1287 (goto-char start)
1288 (while (re-search-forward pat end t)
1289 (save-match-data
1290 (when compilation-debug
1291 (font-lock-append-text-property
1292 (match-beginning 0) (match-end 0)
1293 'compilation-debug (vector 'functionp item)))
1294 (add-text-properties
1295 (match-beginning 0) (match-end 0)
1296 (compilation--compat-error-properties
1297 (funcall line (cons (match-string file)
1298 (cons default-directory
1299 (nthcdr 4 item)))
1300 (if col (match-string col))))))
1301 (compilation--put-prop
1302 file 'font-lock-face compilation-error-face)))
1303
1304 (unless (or (null (nth 5 item)) (integerp (nth 5 item)))
1305 (error "HYPERLINK should be an integer: %s" (nth 5 item)))
1306
1307 (goto-char start)
1308 (while (re-search-forward pat end t)
55fb9013
SM
1309 (when (setq props (compilation-error-properties
1310 file line end-line col end-col (or type 2) fmt))
1311
1312 (when (integerp file)
1313 (compilation--put-prop
1314 file 'font-lock-face
1315 (if (consp type)
1316 (compilation-face type)
1317 (symbol-value (aref [compilation-info-face
1318 compilation-warning-face
1319 compilation-error-face]
1320 (or type 2))))))
1321
1322 (compilation--put-prop
1323 line 'font-lock-face compilation-line-face)
1324 (compilation--put-prop
1325 end-line 'font-lock-face compilation-line-face)
1326
1327 (compilation--put-prop
1328 col 'font-lock-face compilation-column-face)
1329 (compilation--put-prop
1330 end-col 'font-lock-face compilation-column-face)
1331
f1be615c 1332 ;; Obey HIGHLIGHT.
55fb9013
SM
1333 (dolist (extra-item (nthcdr 6 item))
1334 (let ((mn (pop extra-item)))
1335 (when (match-beginning mn)
1336 (let ((face (eval (car extra-item))))
1337 (cond
1338 ((null face))
f1be615c 1339 ((or (symbolp face) (stringp face))
55fb9013
SM
1340 (put-text-property
1341 (match-beginning mn) (match-end mn)
1342 'font-lock-face face))
f1be615c
CY
1343 ((and (listp face)
1344 (eq (car face) 'face)
1345 (or (symbolp (cadr face))
1346 (stringp (cadr face))))
1347 (put-text-property
1348 (match-beginning mn) (match-end mn)
1349 'font-lock-face (cadr face))
1350 (add-text-properties
1351 (match-beginning mn) (match-end mn)
1352 (nthcdr 2 face)))
55fb9013
SM
1353 (t
1354 (error "Don't know how to handle face %S"
1355 face)))))))
1356 (let ((mn (or (nth 5 item) 0)))
1357 (when compilation-debug
1358 (font-lock-append-text-property
1359 (match-beginning 0) (match-end 0)
1360 'compilation-debug (vector 'std item props)))
1361 (add-text-properties
1362 (match-beginning mn) (match-end mn)
1363 (cddr props))
1364 (font-lock-append-text-property
1365 (match-beginning mn) (match-end mn)
1366 'font-lock-face (cadr props)))))))))
1367
1368(defvar compilation--parsed -1)
1369(make-variable-buffer-local 'compilation--parsed)
1370
1371(defun compilation--ensure-parse (limit)
1372 "Make sure the text has been parsed up to LIMIT."
1373 (save-excursion
1374 (goto-char limit)
1375 (setq limit (line-beginning-position 2))
1376 (unless (markerp compilation--parsed)
1377 ;; We use a marker for compilation--parsed so that users (such as
1378 ;; grep.el) don't need to flush-parse when they modify the buffer
1379 ;; in a way that impacts buffer positions but does not require
1380 ;; re-parsing.
1381 (setq compilation--parsed (point-min-marker)))
1382 (when (< compilation--parsed limit)
1383 (let ((start (max compilation--parsed (point-min))))
1384 (move-marker compilation--parsed limit)
1385 (goto-char start)
1386 (forward-line 0) ;Not line-beginning-position: ignore (comint) fields.
1387 (with-silent-modifications
1388 (compilation--parse-region (point) compilation--parsed)))))
1389 nil)
1390
e02f48d7 1391(defun compilation--flush-parse (start _end)
55fb9013 1392 "Mark the region between START and END for re-parsing."
55fb9013
SM
1393 (if (markerp compilation--parsed)
1394 (move-marker compilation--parsed (min start compilation--parsed))))
1395
1396(defun compilation-mode-font-lock-keywords ()
1397 "Return expressions to highlight in Compilation mode."
1398 (append
1399 '((compilation--ensure-parse))
1400 compilation-mode-font-lock-keywords))
7837c247 1401
430aee8b
SS
1402(defun compilation-read-command (command)
1403 (read-shell-command "Compile command: " command
1404 (if (equal (car compile-history) command)
1405 '(compile-history . 1)
1406 'compile-history)))
1407
01f89d11 1408\f
d3cb357b 1409;;;###autoload
7837c247 1410(defun compile (command &optional comint)
55dfd2c4
RS
1411 "Compile the program including the current buffer. Default: run `make'.
1412Runs COMMAND, a shell command, in a separate process asynchronously
1413with output going to the buffer `*compilation*'.
d3cb357b 1414
55dfd2c4
RS
1415You can then use the command \\[next-error] to find the next error message
1416and move to the source code that caused it.
1417
8f72171b
RS
1418If optional second arg COMINT is t the buffer will be in Comint mode with
1419`compilation-shell-minor-mode'.
1420
08b1edf4
RM
1421Interactively, prompts for the command if `compilation-read-command' is
1422non-nil; otherwise uses `compile-command'. With prefix arg, always prompts.
c39bf546
DP
1423Additionally, with universal prefix arg, compilation buffer will be in
1424comint mode, i.e. interactive.
08b1edf4 1425
7d1dad0c 1426To run more than one compilation at once, start one then rename
c72095b3 1427the \`*compilation*' buffer to some other name with
7d1dad0c
RS
1428\\[rename-buffer]. Then _switch buffers_ and start the new compilation.
1429It will create a new \`*compilation*' buffer.
1430
1431On most systems, termination of the main compilation process
1432kills its subprocesses.
d3cb357b
RM
1433
1434The name used for the buffer is actually whatever is returned by
1435the function in `compilation-buffer-name-function', so you can set that
1436to a function that generates a unique name."
90016295 1437 (interactive
c39bf546 1438 (list
20320c65
JL
1439 (let ((command (eval compile-command)))
1440 (if (or compilation-read-command current-prefix-arg)
430aee8b 1441 (compilation-read-command command)
20320c65 1442 command))
c39bf546 1443 (consp current-prefix-arg)))
5b6858da
SM
1444 (unless (equal command (eval compile-command))
1445 (setq compile-command command))
9e86ab0b
SS
1446 (save-some-buffers (not compilation-ask-about-save)
1447 compilation-save-buffers-predicate)
091525d5 1448 (setq-default compilation-directory default-directory)
7837c247 1449 (compilation-start command comint))
55dfd2c4 1450
5b6858da 1451;; run compile with the default command line
430aee8b 1452(defun recompile (&optional edit-command)
6867356a 1453 "Re-compile the program including the current buffer.
6f5b7627 1454If this is run in a Compilation mode buffer, re-use the arguments from the
430aee8b
SS
1455original use. Otherwise, recompile using `compile-command'.
1456If the optional argument `edit-command' is non-nil, the command can be edited."
1457 (interactive "P")
9e86ab0b
SS
1458 (save-some-buffers (not compilation-ask-about-save)
1459 compilation-save-buffers-predicate)
091525d5 1460 (let ((default-directory (or compilation-directory default-directory)))
430aee8b
SS
1461 (when edit-command
1462 (setcar compilation-arguments
1463 (compilation-read-command (car compilation-arguments))))
7837c247
SM
1464 (apply 'compilation-start (or compilation-arguments
1465 `(,(eval compile-command))))))
09843b4a 1466
b5812513 1467(defcustom compilation-scroll-output nil
813fb3fe 1468 "Non-nil to scroll the *compilation* buffer window as output appears.
b5812513 1469
6f5b7627 1470Setting it causes the Compilation mode commands to put point at the
b5812513 1471end of their output window so that the end of the output is always
78dc87a2
JL
1472visible rather than the beginning.
1473
1474The value `first-error' stops scrolling at the first error, and leaves
1475point on its location in the *compilation* buffer."
1476 :type '(choice (const :tag "No scrolling" nil)
1477 (const :tag "Scroll compilation output" t)
1478 (const :tag "Stop scrolling at the first error" first-error))
a46fddeb 1479 :version "20.3"
b5812513
DL
1480 :group 'compilation)
1481
7bdb67b2 1482
e02f48d7 1483(defun compilation-buffer-name (name-of-mode mode-command name-function)
7bdb67b2 1484 "Return the name of a compilation buffer to use.
e02f48d7 1485If NAME-FUNCTION is non-nil, call it with one argument NAME-OF-MODE
7bdb67b2
GM
1486to determine the buffer name.
1487Likewise if `compilation-buffer-name-function' is non-nil.
7d1dad0c 1488If current buffer has the major mode MODE-COMMAND,
7bdb67b2 1489return the name of the current buffer, so that it gets reused.
e02f48d7 1490Otherwise, construct a buffer name from NAME-OF-MODE."
dc2feacf 1491 (cond (name-function
e02f48d7 1492 (funcall name-function name-of-mode))
dc2feacf 1493 (compilation-buffer-name-function
e02f48d7 1494 (funcall compilation-buffer-name-function name-of-mode))
be947101 1495 ((eq mode-command major-mode)
7bdb67b2
GM
1496 (buffer-name))
1497 (t
e02f48d7 1498 (concat "*" (downcase name-of-mode) "*"))))
7bdb67b2 1499
f0019ede 1500(defcustom compilation-always-kill nil
f17e1d00
AS
1501 "If t, always kill a running compilation process before starting a new one.
1502If nil, ask to kill it."
f0019ede
MB
1503 :type 'boolean
1504 :version "24.3"
1505 :group 'compilation)
1506
a24c45d2 1507;;;###autoload
7837c247 1508(defun compilation-start (command &optional mode name-function highlight-regexp)
55dfd2c4 1509 "Run compilation command COMMAND (low level interface).
489a8034 1510If COMMAND starts with a cd command, that becomes the `default-directory'.
9ac57479
KS
1511The rest of the arguments are optional; for them, nil means use the default.
1512
7837c247 1513MODE is the major mode to set in the compilation buffer. Mode
6f5b7627 1514may also be t meaning use `compilation-shell-minor-mode' under `comint-mode'.
7d1dad0c 1515
5b317d74 1516If NAME-FUNCTION is non-nil, call it with one argument (the mode name)
7d1dad0c
RS
1517to determine the buffer name. Otherwise, the default is to
1518reuses the current buffer if it has the proper major mode,
1519else use or create a buffer with name based on the major mode.
23b0c5fc 1520
9ac57479 1521If HIGHLIGHT-REGEXP is non-nil, `next-error' will temporarily highlight
6f5b7627 1522the matching section of the visited source line; the default is to use the
9ac57479
KS
1523global value of `compilation-highlight-regexp'.
1524
646bd331 1525Returns the compilation buffer created."
7837c247 1526 (or mode (setq mode 'compilation-mode))
489a8034
DP
1527 (let* ((name-of-mode
1528 (if (eq mode t)
72fcf382 1529 "compilation"
331b2b90 1530 (replace-regexp-in-string "-mode\\'" "" (symbol-name mode))))
199143f1 1531 (thisdir default-directory)
91ab9c13 1532 (thisenv compilation-environment)
489a8034 1533 outwin outbuf)
c536bb39
SM
1534 (with-current-buffer
1535 (setq outbuf
1536 (get-buffer-create
be947101 1537 (compilation-buffer-name name-of-mode mode name-function)))
d3cb357b 1538 (let ((comp-proc (get-buffer-process (current-buffer))))
a11035b8
MB
1539 (if comp-proc
1540 (if (or (not (eq (process-status comp-proc) 'run))
1541 (eq (process-query-on-exit-flag comp-proc) nil)
1542 (yes-or-no-p
1543 (format "A %s process is running; kill it? "
1544 name-of-mode)))
1545 (condition-case ()
1546 (progn
1547 (interrupt-process comp-proc)
1548 (sit-for 1)
1549 (delete-process comp-proc))
1550 (error nil))
1551 (error "Cannot have two processes in `%s' at once"
1552 (buffer-name)))))
199143f1
DP
1553 ;; first transfer directory from where M-x compile was called
1554 (setq default-directory thisdir)
d42c87ab
RS
1555 ;; Make compilation buffer read-only. The filter can still write it.
1556 ;; Clear out the compilation buffer.
199143f1
DP
1557 (let ((inhibit-read-only t)
1558 (default-directory thisdir))
813fb3fe
SM
1559 ;; Then evaluate a cd command if any, but don't perform it yet, else
1560 ;; start-command would do it again through the shell: (cd "..") AND
1561 ;; sh -c "cd ..; make"
f6f8aa12
CY
1562 (cd (if (string-match "\\`\\s *cd\\(?:\\s +\\(\\S +?\\)\\)?\\s *[;&\n]"
1563 command)
199143f1 1564 (if (match-end 1)
12221c84 1565 (substitute-env-vars (match-string 1 command))
199143f1
DP
1566 "~")
1567 default-directory))
abed5267 1568 (erase-buffer)
6d2957c4
RS
1569 ;; Select the desired mode.
1570 (if (not (eq mode t))
ec4e0abc
SM
1571 (progn
1572 (buffer-disable-undo)
1573 (funcall mode))
6d2957c4
RS
1574 (setq buffer-read-only nil)
1575 (with-no-warnings (comint-mode))
1576 (compilation-shell-minor-mode))
5f3ca1ba
SS
1577 ;; Remember the original dir, so we can use it when we recompile.
1578 ;; default-directory' can't be used reliably for that because it may be
1579 ;; affected by the special handling of "cd ...;".
91ab9c13 1580 ;; NB: must be done after (funcall mode) as that resets local variables
5f3ca1ba 1581 (set (make-local-variable 'compilation-directory) thisdir)
91ab9c13 1582 (set (make-local-variable 'compilation-environment) thisenv)
6d2957c4
RS
1583 (if highlight-regexp
1584 (set (make-local-variable 'compilation-highlight-regexp)
1585 highlight-regexp))
78dc87a2
JL
1586 (if (or compilation-auto-jump-to-first-error
1587 (eq compilation-scroll-output 'first-error))
813fb3fe 1588 (set (make-local-variable 'compilation-auto-jump-to-next) t))
6d2957c4 1589 ;; Output a mode setter, for saving and later reloading this buffer.
d42c87ab 1590 (insert "-*- mode: " name-of-mode
3b548e1b
SM
1591 "; default-directory: "
1592 (prin1-to-string (abbreviate-file-name default-directory))
a67e5425 1593 " -*-\n"
314b410b
JL
1594 (format "%s started at %s\n\n"
1595 mode-name
1596 (substring (current-time-string) 0 19))
a67e5425 1597 command "\n")
abed5267 1598 (setq thisdir default-directory))
7837c247 1599 (set-buffer-modified-p nil))
7837c247 1600 ;; Pop up the compilation buffer.
c34dc850
GM
1601 ;; http://lists.gnu.org/archive/html/emacs-devel/2007-11/msg01638.html
1602 (setq outwin (display-buffer outbuf))
7837c247 1603 (with-current-buffer outbuf
577bf5d2
JL
1604 (let ((process-environment
1605 (append
1606 compilation-environment
a11035b8 1607 (if (if (boundp 'system-uses-terminfo);`If' for compiler warning.
577bf5d2
JL
1608 system-uses-terminfo)
1609 (list "TERM=dumb" "TERMCAP="
1610 (format "COLUMNS=%d" (window-width)))
1611 (list "TERM=emacs"
1612 (format "TERMCAP=emacs:co#%d:tc=unknown:"
1613 (window-width))))
1614 ;; Set the EMACS variable, but
1615 ;; don't override users' setting of $EMACS.
4b1aaa8b 1616 (unless (getenv "EMACS")
e725507a
CY
1617 (list "EMACS=t"))
1618 (list "INSIDE_EMACS=t")
a9e11582 1619 (copy-sequence process-environment))))
577bf5d2
JL
1620 (set (make-local-variable 'compilation-arguments)
1621 (list command mode name-function highlight-regexp))
1622 (set (make-local-variable 'revert-buffer-function)
1623 'compilation-revert-buffer)
1624 (set-window-start outwin (point-min))
2d0a22f8
RS
1625
1626 ;; Position point as the user will see it.
1627 (let ((desired-visible-point
1628 ;; Put it at the end if `compilation-scroll-output' is set.
1629 (if compilation-scroll-output
1630 (point-max)
1631 ;; Normally put it at the top.
1632 (point-min))))
1633 (if (eq outwin (selected-window))
1634 (goto-char desired-visible-point)
1635 (set-window-point outwin desired-visible-point)))
1636
577bf5d2
JL
1637 ;; The setup function is called before compilation-set-window-height
1638 ;; so it can set the compilation-window-height buffer locally.
1639 (if compilation-process-setup-function
1640 (funcall compilation-process-setup-function))
1641 (compilation-set-window-height outwin)
1642 ;; Start the compilation.
2a12d736
EZ
1643 (if (fboundp 'start-process)
1644 (let ((proc
1645 (if (eq mode t)
1646 ;; comint uses `start-file-process'.
1647 (get-buffer-process
1648 (with-no-warnings
1649 (comint-exec
1650 outbuf (downcase mode-name)
1651 (if (file-remote-p default-directory)
1652 "/bin/sh"
1653 shell-file-name)
1654 nil `("-c" ,command))))
1655 (start-file-process-shell-command (downcase mode-name)
1656 outbuf command))))
a11035b8
MB
1657 ;; Make the buffer's mode line show process state.
1658 (setq mode-line-process
1659 '(:propertize ":%s" face compilation-mode-line-run))
1660
1661 ;; Set the process as killable without query by default.
1662 ;; This allows us to start a new compilation without
1663 ;; getting prompted.
1664 (when compilation-always-kill
1665 (set-process-query-on-exit-flag proc nil))
1666
1667 (set-process-sentinel proc 'compilation-sentinel)
1668 (unless (eq mode t)
1669 ;; Keep the comint filter, since it's needed for proper
1670 ;; handling of the prompts.
2a12d736
EZ
1671 (set-process-filter proc 'compilation-filter))
1672 ;; Use (point-max) here so that output comes in
1673 ;; after the initial text,
1674 ;; regardless of where the user sees point.
1675 (set-marker (process-mark proc) (point-max) outbuf)
1676 (when compilation-disable-input
1677 (condition-case nil
1678 (process-send-eof proc)
1679 ;; The process may have exited already.
1680 (error nil)))
dd93e6da
SS
1681 (run-hook-with-args 'compilation-start-hook proc)
1682 (setq compilation-in-progress
2a12d736
EZ
1683 (cons proc compilation-in-progress)))
1684 ;; No asynchronous processes available.
1685 (message "Executing `%s'..." command)
37269466 1686 ;; Fake mode line display as if `start-process' were run.
ddb1f2e3 1687 (setq mode-line-process
5205d6f6 1688 '(:propertize ":run" face compilation-mode-line-run))
2a12d736
EZ
1689 (force-mode-line-update)
1690 (sit-for 0) ; Force redisplay
1691 (save-excursion
1692 ;; Insert the output at the end, after the initial text,
1693 ;; regardless of where the user sees point.
1694 (goto-char (point-max))
07b741a7 1695 (let* ((inhibit-read-only t) ; call-process needs to modify outbuf
9bedd73a 1696 (compilation-filter-start (point))
2a12d736
EZ
1697 (status (call-process shell-file-name nil outbuf nil "-c"
1698 command)))
9bedd73a 1699 (run-hooks 'compilation-filter-hook)
2a12d736
EZ
1700 (cond ((numberp status)
1701 (compilation-handle-exit
1702 'exit status
1703 (if (zerop status)
1704 "finished\n"
1705 (format "exited abnormally with code %d\n" status))))
1706 ((stringp status)
1707 (compilation-handle-exit 'signal status
1708 (concat status "\n")))
1709 (t
1710 (compilation-handle-exit 'bizarre status status)))))
2a12d736
EZ
1711 (set-buffer-modified-p nil)
1712 (message "Executing `%s'...done" command)))
199143f1 1713 ;; Now finally cd to where the shell started make/grep/...
e6f3e104
MR
1714 (setq default-directory thisdir)
1715 ;; The following form selected outwin ever since revision 1.183,
1716 ;; so possibly messing up point in some other window (bug#1073).
1717 ;; Moved into the scope of with-current-buffer, though still with
1718 ;; complete disregard for the case when compilation-scroll-output
1719 ;; equals 'first-error (martin 2008-10-04).
1720 (when compilation-scroll-output
1721 (goto-char (point-max))))
1722
043442b4 1723 ;; Make it so the next C-x ` will use this buffer.
5d9f0de2 1724 (setq next-error-last-buffer outbuf)))
55dfd2c4 1725
c94b02d6 1726(defun compilation-set-window-height (window)
851231e9 1727 "Set the height of WINDOW according to `compilation-window-height'."
9ac57479
KS
1728 (let ((height (buffer-local-value 'compilation-window-height (window-buffer window))))
1729 (and height
0dad3dfe 1730 (window-full-width-p window)
9ac57479
KS
1731 ;; If window is alone in its frame, aside from a minibuffer,
1732 ;; don't change its height.
1733 (not (eq window (frame-root-window (window-frame window))))
b3ef54c5
DP
1734 ;; Stef said that doing the saves in this order is safer:
1735 (save-excursion
9ac57479 1736 (save-selected-window
b3ef54c5
DP
1737 (select-window window)
1738 (enlarge-window (- height (window-height))))))))
c94b02d6 1739
4282eba1 1740(defvar compilation-menu-map
93260283
DN
1741 (let ((map (make-sparse-keymap "Errors"))
1742 (opt-map (make-sparse-keymap "Skip")))
4282eba1 1743 (define-key map [stop-subjob]
38805987
DN
1744 '(menu-item "Stop Compilation" kill-compilation
1745 :help "Kill the process made by the M-x compile or M-x grep commands"))
93260283
DN
1746 (define-key map [compilation-mode-separator3]
1747 '("----" . nil))
1748 (define-key map [compilation-next-error-follow-minor-mode]
1749 '(menu-item
1750 "Auto Error Display" next-error-follow-minor-mode
1751 :help "Display the error under cursor when moving the cursor"
1752 :button (:toggle . next-error-follow-minor-mode)))
1753 (define-key map [compilation-skip]
1754 (cons "Skip Less Important Messages" opt-map))
1755 (define-key opt-map [compilation-skip-none]
1756 '(menu-item "Don't Skip Any Messages"
1757 (lambda ()
1758 (interactive)
1759 (customize-set-variable 'compilation-skip-threshold 0))
1760 :help "Do not skip any type of messages"
1761 :button (:radio . (eq compilation-skip-threshold 0))))
1762 (define-key opt-map [compilation-skip-info]
1763 '(menu-item "Skip Info"
1764 (lambda ()
1765 (interactive)
1766 (customize-set-variable 'compilation-skip-threshold 1))
1767 :help "Skip anything less than warning"
1768 :button (:radio . (eq compilation-skip-threshold 1))))
1769 (define-key opt-map [compilation-skip-warning-and-info]
1770 '(menu-item "Skip Warnings and Info"
1771 (lambda ()
1772 (interactive)
1773 (customize-set-variable 'compilation-skip-threshold 2))
1774 :help "Skip over Warnings and Info, stop for errors"
1775 :button (:radio . (eq compilation-skip-threshold 2))))
4282eba1
SM
1776 (define-key map [compilation-mode-separator2]
1777 '("----" . nil))
9ac57479 1778 (define-key map [compilation-first-error]
38805987
DN
1779 '(menu-item "First Error" first-error
1780 :help "Restart at the first error, visit corresponding source code"))
9ac57479 1781 (define-key map [compilation-previous-error]
38805987
DN
1782 '(menu-item "Previous Error" previous-error
1783 :help "Visit previous `next-error' message and corresponding source code"))
9ac57479 1784 (define-key map [compilation-next-error]
38805987
DN
1785 '(menu-item "Next Error" next-error
1786 :help "Visit next `next-error' message and corresponding source code"))
4282eba1
SM
1787 map))
1788
0b18a8f6 1789(defvar compilation-minor-mode-map
55dfd2c4 1790 (let ((map (make-sparse-keymap)))
abef340a 1791 (set-keymap-parent map special-mode-map)
9da85ee5 1792 (define-key map [mouse-2] 'compile-goto-error)
0ac804df 1793 (define-key map [follow-link] 'mouse-face)
55dfd2c4 1794 (define-key map "\C-c\C-c" 'compile-goto-error)
4e7ce12e 1795 (define-key map "\C-m" 'compile-goto-error)
d3cb357b 1796 (define-key map "\C-c\C-k" 'kill-compilation)
646bd331
RM
1797 (define-key map "\M-n" 'compilation-next-error)
1798 (define-key map "\M-p" 'compilation-previous-error)
d1ed4475
RM
1799 (define-key map "\M-{" 'compilation-previous-file)
1800 (define-key map "\M-}" 'compilation-next-file)
86c7460f 1801 (define-key map "g" 'recompile) ; revert
4282eba1
SM
1802 ;; Set up the menu-bar
1803 (define-key map [menu-bar compilation]
1804 (cons "Errors" compilation-menu-map))
55dfd2c4 1805 map)
4f6e4ad6 1806 "Keymap for `compilation-minor-mode'.")
0b18a8f6 1807
a24770bc
RS
1808(defvar compilation-shell-minor-mode-map
1809 (let ((map (make-sparse-keymap)))
a24770bc
RS
1810 (define-key map "\M-\C-m" 'compile-goto-error)
1811 (define-key map "\M-\C-n" 'compilation-next-error)
1812 (define-key map "\M-\C-p" 'compilation-previous-error)
1813 (define-key map "\M-{" 'compilation-previous-file)
1814 (define-key map "\M-}" 'compilation-next-file)
1815 ;; Set up the menu-bar
4282eba1
SM
1816 (define-key map [menu-bar compilation]
1817 (cons "Errors" compilation-menu-map))
a24770bc
RS
1818 map)
1819 "Keymap for `compilation-shell-minor-mode'.")
1820
60470fd2
SM
1821(defvar compilation-button-map
1822 (let ((map (make-sparse-keymap)))
1823 (define-key map [mouse-2] 'compile-goto-error)
0ac804df 1824 (define-key map [follow-link] 'mouse-face)
60470fd2
SM
1825 (define-key map "\C-m" 'compile-goto-error)
1826 map)
1827 "Keymap for compilation-message buttons.")
1828(fset 'compilation-button-map compilation-button-map)
1829
0b18a8f6 1830(defvar compilation-mode-map
4282eba1 1831 (let ((map (make-sparse-keymap)))
261b01c6
RS
1832 ;; Don't inherit from compilation-minor-mode-map,
1833 ;; because that introduces a menu bar item we don't want.
1834 ;; That confuses C-down-mouse-3.
abef340a 1835 (set-keymap-parent map special-mode-map)
5988691b 1836 (define-key map [mouse-2] 'compile-goto-error)
0ac804df 1837 (define-key map [follow-link] 'mouse-face)
5988691b
RS
1838 (define-key map "\C-c\C-c" 'compile-goto-error)
1839 (define-key map "\C-m" 'compile-goto-error)
1840 (define-key map "\C-c\C-k" 'kill-compilation)
1841 (define-key map "\M-n" 'compilation-next-error)
1842 (define-key map "\M-p" 'compilation-previous-error)
1843 (define-key map "\M-{" 'compilation-previous-file)
1844 (define-key map "\M-}" 'compilation-next-file)
70fec115
JL
1845 (define-key map "\t" 'compilation-next-error)
1846 (define-key map [backtab] 'compilation-previous-error)
86c7460f 1847 (define-key map "g" 'recompile) ; revert
5988691b 1848
221206e3 1849 (define-key map "\C-c\C-f" 'next-error-follow-minor-mode)
9ac57479 1850
e60476ca 1851 ;; Set up the menu-bar
5988691b
RS
1852 (let ((submap (make-sparse-keymap "Compile")))
1853 (define-key map [menu-bar compilation]
1854 (cons "Compile" submap))
1855 (set-keymap-parent submap compilation-menu-map))
4282eba1 1856 (define-key map [menu-bar compilation compilation-separator2]
e60476ca 1857 '("----" . nil))
9ac57479 1858 (define-key map [menu-bar compilation compilation-grep]
38805987
DN
1859 '(menu-item "Search Files (grep)..." grep
1860 :help "Run grep, with user-specified args, and collect output in a buffer"))
9ac57479 1861 (define-key map [menu-bar compilation compilation-recompile]
38805987
DN
1862 '(menu-item "Recompile" recompile
1863 :help "Re-compile the program including the current buffer"))
9ac57479 1864 (define-key map [menu-bar compilation compilation-compile]
38805987
DN
1865 '(menu-item "Compile..." compile
1866 :help "Compile the program including the current buffer. Default: run `make'"))
0b18a8f6
RM
1867 map)
1868 "Keymap for compilation log buffers.
4282eba1 1869`compilation-minor-mode-map' is a parent of this.")
55dfd2c4 1870
c45e48d2 1871(defvar compilation-mode-tool-bar-map
b4bd2cbe
CY
1872 ;; When bootstrapping, tool-bar-map is not properly initialized yet,
1873 ;; so don't do anything.
900503ae
CY
1874 (when (keymapp tool-bar-map)
1875 (let ((map (copy-keymap tool-bar-map)))
1876 (define-key map [undo] nil)
1877 (define-key map [separator-2] nil)
1878 (define-key-after map [separator-compile] menu-bar-separator)
b4bd2cbe
CY
1879 (tool-bar-local-item
1880 "left-arrow" 'previous-error-no-select 'previous-error-no-select map
1881 :rtl "right-arrow"
1882 :help "Goto previous error")
1883 (tool-bar-local-item
1884 "right-arrow" 'next-error-no-select 'next-error-no-select map
1885 :rtl "left-arrow"
1886 :help "Goto next error")
1887 (tool-bar-local-item
1888 "cancel" 'kill-compilation 'kill-compilation map
1889 :enable '(let ((buffer (compilation-find-buffer)))
1890 (get-buffer-process buffer))
1891 :help "Stop compilation")
1892 (tool-bar-local-item
1893 "refresh" 'recompile 'recompile map
1894 :help "Restart compilation")
900503ae 1895 map)))
c45e48d2 1896
0a35bd79
RS
1897(put 'compilation-mode 'mode-class 'special)
1898
501cf428 1899;;;###autoload
d42c87ab 1900(defun compilation-mode (&optional name-of-mode)
55dfd2c4
RS
1901 "Major mode for compilation log buffers.
1902\\<compilation-mode-map>To visit the source for a line-numbered error,
d3cb357b 1903move point to the error message line and type \\[compile-goto-error].
7c163413
RM
1904To kill the compilation, type \\[kill-compilation].
1905
2894bd96 1906Runs `compilation-mode-hook' with `run-mode-hooks' (which see).
8ff2ed52
RS
1907
1908\\{compilation-mode-map}"
55dfd2c4 1909 (interactive)
9af0d309 1910 (kill-all-local-variables)
55dfd2c4 1911 (use-local-map compilation-mode-map)
a1562258
SM
1912 ;; Let windows scroll along with the output.
1913 (set (make-local-variable 'window-point-insertion-type) t)
c45e48d2 1914 (set (make-local-variable 'tool-bar-map) compilation-mode-tool-bar-map)
175069ef 1915 (setq major-mode 'compilation-mode ; FIXME: Use define-derived-mode.
d42c87ab 1916 mode-name (or name-of-mode "Compilation"))
7837c247
SM
1917 (set (make-local-variable 'page-delimiter)
1918 compilation-page-delimiter)
8fe52384 1919 ;; (set (make-local-variable 'compilation-buffer-modtime) nil)
0b18a8f6 1920 (compilation-setup)
bd8c6db5 1921 (setq buffer-read-only t)
7837c247
SM
1922 (run-mode-hooks 'compilation-mode-hook))
1923
b581bb5c
SM
1924;;;###autoload
1925(put 'define-compilation-mode 'doc-string-elt 3)
1926
7837c247
SM
1927(defmacro define-compilation-mode (mode name doc &rest body)
1928 "This is like `define-derived-mode' without the PARENT argument.
1929The parent is always `compilation-mode' and the customizable `compilation-...'
bac3a1c9
JL
1930variables are also set from the name of the mode you have chosen,
1931by replacing the first word, e.g `compilation-scroll-output' from
1932`grep-scroll-output' if that variable exists."
7837c247
SM
1933 (let ((mode-name (replace-regexp-in-string "-mode\\'" "" (symbol-name mode))))
1934 `(define-derived-mode ,mode compilation-mode ,name
1935 ,doc
1936 ,@(mapcar (lambda (v)
1937 (setq v (cons v
1938 (intern-soft (replace-regexp-in-string
1939 "^compilation" mode-name
1940 (symbol-name v)))))
1941 (and (cdr v)
1942 (or (boundp (cdr v))
07b741a7 1943 ;; FIXME: This is hackish, using undocumented info.
7837c247
SM
1944 (if (boundp 'byte-compile-bound-variables)
1945 (memq (cdr v) byte-compile-bound-variables)))
1946 `(set (make-local-variable ',(car v)) ,(cdr v))))
1947 '(compilation-buffer-name-function
1948 compilation-directory-matcher
1949 compilation-error
1950 compilation-error-regexp-alist
1951 compilation-error-regexp-alist-alist
1952 compilation-error-screen-columns
1953 compilation-finish-function
1954 compilation-finish-functions
1955 compilation-first-column
1956 compilation-mode-font-lock-keywords
1957 compilation-page-delimiter
1958 compilation-parse-errors-filename-function
1959 compilation-process-setup-function
1960 compilation-scroll-output
1961 compilation-search-path
1962 compilation-skip-threshold
1963 compilation-window-height))
1964 ,@body)))
0b18a8f6 1965
58856335 1966(defun compilation-revert-buffer (ignore-auto noconfirm)
9ed2ab9f
RS
1967 (if buffer-file-name
1968 (let (revert-buffer-function)
9ac57479 1969 (revert-buffer ignore-auto noconfirm))
9ed2ab9f 1970 (if (or noconfirm (yes-or-no-p (format "Restart compilation? ")))
7837c247
SM
1971 (apply 'compilation-start compilation-arguments))))
1972
c536bb39
SM
1973(defvar compilation-current-error nil
1974 "Marker to the location from where the next error will be found.
1975The global commands next/previous/first-error/goto-error use this.")
51c8ad03 1976
9b7b51a2
SM
1977(defvar compilation-messages-start nil
1978 "Buffer position of the beginning of the compilation messages.
1979If nil, use the beginning of buffer.")
1980
7837c247 1981(defun compilation-setup (&optional minor)
6f5b7627
SM
1982 "Prepare the buffer for the compilation parsing commands to work.
1983Optional argument MINOR indicates this is called from
1984`compilation-minor-mode'."
51c8ad03 1985 (make-local-variable 'compilation-current-error)
9b7b51a2 1986 (make-local-variable 'compilation-messages-start)
18aac618 1987 (make-local-variable 'compilation-error-screen-columns)
b3a7f48f 1988 (make-local-variable 'overlay-arrow-position)
8b71e4d1 1989 (set (make-local-variable 'overlay-arrow-string) "")
6a1cdc5b
JL
1990 (setq next-error-overlay-arrow-position nil)
1991 (add-hook 'kill-buffer-hook
1992 (lambda () (setq next-error-overlay-arrow-position nil)) nil t)
9b7b51a2
SM
1993 ;; Note that compilation-next-error-function is for interfacing
1994 ;; with the next-error function in simple.el, and it's only
1995 ;; coincidentally named similarly to compilation-next-error.
1996 (setq next-error-function 'compilation-next-error-function)
00d6fd04
MA
1997 (set (make-local-variable 'comint-file-name-prefix)
1998 (or (file-remote-p default-directory) ""))
7837c247
SM
1999 (set (make-local-variable 'compilation-locs)
2000 (make-hash-table :test 'equal :weakness 'value))
55fb9013
SM
2001 ;; It's generally preferable to use after-change-functions since they
2002 ;; can be subject to combine-after-change-calls, but if we do that, we risk
2003 ;; running our hook after font-lock, resulting in incorrect refontification.
2004 (add-hook 'before-change-functions 'compilation--flush-parse nil t)
2005 ;; Also for minor mode, since it's not permanent-local.
2006 (add-hook 'change-major-mode-hook #'compilation--remove-properties nil t)
963b2040 2007 (if minor
55fb9013 2008 (progn
f6164cdd 2009 (font-lock-add-keywords nil (compilation-mode-font-lock-keywords))
f6164cdd 2010 (if font-lock-mode
55fb9013
SM
2011 (font-lock-fontify-buffer)))
2012 (setq font-lock-defaults '(compilation-mode-font-lock-keywords t))))
0b18a8f6 2013
07b741a7
SM
2014(defun compilation--unsetup ()
2015 ;; Only for minor mode.
2016 (font-lock-remove-keywords nil (compilation-mode-font-lock-keywords))
55fb9013
SM
2017 (remove-hook 'before-change-functions 'compilation--flush-parse t)
2018 (kill-local-variable 'compilation--parsed)
2019 (compilation--remove-properties)
07b741a7
SM
2020 (if font-lock-mode
2021 (font-lock-fontify-buffer)))
2022
7052680b 2023;;;###autoload
4282eba1 2024(define-minor-mode compilation-shell-minor-mode
ac6c8639
CY
2025 "Toggle Compilation Shell minor mode.
2026With a prefix argument ARG, enable Compilation Shell minor mode
2027if ARG is positive, and disable it otherwise. If called from
2028Lisp, enable the mode if ARG is omitted or nil.
2029
2030When Compilation Shell minor mode is enabled, all the
2031error-parsing commands of the Compilation major mode are
2032available but bound to keys that don't collide with Shell mode.
2033See `compilation-mode'."
7837c247 2034 nil " Shell-Compile"
d408fed8 2035 :group 'compilation
7837c247
SM
2036 (if compilation-shell-minor-mode
2037 (compilation-setup t)
07b741a7 2038 (compilation--unsetup)))
7052680b 2039
d6bd8dca 2040;;;###autoload
4282eba1 2041(define-minor-mode compilation-minor-mode
ac6c8639
CY
2042 "Toggle Compilation minor mode.
2043With a prefix argument ARG, enable Compilation minor mode if ARG
2044is positive, and disable it otherwise. If called from Lisp,
2045enable the mode if ARG is omitted or nil.
2046
2047When Compilation minor mode is enabled, all the error-parsing
2048commands of Compilation major mode are available. See
2049`compilation-mode'."
7837c247 2050 nil " Compilation"
d408fed8 2051 :group 'compilation
7837c247
SM
2052 (if compilation-minor-mode
2053 (compilation-setup t)
07b741a7 2054 (compilation--unsetup)))
55dfd2c4 2055
fd5e58d7 2056(defun compilation-handle-exit (process-status exit-status msg)
f441be5b 2057 "Write MSG in the current buffer and hack its `mode-line-process'."
d42c87ab 2058 (let ((inhibit-read-only t)
fd5e58d7
RM
2059 (status (if compilation-exit-message-function
2060 (funcall compilation-exit-message-function
2061 process-status exit-status msg)
2062 (cons msg exit-status)))
2063 (omax (point-max))
c96e025a
GM
2064 (opoint (point))
2065 (cur-buffer (current-buffer)))
b3a7f48f 2066 ;; Record where we put the message, so we can ignore it later on.
fd5e58d7
RM
2067 (goto-char omax)
2068 (insert ?\n mode-name " " (car status))
0eac1faa 2069 (if (and (numberp compilation-window-height)
7837c247
SM
2070 (zerop compilation-window-height))
2071 (message "%s" (cdr status)))
01c50447
RS
2072 (if (bolp)
2073 (forward-char -1))
fd5e58d7 2074 (insert " at " (substring (current-time-string) 0 19))
01c50447 2075 (goto-char (point-max))
47092737
RS
2076 ;; Prevent that message from being recognized as a compilation error.
2077 (add-text-properties omax (point)
2078 (append '(compilation-handle-exit t) nil))
a8bdd228
DN
2079 (setq mode-line-process
2080 (let ((out-string (format ":%s [%s]" process-status (cdr status)))
a46b95a8 2081 (msg (format "%s %s" mode-name
07b741a7
SM
2082 (replace-regexp-in-string "\n?$" ""
2083 (car status)))))
a46b95a8
JL
2084 (message "%s" msg)
2085 (propertize out-string
5205d6f6
CY
2086 'help-echo msg
2087 'face (if (> exit-status 0)
2088 'compilation-mode-line-fail
2089 'compilation-mode-line-exit))))
fd5e58d7
RM
2090 ;; Force mode line redisplay soon.
2091 (force-mode-line-update)
2092 (if (and opoint (< opoint omax))
2093 (goto-char opoint))
a5f1c37e
RS
2094 (with-no-warnings
2095 (if compilation-finish-function
c96e025a
GM
2096 (funcall compilation-finish-function cur-buffer msg)))
2097 (run-hook-with-args 'compilation-finish-functions cur-buffer msg)))
fd5e58d7 2098
55dfd2c4 2099;; Called when compilation process changes state.
55dfd2c4 2100(defun compilation-sentinel (proc msg)
d3cb357b 2101 "Sentinel for compilation buffers."
b3a7f48f
DP
2102 (if (memq (process-status proc) '(exit signal))
2103 (let ((buffer (process-buffer proc)))
2104 (if (null (buffer-name buffer))
2105 ;; buffer killed
2106 (set-process-buffer proc nil)
2107 (with-current-buffer buffer
2108 ;; Write something in the compilation buffer
2109 ;; and hack its mode line.
2110 (compilation-handle-exit (process-status proc)
2111 (process-exit-status proc)
2112 msg)
2113 ;; Since the buffer and mode line will show that the
2114 ;; process is dead, we can delete it now. Otherwise it
2115 ;; will stay around until M-x list-processes.
2116 (delete-process proc)))
2117 (setq compilation-in-progress (delq proc compilation-in-progress)))))
55dfd2c4 2118
ad62b7f1
RM
2119(defun compilation-filter (proc string)
2120 "Process filter for compilation buffers.
20179516
SS
2121Just inserts the text,
2122handles carriage motion (see `comint-inhibit-carriage-motion'),
2123and runs `compilation-filter-hook'."
ec4e0abc
SM
2124 (when (buffer-live-p (process-buffer proc))
2125 (with-current-buffer (process-buffer proc)
2126 (let ((inhibit-read-only t)
2127 ;; `save-excursion' doesn't use the right insertion-type for us.
0b508a27 2128 (pos (copy-marker (point) t))
07b741a7
SM
2129 ;; `save-restriction' doesn't use the right insertion type either:
2130 ;; If we are inserting at the end of the accessible part of the
2131 ;; buffer, keep the inserted text visible.
0b508a27 2132 (min (point-min-marker))
d9c54a06
CY
2133 (max (copy-marker (point-max) t))
2134 (compilation-filter-start (marker-position (process-mark proc))))
ec4e0abc
SM
2135 (unwind-protect
2136 (progn
0b508a27 2137 (widen)
d9c54a06 2138 (goto-char compilation-filter-start)
ec4e0abc
SM
2139 ;; We used to use `insert-before-markers', so that windows with
2140 ;; point at `process-mark' scroll along with the output, but we
2141 ;; now use window-point-insertion-type instead.
2142 (insert string)
20179516
SS
2143 (unless comint-inhibit-carriage-motion
2144 (comint-carriage-motion (process-mark proc) (point)))
ec4e0abc 2145 (set-marker (process-mark proc) (point))
8fe52384
SM
2146 ;; (set (make-local-variable 'compilation-buffer-modtime)
2147 ;; (current-time))
ec4e0abc 2148 (run-hooks 'compilation-filter-hook))
0b508a27
RS
2149 (goto-char pos)
2150 (narrow-to-region min max)
07b741a7 2151 (set-marker pos nil)
0b508a27
RS
2152 (set-marker min nil)
2153 (set-marker max nil))))))
b5bb472e 2154
5d9f0de2
KS
2155;;; test if a buffer is a compilation buffer, assuming we're in the buffer
2156(defsubst compilation-buffer-internal-p ()
2157 "Test if inside a compilation buffer."
2158 (local-variable-p 'compilation-locs))
2159
2160;;; test if a buffer is a compilation buffer, using compilation-buffer-internal-p
51ba27e7 2161(defsubst compilation-buffer-p (buffer)
5d9f0de2
KS
2162 "Test if BUFFER is a compilation buffer."
2163 (with-current-buffer buffer
2164 (compilation-buffer-internal-p)))
7837c247 2165
060d5dc1
CY
2166(defmacro compilation-loop (< property-change 1+ error limit)
2167 `(let (opt)
2168 (while (,< n 0)
2169 (setq opt pt)
07b741a7 2170 (or (setq pt (,property-change pt 'compilation-message))
060d5dc1
CY
2171 ;; Handle the case where where the first error message is
2172 ;; at the start of the buffer, and n < 0.
07b741a7
SM
2173 (if (or (eq (get-text-property ,limit 'compilation-message)
2174 (get-text-property opt 'compilation-message))
060d5dc1 2175 (eq pt opt))
71873e2b 2176 (user-error ,error compilation-error)
060d5dc1 2177 (setq pt ,limit)))
07b741a7 2178 ;; prop 'compilation-message usually has 2 changes, on and off, so
060d5dc1 2179 ;; re-search if off
07b741a7
SM
2180 (or (setq msg (get-text-property pt 'compilation-message))
2181 (if (setq pt (,property-change pt 'compilation-message nil ,limit))
2182 (setq msg (get-text-property pt 'compilation-message)))
71873e2b 2183 (user-error ,error compilation-error))
8fe52384 2184 (or (< (compilation--message->type msg) compilation-skip-threshold)
060d5dc1 2185 (if different-file
8fe52384
SM
2186 (eq (prog1 last
2187 (setq last (compilation--loc->file-struct
2188 (compilation--message->loc msg))))
060d5dc1
CY
2189 last))
2190 (if compilation-skip-visited
8fe52384 2191 (compilation--loc->visited (compilation--message->loc msg)))
060d5dc1 2192 (if compilation-skip-to-next-location
8fe52384 2193 (eq (compilation--message->loc msg) loc))
060d5dc1
CY
2194 ;; count this message only if none of the above are true
2195 (setq n (,1+ n))))))
7837c247 2196
55fb9013
SM
2197(defun compilation-next-single-property-change (position prop
2198 &optional object limit)
2199 (let (parsed res)
2200 (while (progn
2201 ;; We parse the buffer here "on-demand" by chunks of 500 chars.
2202 ;; But we could also just parse the whole buffer.
2203 (compilation--ensure-parse
2204 (setq parsed (max compilation--parsed
2205 (min (+ position 500)
2206 (or limit (point-max))))))
2207 (and (or (not (setq res (next-single-property-change
2208 position prop object limit)))
2209 (eq res limit))
2210 (< position (or limit (point-max)))))
2211 (setq position parsed))
2212 res))
2213
51c8ad03 2214(defun compilation-next-error (n &optional different-file pt)
646bd331 2215 "Move point to the next error in the compilation buffer.
d0048c60 2216This function does NOT find the source line like \\[next-error].
851231e9
DL
2217Prefix arg N says how many error messages to move forwards (or
2218backwards, if negative).
d0048c60
EZ
2219Optional arg DIFFERENT-FILE, if non-nil, means find next error for a
2220file that is different from the current one.
2221Optional arg PT, if non-nil, specifies the value of point to start
2222looking for the next message."
646bd331
RM
2223 (interactive "p")
2224 (or (compilation-buffer-p (current-buffer))
851231e9 2225 (error "Not in a compilation buffer"))
51c8ad03 2226 (or pt (setq pt (point)))
07b741a7 2227 (let* ((msg (get-text-property pt 'compilation-message))
8fe52384 2228 ;; `loc', `msg', and `last' are used by the compilation-loop macro.
7d116647 2229 (loc (and msg (compilation--message->loc msg)))
51c8ad03 2230 last)
7837c247
SM
2231 (if (zerop n)
2232 (unless (or msg ; find message near here
c536bb39 2233 (setq msg (get-text-property (max (1- pt) (point-min))
07b741a7
SM
2234 'compilation-message)))
2235 (setq pt (previous-single-property-change pt 'compilation-message nil
c536bb39 2236 (line-beginning-position)))
07b741a7
SM
2237 (unless (setq msg (get-text-property (max (1- pt) (point-min))
2238 'compilation-message))
2239 (setq pt (next-single-property-change pt 'compilation-message nil
c536bb39 2240 (line-end-position)))
07b741a7 2241 (or (setq msg (get-text-property pt 'compilation-message))
b3a7f48f 2242 (setq pt (point)))))
7d116647 2243 (setq last (compilation--loc->file-struct loc))
51c8ad03 2244 (if (>= n 0)
55fb9013 2245 (compilation-loop > compilation-next-single-property-change 1-
51c8ad03
DP
2246 (if (get-buffer-process (current-buffer))
2247 "No more %ss yet"
060d5dc1
CY
2248 "Moved past last %s")
2249 (point-max))
55fb9013 2250 (compilation--ensure-parse pt)
c536bb39
SM
2251 ;; Don't move "back" to message at or before point.
2252 ;; Pass an explicit (point-min) to make sure pt is non-nil.
07b741a7
SM
2253 (setq pt (previous-single-property-change
2254 pt 'compilation-message nil (point-min)))
51c8ad03 2255 (compilation-loop < previous-single-property-change 1+
060d5dc1 2256 "Moved back before first %s" (point-min))))
7837c247
SM
2257 (goto-char pt)
2258 (or msg
2259 (error "No %s here" compilation-error))))
646bd331
RM
2260
2261(defun compilation-previous-error (n)
2262 "Move point to the previous error in the compilation buffer.
851231e9
DL
2263Prefix arg N says how many error messages to move backwards (or
2264forwards, if negative).
7837c247 2265Does NOT find the source line like \\[previous-error]."
646bd331
RM
2266 (interactive "p")
2267 (compilation-next-error (- n)))
2268
b5bb472e 2269(defun compilation-next-file (n)
24299582
DP
2270 "Move point to the next error for a different file than the current one.
2271Prefix arg N says how many files to move forwards (or backwards, if negative)."
b5bb472e 2272 (interactive "p")
7837c247 2273 (compilation-next-error n t))
b5bb472e
RM
2274
2275(defun compilation-previous-file (n)
24299582
DP
2276 "Move point to the previous error for a different file than the current one.
2277Prefix arg N says how many files to move backwards (or forwards, if negative)."
b5bb472e
RM
2278 (interactive "p")
2279 (compilation-next-file (- n)))
2280
55dfd2c4 2281(defun kill-compilation ()
b765ba64 2282 "Kill the process made by the \\[compile] or \\[grep] commands."
55dfd2c4 2283 (interactive)
d3cb357b 2284 (let ((buffer (compilation-find-buffer)))
55dfd2c4 2285 (if (get-buffer-process buffer)
d3cb357b 2286 (interrupt-process (get-buffer-process buffer))
bac3a1c9 2287 (error "The %s process is not running" (downcase mode-name)))))
d3cb357b 2288
9da85ee5 2289(defalias 'compile-mouse-goto-error 'compile-goto-error)
c536bb39 2290
9da85ee5
SM
2291(defun compile-goto-error (&optional event)
2292 "Visit the source for the error message at point.
7837c247 2293Use this command in a compilation log buffer. Sets the mark at point there."
9da85ee5 2294 (interactive (list last-input-event))
a6cd3f65 2295 (if event (posn-set-point (event-end event)))
d3cb357b 2296 (or (compilation-buffer-p (current-buffer))
851231e9 2297 (error "Not in a compilation buffer"))
55fb9013 2298 (compilation--ensure-parse (point))
07b741a7
SM
2299 (if (get-text-property (point) 'compilation-directory)
2300 (dired-other-window
2301 (car (get-text-property (point) 'compilation-directory)))
b3a7f48f
DP
2302 (push-mark)
2303 (setq compilation-current-error (point))
942c40e3 2304 (next-error-internal)))
55dfd2c4 2305
07b741a7
SM
2306;; This is mostly unused, but we keep it for the sake of some external
2307;; packages which seem to make use of it.
749354f0 2308(defun compilation-find-buffer (&optional avoid-current)
7d1dad0c 2309 "Return a compilation buffer.
0dad3dfe
MR
2310If AVOID-CURRENT is nil, and the current buffer is a compilation buffer,
2311return it. If AVOID-CURRENT is non-nil, return the current buffer only
2312as a last resort."
2313 (if (and (compilation-buffer-internal-p) (not avoid-current))
7d1dad0c
RS
2314 (current-buffer)
2315 (next-error-find-buffer avoid-current 'compilation-buffer-internal-p)))
d3cb357b
RM
2316
2317;;;###autoload
5d9f0de2 2318(defun compilation-next-error-function (n &optional reset)
a5f1c37e
RS
2319 "Advance to the next error message and visit the file where the error was.
2320This is the value of `next-error-function' in Compilation buffers."
7837c247 2321 (interactive "p")
5d9f0de2
KS
2322 (when reset
2323 (setq compilation-current-error nil))
1dce7193 2324 (let* ((screen-columns compilation-error-screen-columns)
5ddce96c 2325 (first-column compilation-first-column)
e02f48d7 2326 (last 1)
07b741a7 2327 (msg (compilation-next-error (or n 1) nil
9b7b51a2
SM
2328 (or compilation-current-error
2329 compilation-messages-start
2330 (point-min))))
8fe52384
SM
2331 (loc (compilation--message->loc msg))
2332 (end-loc (compilation--message->end-loc msg))
7837c247 2333 (marker (point-marker)))
51c8ad03 2334 (setq compilation-current-error (point-marker)
b3a7f48f
DP
2335 overlay-arrow-position
2336 (if (bolp)
2337 compilation-current-error
07b741a7 2338 (copy-marker (line-beginning-position))))
b84acff6
SS
2339 ;; If loc contains no marker, no error in that file has been visited.
2340 ;; If the marker is invalid the buffer has been killed.
b84acff6 2341 ;; So, recalculate all markers for that file.
8fe52384
SM
2342 (unless (and (compilation--loc->marker loc)
2343 (marker-buffer (compilation--loc->marker loc))
2344 ;; FIXME-omake: For "omake -P", which automatically recompiles
2345 ;; when the file is modified, the line numbers of new output
2346 ;; may not be related to line numbers from earlier output
2347 ;; (earlier markers), so we used to try to detect it here and
2348 ;; force a reparse. But that caused more problems elsewhere,
2349 ;; so instead we now flush the file-structure when we see
2350 ;; omake's message telling it's about to recompile a file.
2351 ;; (or (null (compilation--loc->timestamp loc)) ;A fake-loc
2352 ;; (equal (compilation--loc->timestamp loc)
2353 ;; (setq timestamp compilation-buffer-modtime)))
2354 )
2355 (with-current-buffer
2356 (compilation-find-file
2357 marker
2358 (caar (compilation--loc->file-struct loc))
2359 (cadr (car (compilation--loc->file-struct loc))))
1dce7193
SM
2360 (let ((screen-columns
2361 ;; Obey the compilation-error-screen-columns of the target
2362 ;; buffer if its major mode set it buffer-locally.
2363 (if (local-variable-p 'compilation-error-screen-columns)
5ddce96c
GM
2364 compilation-error-screen-columns screen-columns))
2365 (compilation-first-column
2366 (if (local-variable-p 'compilation-first-column)
2367 compilation-first-column first-column)))
1dce7193
SM
2368 (save-restriction
2369 (widen)
2370 (goto-char (point-min))
2371 ;; Treat file's found lines in forward order, 1 by 1.
2372 (dolist (line (reverse (cddr (compilation--loc->file-struct loc))))
2373 (when (car line) ; else this is a filename w/o a line#
2374 (beginning-of-line (- (car line) last -1))
2375 (setq last (car line)))
2376 ;; Treat line's found columns and store/update a marker for each.
2377 (dolist (col (cdr line))
2378 (if (compilation--loc->col col)
2379 (if (eq (compilation--loc->col col) -1)
2380 ;; Special case for range end.
2381 (end-of-line)
2382 (compilation-move-to-column (compilation--loc->col col)
2383 screen-columns))
2384 (beginning-of-line)
2385 (skip-chars-forward " \t"))
2386 (if (compilation--loc->marker col)
2387 (set-marker (compilation--loc->marker col) (point))
2388 (setf (compilation--loc->marker col) (point-marker)))
2389 ;; (setf (compilation--loc->timestamp col) timestamp)
2390 ))))))
8fe52384
SM
2391 (compilation-goto-locus marker (compilation--loc->marker loc)
2392 (compilation--loc->marker end-loc))
2393 (setf (compilation--loc->visited loc) t)))
7837c247 2394
e3bef839
SM
2395(defvar compilation-gcpro nil
2396 "Internal variable used to keep some values from being GC'd.")
2397(make-variable-buffer-local 'compilation-gcpro)
2398
eb6fb6e2
DP
2399(defun compilation-fake-loc (marker file &optional line col)
2400 "Preassociate MARKER with FILE.
dbd97672 2401FILE should be ABSOLUTE-FILENAME or (RELATIVE-FILENAME . DIRNAME).
eb6fb6e2
DP
2402This is useful when you compile temporary files, but want
2403automatic translation of the messages to the real buffer from
07b741a7
SM
2404which the temporary file came. This may also affect previous messages
2405about FILE.
eb6fb6e2
DP
2406
2407Optional args LINE and COL default to 1 and beginning of
2408indentation respectively. The marker is expected to reflect
2409this. In the simplest case the marker points to the first line
2410of the region that was saved to the temp file.
2411
2412If you concatenate several regions into the temp file (e.g. a
2413header with variable assignments and a code region), you must
2414call this several times, once each for the last line of one
2415region and the first line of the next region."
2416 (or (consp file) (setq file (list file)))
07b741a7
SM
2417 (compilation--flush-file-structure file)
2418 (let ((fs (compilation-get-file-structure file)))
2419 ;; Between the current call to compilation-fake-loc and the first
2420 ;; occurrence of an error message referring to `file', the data is
2421 ;; only kept in the weak hash-table compilation-locs, so we need
2422 ;; to prevent this entry in compilation-locs from being GC'd
2423 ;; away. --Stef
2424 (push fs compilation-gcpro)
2425 (let ((loc (compilation-assq (or line 1) (cdr fs))))
2426 (setq loc (compilation-assq col loc))
a464a6c7 2427 (cl-assert (null (cdr loc)))
8fe52384 2428 (setcdr loc (compilation--make-cdrloc line fs marker))
07b741a7 2429 loc)))
eb6fb6e2 2430
8b71e4d1
NR
2431(defcustom compilation-context-lines nil
2432 "Display this many lines of leading context before the current message.
2433If nil and the left fringe is displayed, don't scroll the
2434compilation output window; an arrow in the left fringe points to
2435the current message. If nil and there is no left fringe, the message
2436displays at the top of the window; there is no arrow."
a3a9c080 2437 :type '(choice integer (const :tag "No window scrolling" nil))
f6164cdd 2438 :group 'compilation
bf247b6e 2439 :version "22.1")
7837c247
SM
2440
2441(defsubst compilation-set-window (w mk)
6f5b7627 2442 "Align the compilation output window W with marker MK near top."
a3a9c080
JL
2443 (if (integerp compilation-context-lines)
2444 (set-window-start w (save-excursion
8b71e4d1
NR
2445 (goto-char mk)
2446 (beginning-of-line
2447 (- 1 compilation-context-lines))
2448 (point)))
3c9e7f42
RS
2449 ;; If there is no left fringe.
2450 (if (equal (car (window-fringes)) 0)
8b71e4d1
NR
2451 (set-window-start w (save-excursion
2452 (goto-char mk)
2453 (beginning-of-line 1)
2454 (point)))))
2455 (set-window-point w mk))
7837c247 2456
0ea50e43
RS
2457(defvar next-error-highlight-timer)
2458
7837c247 2459(defun compilation-goto-locus (msg mk end-mk)
6f5b7627 2460 "Jump to an error corresponding to MSG at MK.
9dc3a46a
JL
2461All arguments are markers. If END-MK is non-nil, mark is set there
2462and overlay is highlighted between MK and END-MK."
eaa3cac5 2463 ;; Show compilation buffer in other window, scrolled to this error.
e5456e73
SM
2464 (let* ((from-compilation-buffer (eq (window-buffer (selected-window))
2465 (marker-buffer msg)))
2466 ;; Use an existing window if it is in a visible frame.
7bbbd31f 2467 (pre-existing (get-buffer-window (marker-buffer msg) 0))
e5456e73
SM
2468 (w (if (and from-compilation-buffer pre-existing)
2469 ;; Calling display-buffer here may end up (partly) hiding
2470 ;; the error location if the two buffers are in two
2471 ;; different frames. So don't do it if it's not necessary.
2472 pre-existing
77f1f99c 2473 (display-buffer (marker-buffer msg))))
7837c247
SM
2474 (highlight-regexp (with-current-buffer (marker-buffer msg)
2475 ;; also do this while we change buffer
2476 (compilation-set-window w msg)
9ac57479 2477 compilation-highlight-regexp)))
3199b96f
CY
2478 ;; Ideally, the window-size should be passed to `display-buffer'
2479 ;; so it's only used when creating a new window.
7bbbd31f 2480 (unless pre-existing (compilation-set-window-height w))
9ac57479 2481
e5456e73
SM
2482 (if from-compilation-buffer
2483 ;; If the compilation buffer window was selected,
2484 ;; keep the compilation buffer in this window;
2485 ;; display the source in another window.
2486 (let ((pop-up-windows t))
2487 (pop-to-buffer (marker-buffer mk) 'other-window))
c3313451 2488 (switch-to-buffer (marker-buffer mk)))
e5456e73 2489 (unless (eq (goto-char mk) (point))
1fc01b08 2490 ;; If narrowing gets in the way of going to the right place, widen.
e5456e73 2491 (widen)
1fc01b08
RS
2492 (if next-error-move-function
2493 (funcall next-error-move-function msg mk)
2494 (goto-char mk)))
e5456e73
SM
2495 (if end-mk
2496 (push-mark end-mk t)
2497 (if mark-active (setq mark-active)))
2498 ;; If hideshow got in the way of
2499 ;; seeing the right place, open permanently.
2500 (dolist (ov (overlays-at (point)))
2501 (when (eq 'hs (overlay-get ov 'invisible))
2502 (delete-overlay ov)
2503 (goto-char mk)))
2504
9dc3a46a 2505 (when highlight-regexp
073fcaf6
JL
2506 (if (timerp next-error-highlight-timer)
2507 (cancel-timer next-error-highlight-timer))
9ac57479 2508 (unless compilation-highlight-overlay
c536bb39
SM
2509 (setq compilation-highlight-overlay
2510 (make-overlay (point-min) (point-min)))
2beb6aa0 2511 (overlay-put compilation-highlight-overlay 'face 'next-error))
7837c247 2512 (with-current-buffer (marker-buffer mk)
9ac57479 2513 (save-excursion
9dc3a46a 2514 (if end-mk (goto-char end-mk) (end-of-line))
c536bb39 2515 (let ((end (point)))
9dc3a46a 2516 (if mk (goto-char mk) (beginning-of-line))
9ac57479 2517 (if (and (stringp highlight-regexp)
7837c247 2518 (re-search-forward highlight-regexp end t))
9ac57479
KS
2519 (progn
2520 (goto-char (match-beginning 0))
2beb6aa0
JL
2521 (move-overlay compilation-highlight-overlay
2522 (match-beginning 0) (match-end 0)
2523 (current-buffer)))
2524 (move-overlay compilation-highlight-overlay
2525 (point) end (current-buffer)))
63522e3a
RS
2526 (if (or (eq next-error-highlight t)
2527 (numberp next-error-highlight))
2528 ;; We want highlighting: delete overlay on next input.
2529 (add-hook 'pre-command-hook
2530 'compilation-goto-locus-delete-o)
2531 ;; We don't want highlighting: delete overlay now.
2532 (delete-overlay compilation-highlight-overlay))
2533 ;; We want highlighting for a limited time:
2534 ;; set up a timer to delete it.
2535 (when (numberp next-error-highlight)
2536 (setq next-error-highlight-timer
2537 (run-at-time next-error-highlight nil
2538 'compilation-goto-locus-delete-o)))))))
2beb6aa0 2539 (when (and (eq next-error-highlight 'fringe-arrow))
63522e3a 2540 ;; We want a fringe arrow (instead of highlighting).
6a1cdc5b
JL
2541 (setq next-error-overlay-arrow-position
2542 (copy-marker (line-beginning-position))))))
2543
63522e3a
RS
2544(defun compilation-goto-locus-delete-o ()
2545 (delete-overlay compilation-highlight-overlay)
2546 ;; Get rid of timer and hook that would try to do this again.
2547 (if (timerp next-error-highlight-timer)
2548 (cancel-timer next-error-highlight-timer))
2549 (remove-hook 'pre-command-hook
2550 'compilation-goto-locus-delete-o))
eaa3cac5 2551\f
7957baea 2552(defun compilation-find-file (marker filename directory &rest formats)
851231e9 2553 "Find a buffer for file FILENAME.
5099d512
EZ
2554If FILENAME is not found at all, ask the user where to find it.
2555Pop up the buffer containing MARKER and scroll to MARKER if we ask
2556the user where to find the file.
ffb4b7a1
SM
2557Search the directories in `compilation-search-path'.
2558A nil in `compilation-search-path' means to try the
7957baea 2559\"current\" directory, which is passed in DIRECTORY.
f441be5b
JB
2560If DIRECTORY is relative, it is combined with `default-directory'.
2561If DIRECTORY is nil, that means use `default-directory'.
5099d512
EZ
2562FORMATS, if given, is a list of formats to reformat FILENAME when
2563looking for it: for each element FMT in FORMATS, this function
2564attempts to find a file whose name is produced by (format FMT FILENAME)."
20c1daec 2565 (or formats (setq formats '("%s")))
b8fa0ffd
SM
2566 (let ((dirs compilation-search-path)
2567 (spec-dir (if directory
2568 (expand-file-name directory)
2569 default-directory))
2570 buffer thisdir fmts name)
2571 (if (file-name-absolute-p filename)
2572 ;; The file name is absolute. Use its explicit directory as
2573 ;; the first in the search path, and strip it from FILENAME.
2574 (setq filename (abbreviate-file-name (expand-file-name filename))
2575 dirs (cons (file-name-directory filename) dirs)
2576 filename (file-name-nondirectory filename)))
2577 ;; Now search the path.
2578 (while (and dirs (null buffer))
2579 (setq thisdir (or (car dirs) spec-dir)
2580 fmts formats)
2581 ;; For each directory, try each format string.
2582 (while (and fmts (null buffer))
2583 (setq name (expand-file-name (format (car fmts) filename) thisdir)
2584 buffer (and (file-exists-p name)
2585 (find-file-noselect name))
2586 fmts (cdr fmts)))
2587 (setq dirs (cdr dirs)))
f65b9df2
SM
2588 (while (null buffer) ;Repeat until the user selects an existing file.
2589 ;; The file doesn't exist. Ask the user where to find it.
2590 (save-excursion ;This save-excursion is probably not right.
2591 (let ((pop-up-windows t))
2592 (compilation-set-window (display-buffer (marker-buffer marker))
2593 marker)
2594 (let* ((name (read-file-name
2595 (format "Find this %s in (default %s): "
2596 compilation-error filename)
44038dc8
SM
2597 spec-dir filename t nil
2598 ;; The predicate below is fine when called from
2599 ;; minibuffer-complete-and-exit, but it's too
2600 ;; restrictive otherwise, since it also prevents the
2601 ;; user from completing "fo" to "foo/" when she
2602 ;; wants to enter "foo/bar".
f441be5b 2603 ;;
44038dc8
SM
2604 ;; Try to make sure the user can only select
2605 ;; a valid answer. This predicate may be ignored,
2606 ;; tho, so we still have to double-check afterwards.
2607 ;; TODO: We should probably fix read-file-name so
2608 ;; that it never ignores this predicate, even when
2609 ;; using popup dialog boxes.
2610 ;; (lambda (name)
2611 ;; (if (file-directory-p name)
2612 ;; (setq name (expand-file-name filename name)))
2613 ;; (file-exists-p name))
2614 ))
f65b9df2
SM
2615 (origname name))
2616 (cond
2617 ((not (file-exists-p name))
2618 (message "Cannot find file `%s'" name)
2619 (ding) (sit-for 2))
2620 ((and (file-directory-p name)
2621 (not (file-exists-p
2622 (setq name (expand-file-name filename name)))))
2623 (message "No `%s' in directory %s" filename origname)
2624 (ding) (sit-for 2))
2625 (t
2626 (setq buffer (find-file-noselect name))))))))
b8fa0ffd 2627 ;; Make intangible overlays tangible.
f65b9df2
SM
2628 ;; This is weird: it's not even clear which is the current buffer,
2629 ;; so the code below can't be expected to DTRT here. -- Stef
2630 (dolist (ov (overlays-in (point-min) (point-max)))
2631 (when (overlay-get ov 'intangible)
2632 (overlay-put ov 'intangible nil)))
b8fa0ffd 2633 buffer))
721cfafe 2634
dbd97672
DP
2635(defun compilation-get-file-structure (file &optional fmt)
2636 "Retrieve FILE's file-structure or create a new one.
7957baea
RS
2637FILE should be (FILENAME) or (RELATIVE-FILENAME . DIRNAME).
2638In the former case, FILENAME may be relative or absolute.
dbd97672 2639
7957baea 2640The file-structure looks like this:
07b741a7 2641 ((FILENAME [DIR-FROM-PREV-MSG]) FMT LINE-STRUCT...)"
dbd97672
DP
2642 (or (gethash file compilation-locs)
2643 ;; File was not previously encountered, at least not in the form passed.
2644 ;; Let's normalize it and look again.
2645 (let ((filename (car file))
7957baea
RS
2646 ;; Get the specified directory from FILE.
2647 (spec-directory (if (cdr file)
2648 (file-truename (cdr file)))))
dbd97672
DP
2649
2650 ;; Check for a comint-file-name-prefix and prepend it if appropriate.
2651 ;; (This is very useful for compilation-minor-mode in an rlogin-mode
2652 ;; buffer.)
7957baea
RS
2653 (when (and (boundp 'comint-file-name-prefix)
2654 (not (equal comint-file-name-prefix "")))
2655 (if (file-name-absolute-p filename)
2656 (setq filename
2657 (concat comint-file-name-prefix filename))
2658 (if spec-directory
2659 (setq spec-directory
2660 (file-truename
2661 (concat comint-file-name-prefix spec-directory))))))
dbd97672
DP
2662
2663 ;; If compilation-parse-errors-filename-function is
2664 ;; defined, use it to process the filename.
2665 (when compilation-parse-errors-filename-function
2666 (setq filename
2667 (funcall compilation-parse-errors-filename-function
2668 filename)))
2669
2670 ;; Some compilers (e.g. Sun's java compiler, reportedly) produce bogus
2671 ;; file names like "./bar//foo.c" for file "bar/foo.c";
2672 ;; expand-file-name will collapse these into "/foo.c" and fail to find
2673 ;; the appropriate file. So we look for doubled slashes in the file
2674 ;; name and fix them.
2675 (setq filename (command-line-normalize-file-name filename))
2676
dbd97672
DP
2677 ;; Store it for the possibly unnormalized name
2678 (puthash file
2679 ;; Retrieve or create file-structure for normalized name
e68b1841
GM
2680 ;; The gethash used to not use spec-directory, but
2681 ;; this leads to errors when files in different
2682 ;; directories have the same name:
2683 ;; http://lists.gnu.org/archive/html/emacs-devel/2007-08/msg00463.html
2684 (or (gethash (cons filename spec-directory) compilation-locs)
34a9bf20 2685 (puthash (cons filename spec-directory)
8fe52384
SM
2686 (compilation--make-file-struct
2687 (list filename spec-directory) fmt)
7957baea 2688 compilation-locs))
dbd97672 2689 compilation-locs))))
51501e54 2690
07b741a7
SM
2691(defun compilation--flush-file-structure (file)
2692 (or (consp file) (setq file (list file)))
2693 (let ((fs (compilation-get-file-structure file)))
a464a6c7
SM
2694 (cl-assert (eq fs (gethash file compilation-locs)))
2695 (cl-assert (eq fs (gethash (cons (caar fs) (cadr (car fs)))
07b741a7
SM
2696 compilation-locs)))
2697 (maphash (lambda (k v)
2698 (if (eq v fs) (remhash k compilation-locs)))
2699 compilation-locs)))
2700
c536bb39
SM
2701;;; Compatibility with the old compile.el.
2702
07b741a7
SM
2703(defvaralias 'compilation-last-buffer 'next-error-last-buffer)
2704(defvar compilation-parsing-end (make-marker))
2705(defvar compilation-error-list nil)
2706(defvar compilation-old-error-list nil)
c536bb39 2707
07b741a7 2708(defun compilation--compat-error-properties (err)
6f5b7627 2709 "Map old-style error ERR to new-style message."
efb0e677
SM
2710 ;; Old-style structure is (MARKER (FILE DIR) LINE COL) or
2711 ;; (MARKER . MARKER).
2712 (let ((dst (cdr err)))
2713 (if (markerp dst)
55fb9013 2714 `(compilation-message ,(compilation--make-message
8fe52384
SM
2715 (cons nil (compilation--make-cdrloc
2716 nil nil dst))
2717 2 nil)
efb0e677
SM
2718 help-echo "mouse-2: visit the source location"
2719 keymap compilation-button-map
2720 mouse-face highlight)
2721 ;; Too difficult to do it by hand: dispatch to the normal code.
2722 (let* ((file (pop dst))
2723 (line (pop dst))
2724 (col (pop dst))
2725 (filename (pop file))
2726 (dirname (pop file))
2727 (fmt (pop file)))
2728 (compilation-internal-error-properties
2729 (cons filename dirname) line nil col nil 2 fmt)))))
c536bb39 2730
07b741a7 2731(defun compilation--compat-parse-errors (limit)
c536bb39
SM
2732 (when compilation-parse-errors-function
2733 ;; FIXME: We should remove the rest of the compilation keywords
2734 ;; but we can't do that from here because font-lock is using
07b741a7 2735 ;; the value right now. --Stef
c536bb39
SM
2736 (save-excursion
2737 (setq compilation-error-list nil)
2738 ;; Reset compilation-parsing-end each time because font-lock
2739 ;; might force us the re-parse many times (typically because
2740 ;; some code adds some text-property to the output that we
2741 ;; already parsed). You might say "why reparse", well:
07b741a7
SM
2742 ;; because font-lock has just removed the `compilation-message' property
2743 ;; so have to do it all over again.
c536bb39
SM
2744 (if compilation-parsing-end
2745 (set-marker compilation-parsing-end (point))
2746 (setq compilation-parsing-end (point-marker)))
2747 (condition-case nil
2748 ;; Ignore any error: we're calling this function earlier than
2749 ;; in the old compile.el so things might not all be setup yet.
2750 (funcall compilation-parse-errors-function limit nil)
2751 (error nil))
2752 (dolist (err (if (listp compilation-error-list) compilation-error-list))
2753 (let* ((src (car err))
2754 (dst (cdr err))
8fe52384
SM
2755 (loc (cond ((markerp dst)
2756 (cons nil
2757 (compilation--make-cdrloc nil nil dst)))
c536bb39 2758 ((consp dst)
8fe52384
SM
2759 (cons (nth 2 dst)
2760 (compilation--make-cdrloc
2761 (nth 1 dst)
2762 (cons (cdar dst) (caar dst))
2763 nil))))))
c536bb39
SM
2764 (when loc
2765 (goto-char src)
07b741a7
SM
2766 ;; (put-text-property src (line-end-position)
2767 ;; 'font-lock-face 'font-lock-warning-face)
c536bb39 2768 (put-text-property src (line-end-position)
8fe52384
SM
2769 'compilation-message
2770 (compilation--make-message loc 2 nil)))))))
c536bb39
SM
2771 (goto-char limit)
2772 nil)
2773
07b741a7 2774;; Beware! this is not only compatibility code. New code also uses it. --Stef
c536bb39
SM
2775(defun compilation-forget-errors ()
2776 ;; In case we hit the same file/line specs, we want to recompute a new
2777 ;; marker for them, so flush our cache.
331b2b90 2778 (clrhash compilation-locs)
e3bef839 2779 (setq compilation-gcpro nil)
c536bb39
SM
2780 ;; FIXME: the old code reset the directory-stack, so maybe we should
2781 ;; put a `directory change' marker of some sort, but where? -stef
b3a7f48f 2782 ;;
c536bb39
SM
2783 ;; FIXME: The old code moved compilation-current-error (which was
2784 ;; virtually represented by a mix of compilation-parsing-end and
2785 ;; compilation-error-list) to point-min, but that was only meaningful for
2786 ;; the internal uses of compilation-forget-errors: all calls from external
2787 ;; packages seem to be followed by a move of compilation-parsing-end to
b956d64f 2788 ;; something equivalent to point-max. So we heuristically move
c536bb39 2789 ;; compilation-current-error to point-max (since the external package
b956d64f 2790 ;; won't know that it should do it). --Stef
9b7b51a2
SM
2791 (setq compilation-current-error nil)
2792 (let* ((proc (get-buffer-process (current-buffer)))
2793 (mark (if proc (process-mark proc)))
2794 (pos (or mark (point-max))))
2795 (setq compilation-messages-start
2796 ;; In the future, ignore the text already present in the buffer.
2797 ;; Since many process filter functions insert before markers,
2798 ;; we need to put ours just before the insertion point rather
2799 ;; than at the insertion point. If that's not possible, then
2800 ;; don't use a marker. --Stef
b956d64f
SM
2801 (if (> pos (point-min)) (copy-marker (1- pos)) pos)))
2802 ;; Again, since this command is used in buffers that contain several
2803 ;; compilations, to set the beginning of "this compilation", it's a good
2804 ;; place to reset compilation-auto-jump-to-next.
2805 (set (make-local-variable 'compilation-auto-jump-to-next)
78dc87a2
JL
2806 (or compilation-auto-jump-to-first-error
2807 (eq compilation-scroll-output 'first-error))))
c536bb39 2808
4746118a 2809(provide 'compile)
fad160d5
ER
2810
2811;;; compile.el ends here