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