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