Fix for browse-url-firefox on Windows.
[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
CY
147 "^[ \t]*\\[[^] \n]+\\][ \t]*\\([^: \n]+\\):\\([0-9]+\\):\\(?:\\([0-9]+\\):\\([0-9]+\\):\\([0-9]+\\):\\)?\
148\\( warning\\)?" 1 (2 . 4) (3 . 5) (4))
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))
77b143eb 526 (" -\\(?:o[= ]?\\|-\\(?:outfile\\|output\\)[= ]\\)\\(\\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)))
f0685ed1
RS
988 (prev-struct
989 (car (nth 2 (car prev)))))
990 ;; Construct FILE . DIR from that.
991 (if prev-struct
992 (setq file (cons (car prev-struct)
993 (cadr prev-struct))))))
994 (unless file
995 (setq file '("*unknown*")))))
7837c247
SM
996 ;; All of these fields are optional, get them only if we have an index, and
997 ;; it matched some part of the message.
998 (and line
999 (setq line (match-string-no-properties line))
1000 (setq line (string-to-number line)))
1001 (and end-line
1002 (setq end-line (match-string-no-properties end-line))
1003 (setq end-line (string-to-number end-line)))
9dc3a46a
JL
1004 (if col
1005 (if (functionp col)
1006 (setq col (funcall col))
1007 (and
1008 (setq col (match-string-no-properties col))
1009 (setq col (- (string-to-number col) compilation-first-column)))))
1010 (if (and end-col (functionp end-col))
1011 (setq end-col (funcall end-col))
1012 (if (and end-col (setq end-col (match-string-no-properties end-col)))
1013 (setq end-col (- (string-to-number end-col) compilation-first-column -1))
1014 (if end-line (setq end-col -1))))
eb6fb6e2 1015 (if (consp type) ; not a static type, check what it is.
7837c247
SM
1016 (setq type (or (and (car type) (match-end (car type)) 1)
1017 (and (cdr type) (match-end (cdr type)) 0)
1018 2)))
813fb3fe
SM
1019
1020 (when (and compilation-auto-jump-to-next
1021 (>= type compilation-skip-threshold))
1022 (kill-local-variable 'compilation-auto-jump-to-next)
1023 (run-with-timer 0 nil 'compilation-auto-jump
1024 (current-buffer) (match-beginning 0)))
1025
07b741a7
SM
1026 (compilation-internal-error-properties
1027 file line end-line col end-col type fmt)))
efb0e677 1028
9c8e6c85
SM
1029(defun compilation-move-to-column (col screen)
1030 "Go to column COL on the current line.
1031If SCREEN is non-nil, columns are screen columns, otherwise, they are
1032just char-counts."
1033 (if screen
ee15d759 1034 (move-to-column (max col 0))
9c8e6c85
SM
1035 (goto-char (min (+ (line-beginning-position) col) (line-end-position)))))
1036
7957baea 1037(defun compilation-internal-error-properties (file line end-line col end-col type fmts)
efb0e677
SM
1038 "Get the meta-info that will be added as text-properties.
1039LINE, END-LINE, COL, END-COL are integers or nil.
7957baea
RS
1040TYPE can be 0, 1, or 2, meaning error, warning, or just info.
1041FILE should be (FILENAME) or (RELATIVE-FILENAME . DIRNAME) or nil.
1042FMTS is a list of format specs for transforming the file name.
1043 (See `compilation-error-regexp-alist'.)"
efb0e677 1044 (unless file (setq file '("*unknown*")))
7957baea
RS
1045 (let* ((file-struct (compilation-get-file-structure file fmts))
1046 ;; Get first already existing marker (if any has one, all have one).
1047 ;; Do this first, as the compilation-assq`s may create new nodes.
8fe52384
SM
1048 (marker-line ; a line structure
1049 (cadr (compilation--file-struct->loc-tree file-struct)))
1050 (marker
1051 (if marker-line (compilation--loc->marker (cadr marker-line))))
efb0e677
SM
1052 (compilation-error-screen-columns compilation-error-screen-columns)
1053 end-marker loc end-loc)
1054 (if (not (and marker (marker-buffer marker)))
7957baea 1055 (setq marker nil) ; no valid marker for this file
dbd97672
DP
1056 (setq loc (or line 1)) ; normalize no linenumber to line 1
1057 (catch 'marker ; find nearest loc, at least one exists
8fe52384
SM
1058 (dolist (x (cddr (compilation--file-struct->loc-tree
1059 file-struct))) ; Loop over remaining lines.
dbd97672 1060 (if (> (car x) loc) ; still bigger
efb0e677 1061 (setq marker-line x)
dbd97672
DP
1062 (if (> (- (or (car marker-line) 1) loc)
1063 (- loc (car x))) ; current line is nearer
efb0e677
SM
1064 (setq marker-line x))
1065 (throw 'marker t))))
8fe52384 1066 (setq marker (compilation--loc->marker (cadr marker-line))
dbd97672 1067 marker-line (or (car marker-line) 1))
efb0e677 1068 (with-current-buffer (marker-buffer marker)
8dfb3e16
RS
1069 (save-excursion
1070 (save-restriction
1071 (widen)
1072 (goto-char (marker-position marker))
1073 (when (or end-col end-line)
1074 (beginning-of-line (- (or end-line line) marker-line -1))
1075 (if (or (null end-col) (< end-col 0))
1076 (end-of-line)
1077 (compilation-move-to-column
1078 end-col compilation-error-screen-columns))
8fe52384 1079 (setq end-marker (point-marker)))
8dfb3e16
RS
1080 (beginning-of-line (if end-line
1081 (- line end-line -1)
1082 (- loc marker-line -1)))
1083 (if col
1084 (compilation-move-to-column
1085 col compilation-error-screen-columns)
1086 (forward-to-indentation 0))
8fe52384 1087 (setq marker (point-marker))))))
efb0e677 1088
8fe52384
SM
1089 (setq loc (compilation-assq line (compilation--file-struct->loc-tree
1090 file-struct)))
1091 (setq end-loc
efb0e677 1092 (if end-line
8fe52384
SM
1093 (compilation-assq
1094 end-col (compilation-assq
1095 end-line (compilation--file-struct->loc-tree
1096 file-struct)))
efb0e677 1097 (if end-col ; use same line element
8fe52384 1098 (compilation-assq end-col loc))))
efb0e677
SM
1099 (setq loc (compilation-assq col loc))
1100 ;; If they are new, make the loc(s) reference the file they point to.
8fe52384
SM
1101 ;; FIXME-omake: there's a problem with timestamps here: the markers
1102 ;; relative to which we computed the current `marker' have a timestamp
1103 ;; almost guaranteed to be different from compilation-buffer-modtime, so if
1104 ;; we use their timestamp, we'll never use `loc' since the timestamp won't
1105 ;; match compilation-buffer-modtime, and if we use
1106 ;; compilation-buffer-modtime then we have different timestamps for
1107 ;; locations that were computed together, which doesn't make sense either.
1108 ;; I think this points to a fundamental problem in our approach to the
1109 ;; "omake -P" problem. --Stef
1110 (or (cdr loc)
1111 (setcdr loc (compilation--make-cdrloc line file-struct marker)))
efb0e677 1112 (if end-loc
7957baea 1113 (or (cdr end-loc)
8fe52384
SM
1114 (setcdr end-loc
1115 (compilation--make-cdrloc (or end-line line) file-struct
1116 end-marker))))
efb0e677
SM
1117
1118 ;; Must start with face
55fb9013 1119 `(font-lock-face ,compilation-message-face
8fe52384 1120 compilation-message ,(compilation--make-message loc type end-loc)
07b741a7
SM
1121 help-echo ,(if col
1122 "mouse-2: visit this file, line and column"
1123 (if line
1124 "mouse-2: visit this file and line"
1125 "mouse-2: visit this file"))
1126 keymap compilation-button-map
1127 mouse-face highlight)))
7837c247 1128
55fb9013
SM
1129(defun compilation--put-prop (matchnum prop val)
1130 (when (and (integerp matchnum) (match-beginning matchnum))
1131 (put-text-property
1132 (match-beginning matchnum) (match-end matchnum)
1133 prop val)))
1134
1135(defun compilation--remove-properties (&optional start end)
1136 (with-silent-modifications
1137 ;; When compile.el used font-lock directly, we could just remove all
1138 ;; our text-properties in one go, but now that we manually place
1139 ;; font-lock-face, we have to be careful to only remove the font-lock-face
1140 ;; we placed.
1141 ;; (remove-list-of-text-properties
1142 ;; (or start (point-min)) (or end (point-max))
1143 ;; '(compilation-debug compilation-directory compilation-message
1144 ;; font-lock-face help-echo mouse-face))
1145 (let (next)
1146 (unless start (setq start (point-min)))
1147 (unless end (setq end (point-max)))
9e11271c 1148 (compilation--flush-directory-cache start end)
55fb9013
SM
1149 (while
1150 (progn
1151 (setq next (or (next-single-property-change
1152 start 'compilation-message nil end)
1153 end))
1154 (when (get-text-property start 'compilation-message)
1155 (remove-list-of-text-properties
1156 start next
1157 '(compilation-debug compilation-directory compilation-message
1158 font-lock-face help-echo mouse-face)))
1159 (< next end))
1160 (setq start next)))))
1161
1162(defun compilation--parse-region (start end)
1163 (goto-char end)
1164 (unless (bolp)
1165 ;; We generally don't like to parse partial lines.
1166 (assert (eobp))
1167 (when (let ((proc (get-buffer-process (current-buffer))))
1168 (and proc (memq (process-status proc) '(run open))))
1169 (setq end (line-beginning-position))))
1170 (compilation--remove-properties start end)
91fa27cd
SM
1171 (if compilation-parse-errors-function
1172 ;; An old package! Try the compatibility code.
55fb9013
SM
1173 (progn
1174 (goto-char start)
1175 (compilation--compat-parse-errors end))
1176
1177 ;; compilation-directory-matcher is the only part that really needs to be
1178 ;; parsed sequentially. So we could split it out, handle directories
1179 ;; like syntax-propertize, and the rest as font-lock-keywords. But since
1180 ;; we want to have it work even when font-lock is off, we'd then need to
1181 ;; use our own compilation-parsed text-property to keep track of the parts
1182 ;; that have already been parsed.
1183 (goto-char start)
1184 (while (re-search-forward (car compilation-directory-matcher)
1185 end t)
9e11271c 1186 (compilation--flush-directory-cache (match-beginning 0) (match-end 0))
55fb9013
SM
1187 (when compilation-debug
1188 (font-lock-append-text-property
1189 (match-beginning 0) (match-end 0)
1190 'compilation-debug
1191 (vector 'directory compilation-directory-matcher)))
1192 (dolist (elt (cdr compilation-directory-matcher))
1193 (add-text-properties (match-beginning (car elt))
1194 (match-end (car elt))
1195 (compilation-directory-properties
1196 (car elt) (cdr elt)))))
1197
1198 (compilation-parse-errors start end)))
1199
1200(defun compilation-parse-errors (start end &rest rules)
1201 "Parse errors between START and END.
1202The errors recognized are the ones specified in RULES which default
1203to `compilation-error-regexp-alist' if RULES is nil."
55fb9013
SM
1204 (dolist (item (or rules compilation-error-regexp-alist))
1205 (if (symbolp item)
1206 (setq item (cdr (assq item
1207 compilation-error-regexp-alist-alist))))
1208 (let ((file (nth 1 item))
1209 (line (nth 2 item))
1210 (col (nth 3 item))
1211 (type (nth 4 item))
1212 (pat (car item))
1213 end-line end-col fmt
1214 props)
1215
1216 ;; omake reports some error indented, so skip the indentation.
1217 ;; another solution is to modify (some?) regexps in
1218 ;; `compilation-error-regexp-alist'.
1219 ;; note that omake usage is not limited to ocaml and C (for stubs).
1220 ;; FIXME-omake: Doing it here seems wrong, at least it should depend on
1221 ;; whether or not omake's own error messages are recognized.
1222 (cond
1223 ((not (memq 'omake compilation-error-regexp-alist)) nil)
1224 ((string-match "\\`\\([^^]\\|^\\( \\*\\|\\[\\)\\)" pat)
1225 nil) ;; Not anchored or anchored but already allows empty spaces.
1226 (t (setq pat (concat "^ *" (substring pat 1)))))
1227
1228 (if (consp file) (setq fmt (cdr file) file (car file)))
1229 (if (consp line) (setq end-line (cdr line) line (car line)))
1230 (if (consp col) (setq end-col (cdr col) col (car col)))
1231
1232 (if (functionp line)
1233 ;; The old compile.el had here an undocumented hook that
1234 ;; allowed `line' to be a function that computed the actual
1235 ;; error location. Let's do our best.
1236 (progn
1237 (goto-char start)
1238 (while (re-search-forward pat end t)
1239 (save-match-data
1240 (when compilation-debug
1241 (font-lock-append-text-property
1242 (match-beginning 0) (match-end 0)
1243 'compilation-debug (vector 'functionp item)))
1244 (add-text-properties
1245 (match-beginning 0) (match-end 0)
1246 (compilation--compat-error-properties
1247 (funcall line (cons (match-string file)
1248 (cons default-directory
1249 (nthcdr 4 item)))
1250 (if col (match-string col))))))
1251 (compilation--put-prop
1252 file 'font-lock-face compilation-error-face)))
1253
1254 (unless (or (null (nth 5 item)) (integerp (nth 5 item)))
1255 (error "HYPERLINK should be an integer: %s" (nth 5 item)))
1256
1257 (goto-char start)
1258 (while (re-search-forward pat end t)
55fb9013
SM
1259 (when (setq props (compilation-error-properties
1260 file line end-line col end-col (or type 2) fmt))
1261
1262 (when (integerp file)
1263 (compilation--put-prop
1264 file 'font-lock-face
1265 (if (consp type)
1266 (compilation-face type)
1267 (symbol-value (aref [compilation-info-face
1268 compilation-warning-face
1269 compilation-error-face]
1270 (or type 2))))))
1271
1272 (compilation--put-prop
1273 line 'font-lock-face compilation-line-face)
1274 (compilation--put-prop
1275 end-line 'font-lock-face compilation-line-face)
1276
1277 (compilation--put-prop
1278 col 'font-lock-face compilation-column-face)
1279 (compilation--put-prop
1280 end-col 'font-lock-face compilation-column-face)
1281
1282 (dolist (extra-item (nthcdr 6 item))
1283 (let ((mn (pop extra-item)))
1284 (when (match-beginning mn)
1285 (let ((face (eval (car extra-item))))
1286 (cond
1287 ((null face))
1288 ((symbolp face)
1289 (put-text-property
1290 (match-beginning mn) (match-end mn)
1291 'font-lock-face face))
1292 (t
1293 (error "Don't know how to handle face %S"
1294 face)))))))
1295 (let ((mn (or (nth 5 item) 0)))
1296 (when compilation-debug
1297 (font-lock-append-text-property
1298 (match-beginning 0) (match-end 0)
1299 'compilation-debug (vector 'std item props)))
1300 (add-text-properties
1301 (match-beginning mn) (match-end mn)
1302 (cddr props))
1303 (font-lock-append-text-property
1304 (match-beginning mn) (match-end mn)
1305 'font-lock-face (cadr props)))))))))
1306
1307(defvar compilation--parsed -1)
1308(make-variable-buffer-local 'compilation--parsed)
1309
1310(defun compilation--ensure-parse (limit)
1311 "Make sure the text has been parsed up to LIMIT."
1312 (save-excursion
1313 (goto-char limit)
1314 (setq limit (line-beginning-position 2))
1315 (unless (markerp compilation--parsed)
1316 ;; We use a marker for compilation--parsed so that users (such as
1317 ;; grep.el) don't need to flush-parse when they modify the buffer
1318 ;; in a way that impacts buffer positions but does not require
1319 ;; re-parsing.
1320 (setq compilation--parsed (point-min-marker)))
1321 (when (< compilation--parsed limit)
1322 (let ((start (max compilation--parsed (point-min))))
1323 (move-marker compilation--parsed limit)
1324 (goto-char start)
1325 (forward-line 0) ;Not line-beginning-position: ignore (comint) fields.
1326 (with-silent-modifications
1327 (compilation--parse-region (point) compilation--parsed)))))
1328 nil)
1329
e02f48d7 1330(defun compilation--flush-parse (start _end)
55fb9013 1331 "Mark the region between START and END for re-parsing."
55fb9013
SM
1332 (if (markerp compilation--parsed)
1333 (move-marker compilation--parsed (min start compilation--parsed))))
1334
1335(defun compilation-mode-font-lock-keywords ()
1336 "Return expressions to highlight in Compilation mode."
1337 (append
1338 '((compilation--ensure-parse))
1339 compilation-mode-font-lock-keywords))
7837c247 1340
430aee8b
SS
1341(defun compilation-read-command (command)
1342 (read-shell-command "Compile command: " command
1343 (if (equal (car compile-history) command)
1344 '(compile-history . 1)
1345 'compile-history)))
1346
01f89d11 1347\f
d3cb357b 1348;;;###autoload
7837c247 1349(defun compile (command &optional comint)
55dfd2c4
RS
1350 "Compile the program including the current buffer. Default: run `make'.
1351Runs COMMAND, a shell command, in a separate process asynchronously
1352with output going to the buffer `*compilation*'.
d3cb357b 1353
55dfd2c4
RS
1354You can then use the command \\[next-error] to find the next error message
1355and move to the source code that caused it.
1356
8f72171b
RS
1357If optional second arg COMINT is t the buffer will be in Comint mode with
1358`compilation-shell-minor-mode'.
1359
08b1edf4
RM
1360Interactively, prompts for the command if `compilation-read-command' is
1361non-nil; otherwise uses `compile-command'. With prefix arg, always prompts.
c39bf546
DP
1362Additionally, with universal prefix arg, compilation buffer will be in
1363comint mode, i.e. interactive.
08b1edf4 1364
7d1dad0c 1365To run more than one compilation at once, start one then rename
c72095b3 1366the \`*compilation*' buffer to some other name with
7d1dad0c
RS
1367\\[rename-buffer]. Then _switch buffers_ and start the new compilation.
1368It will create a new \`*compilation*' buffer.
1369
1370On most systems, termination of the main compilation process
1371kills its subprocesses.
d3cb357b
RM
1372
1373The name used for the buffer is actually whatever is returned by
1374the function in `compilation-buffer-name-function', so you can set that
1375to a function that generates a unique name."
90016295 1376 (interactive
c39bf546 1377 (list
20320c65
JL
1378 (let ((command (eval compile-command)))
1379 (if (or compilation-read-command current-prefix-arg)
430aee8b 1380 (compilation-read-command command)
20320c65 1381 command))
c39bf546 1382 (consp current-prefix-arg)))
5b6858da
SM
1383 (unless (equal command (eval compile-command))
1384 (setq compile-command command))
9e86ab0b
SS
1385 (save-some-buffers (not compilation-ask-about-save)
1386 compilation-save-buffers-predicate)
091525d5 1387 (setq-default compilation-directory default-directory)
7837c247 1388 (compilation-start command comint))
55dfd2c4 1389
5b6858da 1390;; run compile with the default command line
430aee8b 1391(defun recompile (&optional edit-command)
6867356a 1392 "Re-compile the program including the current buffer.
6f5b7627 1393If this is run in a Compilation mode buffer, re-use the arguments from the
430aee8b
SS
1394original use. Otherwise, recompile using `compile-command'.
1395If the optional argument `edit-command' is non-nil, the command can be edited."
1396 (interactive "P")
9e86ab0b
SS
1397 (save-some-buffers (not compilation-ask-about-save)
1398 compilation-save-buffers-predicate)
091525d5 1399 (let ((default-directory (or compilation-directory default-directory)))
430aee8b
SS
1400 (when edit-command
1401 (setcar compilation-arguments
1402 (compilation-read-command (car compilation-arguments))))
7837c247
SM
1403 (apply 'compilation-start (or compilation-arguments
1404 `(,(eval compile-command))))))
09843b4a 1405
b5812513 1406(defcustom compilation-scroll-output nil
813fb3fe 1407 "Non-nil to scroll the *compilation* buffer window as output appears.
b5812513 1408
6f5b7627 1409Setting it causes the Compilation mode commands to put point at the
b5812513 1410end of their output window so that the end of the output is always
78dc87a2
JL
1411visible rather than the beginning.
1412
1413The value `first-error' stops scrolling at the first error, and leaves
1414point on its location in the *compilation* buffer."
1415 :type '(choice (const :tag "No scrolling" nil)
1416 (const :tag "Scroll compilation output" t)
1417 (const :tag "Stop scrolling at the first error" first-error))
a46fddeb 1418 :version "20.3"
b5812513
DL
1419 :group 'compilation)
1420
7bdb67b2 1421
e02f48d7 1422(defun compilation-buffer-name (name-of-mode mode-command name-function)
7bdb67b2 1423 "Return the name of a compilation buffer to use.
e02f48d7 1424If NAME-FUNCTION is non-nil, call it with one argument NAME-OF-MODE
7bdb67b2
GM
1425to determine the buffer name.
1426Likewise if `compilation-buffer-name-function' is non-nil.
7d1dad0c 1427If current buffer has the major mode MODE-COMMAND,
7bdb67b2 1428return the name of the current buffer, so that it gets reused.
e02f48d7 1429Otherwise, construct a buffer name from NAME-OF-MODE."
dc2feacf 1430 (cond (name-function
e02f48d7 1431 (funcall name-function name-of-mode))
dc2feacf 1432 (compilation-buffer-name-function
e02f48d7 1433 (funcall compilation-buffer-name-function name-of-mode))
be947101 1434 ((eq mode-command major-mode)
7bdb67b2
GM
1435 (buffer-name))
1436 (t
e02f48d7 1437 (concat "*" (downcase name-of-mode) "*"))))
7bdb67b2 1438
7837c247
SM
1439;; This is a rough emulation of the old hack, until the transition to new
1440;; compile is complete.
55dfd2c4 1441(defun compile-internal (command error-message
e02f48d7 1442 &optional _name-of-mode parser
a24770bc 1443 error-regexp-alist name-function
e02f48d7
JB
1444 _enter-regexp-alist _leave-regexp-alist
1445 file-regexp-alist _nomessage-regexp-alist
1446 _no-async highlight-regexp _local-map)
7837c247
SM
1447 (if parser
1448 (error "Compile now works very differently, see `compilation-error-regexp-alist'"))
1449 (let ((compilation-error-regexp-alist
1450 (append file-regexp-alist (or error-regexp-alist
1451 compilation-error-regexp-alist)))
1452 (compilation-error (replace-regexp-in-string "^No more \\(.+\\)s\\.?"
1453 "\\1" error-message)))
1454 (compilation-start command nil name-function highlight-regexp)))
ddb1f2e3 1455(make-obsolete 'compile-internal 'compilation-start "22.1")
7837c247 1456
a24c45d2 1457;;;###autoload
7837c247 1458(defun compilation-start (command &optional mode name-function highlight-regexp)
55dfd2c4 1459 "Run compilation command COMMAND (low level interface).
489a8034 1460If COMMAND starts with a cd command, that becomes the `default-directory'.
9ac57479
KS
1461The rest of the arguments are optional; for them, nil means use the default.
1462
7837c247 1463MODE is the major mode to set in the compilation buffer. Mode
6f5b7627 1464may also be t meaning use `compilation-shell-minor-mode' under `comint-mode'.
7d1dad0c 1465
5b317d74 1466If NAME-FUNCTION is non-nil, call it with one argument (the mode name)
7d1dad0c
RS
1467to determine the buffer name. Otherwise, the default is to
1468reuses the current buffer if it has the proper major mode,
1469else use or create a buffer with name based on the major mode.
23b0c5fc 1470
9ac57479 1471If HIGHLIGHT-REGEXP is non-nil, `next-error' will temporarily highlight
6f5b7627 1472the matching section of the visited source line; the default is to use the
9ac57479
KS
1473global value of `compilation-highlight-regexp'.
1474
646bd331 1475Returns the compilation buffer created."
7837c247 1476 (or mode (setq mode 'compilation-mode))
489a8034
DP
1477 (let* ((name-of-mode
1478 (if (eq mode t)
72fcf382 1479 "compilation"
331b2b90 1480 (replace-regexp-in-string "-mode\\'" "" (symbol-name mode))))
199143f1 1481 (thisdir default-directory)
489a8034 1482 outwin outbuf)
c536bb39
SM
1483 (with-current-buffer
1484 (setq outbuf
1485 (get-buffer-create
be947101 1486 (compilation-buffer-name name-of-mode mode name-function)))
d3cb357b
RM
1487 (let ((comp-proc (get-buffer-process (current-buffer))))
1488 (if comp-proc
1489 (if (or (not (eq (process-status comp-proc) 'run))
1490 (yes-or-no-p
bea1d57a
JB
1491 (format "A %s process is running; kill it? "
1492 name-of-mode)))
d3cb357b
RM
1493 (condition-case ()
1494 (progn
1495 (interrupt-process comp-proc)
1496 (sit-for 1)
1497 (delete-process comp-proc))
1498 (error nil))
1499 (error "Cannot have two processes in `%s' at once"
7837c247 1500 (buffer-name)))))
199143f1
DP
1501 ;; first transfer directory from where M-x compile was called
1502 (setq default-directory thisdir)
d42c87ab
RS
1503 ;; Make compilation buffer read-only. The filter can still write it.
1504 ;; Clear out the compilation buffer.
199143f1
DP
1505 (let ((inhibit-read-only t)
1506 (default-directory thisdir))
813fb3fe
SM
1507 ;; Then evaluate a cd command if any, but don't perform it yet, else
1508 ;; start-command would do it again through the shell: (cd "..") AND
1509 ;; sh -c "cd ..; make"
f6f8aa12
CY
1510 (cd (if (string-match "\\`\\s *cd\\(?:\\s +\\(\\S +?\\)\\)?\\s *[;&\n]"
1511 command)
199143f1 1512 (if (match-end 1)
12221c84 1513 (substitute-env-vars (match-string 1 command))
199143f1
DP
1514 "~")
1515 default-directory))
abed5267 1516 (erase-buffer)
6d2957c4
RS
1517 ;; Select the desired mode.
1518 (if (not (eq mode t))
ec4e0abc
SM
1519 (progn
1520 (buffer-disable-undo)
1521 (funcall mode))
6d2957c4
RS
1522 (setq buffer-read-only nil)
1523 (with-no-warnings (comint-mode))
1524 (compilation-shell-minor-mode))
5f3ca1ba
SS
1525 ;; Remember the original dir, so we can use it when we recompile.
1526 ;; default-directory' can't be used reliably for that because it may be
1527 ;; affected by the special handling of "cd ...;".
1528 ;; NB: must be fone after (funcall mode) as that resets local variables
1529 (set (make-local-variable 'compilation-directory) thisdir)
6d2957c4
RS
1530 (if highlight-regexp
1531 (set (make-local-variable 'compilation-highlight-regexp)
1532 highlight-regexp))
78dc87a2
JL
1533 (if (or compilation-auto-jump-to-first-error
1534 (eq compilation-scroll-output 'first-error))
813fb3fe 1535 (set (make-local-variable 'compilation-auto-jump-to-next) t))
6d2957c4 1536 ;; Output a mode setter, for saving and later reloading this buffer.
d42c87ab 1537 (insert "-*- mode: " name-of-mode
3b548e1b
SM
1538 "; default-directory: "
1539 (prin1-to-string (abbreviate-file-name default-directory))
a67e5425 1540 " -*-\n"
314b410b
JL
1541 (format "%s started at %s\n\n"
1542 mode-name
1543 (substring (current-time-string) 0 19))
a67e5425 1544 command "\n")
abed5267 1545 (setq thisdir default-directory))
7837c247 1546 (set-buffer-modified-p nil))
7837c247 1547 ;; Pop up the compilation buffer.
c34dc850
GM
1548 ;; http://lists.gnu.org/archive/html/emacs-devel/2007-11/msg01638.html
1549 (setq outwin (display-buffer outbuf))
7837c247 1550 (with-current-buffer outbuf
577bf5d2
JL
1551 (let ((process-environment
1552 (append
1553 compilation-environment
1554 (if (if (boundp 'system-uses-terminfo) ; `if' for compiler warning
1555 system-uses-terminfo)
1556 (list "TERM=dumb" "TERMCAP="
1557 (format "COLUMNS=%d" (window-width)))
1558 (list "TERM=emacs"
1559 (format "TERMCAP=emacs:co#%d:tc=unknown:"
1560 (window-width))))
1561 ;; Set the EMACS variable, but
1562 ;; don't override users' setting of $EMACS.
4b1aaa8b 1563 (unless (getenv "EMACS")
e725507a
CY
1564 (list "EMACS=t"))
1565 (list "INSIDE_EMACS=t")
a9e11582 1566 (copy-sequence process-environment))))
577bf5d2
JL
1567 (set (make-local-variable 'compilation-arguments)
1568 (list command mode name-function highlight-regexp))
1569 (set (make-local-variable 'revert-buffer-function)
1570 'compilation-revert-buffer)
1571 (set-window-start outwin (point-min))
2d0a22f8
RS
1572
1573 ;; Position point as the user will see it.
1574 (let ((desired-visible-point
1575 ;; Put it at the end if `compilation-scroll-output' is set.
1576 (if compilation-scroll-output
1577 (point-max)
1578 ;; Normally put it at the top.
1579 (point-min))))
1580 (if (eq outwin (selected-window))
1581 (goto-char desired-visible-point)
1582 (set-window-point outwin desired-visible-point)))
1583
577bf5d2
JL
1584 ;; The setup function is called before compilation-set-window-height
1585 ;; so it can set the compilation-window-height buffer locally.
1586 (if compilation-process-setup-function
1587 (funcall compilation-process-setup-function))
1588 (compilation-set-window-height outwin)
1589 ;; Start the compilation.
2a12d736
EZ
1590 (if (fboundp 'start-process)
1591 (let ((proc
1592 (if (eq mode t)
1593 ;; comint uses `start-file-process'.
1594 (get-buffer-process
1595 (with-no-warnings
1596 (comint-exec
1597 outbuf (downcase mode-name)
1598 (if (file-remote-p default-directory)
1599 "/bin/sh"
1600 shell-file-name)
1601 nil `("-c" ,command))))
1602 (start-file-process-shell-command (downcase mode-name)
1603 outbuf command))))
1604 ;; Make the buffer's mode line show process state.
1605 (setq mode-line-process
1606 (list (propertize ":%s" 'face 'compilation-warning)))
1607 (set-process-sentinel proc 'compilation-sentinel)
1608 (unless (eq mode t)
1609 ;; Keep the comint filter, since it's needed for proper handling
1610 ;; of the prompts.
1611 (set-process-filter proc 'compilation-filter))
1612 ;; Use (point-max) here so that output comes in
1613 ;; after the initial text,
1614 ;; regardless of where the user sees point.
1615 (set-marker (process-mark proc) (point-max) outbuf)
1616 (when compilation-disable-input
1617 (condition-case nil
1618 (process-send-eof proc)
1619 ;; The process may have exited already.
1620 (error nil)))
dd93e6da
SS
1621 (run-hook-with-args 'compilation-start-hook proc)
1622 (setq compilation-in-progress
2a12d736
EZ
1623 (cons proc compilation-in-progress)))
1624 ;; No asynchronous processes available.
1625 (message "Executing `%s'..." command)
1626 ;; Fake modeline display as if `start-process' were run.
ddb1f2e3 1627 (setq mode-line-process
2a12d736
EZ
1628 (list (propertize ":run" 'face 'compilation-warning)))
1629 (force-mode-line-update)
1630 (sit-for 0) ; Force redisplay
1631 (save-excursion
1632 ;; Insert the output at the end, after the initial text,
1633 ;; regardless of where the user sees point.
1634 (goto-char (point-max))
07b741a7 1635 (let* ((inhibit-read-only t) ; call-process needs to modify outbuf
9bedd73a 1636 (compilation-filter-start (point))
2a12d736
EZ
1637 (status (call-process shell-file-name nil outbuf nil "-c"
1638 command)))
9bedd73a 1639 (run-hooks 'compilation-filter-hook)
2a12d736
EZ
1640 (cond ((numberp status)
1641 (compilation-handle-exit
1642 'exit status
1643 (if (zerop status)
1644 "finished\n"
1645 (format "exited abnormally with code %d\n" status))))
1646 ((stringp status)
1647 (compilation-handle-exit 'signal status
1648 (concat status "\n")))
1649 (t
1650 (compilation-handle-exit 'bizarre status status)))))
2a12d736
EZ
1651 (set-buffer-modified-p nil)
1652 (message "Executing `%s'...done" command)))
199143f1 1653 ;; Now finally cd to where the shell started make/grep/...
e6f3e104
MR
1654 (setq default-directory thisdir)
1655 ;; The following form selected outwin ever since revision 1.183,
1656 ;; so possibly messing up point in some other window (bug#1073).
1657 ;; Moved into the scope of with-current-buffer, though still with
1658 ;; complete disregard for the case when compilation-scroll-output
1659 ;; equals 'first-error (martin 2008-10-04).
1660 (when compilation-scroll-output
1661 (goto-char (point-max))))
1662
043442b4 1663 ;; Make it so the next C-x ` will use this buffer.
5d9f0de2 1664 (setq next-error-last-buffer outbuf)))
55dfd2c4 1665
c94b02d6 1666(defun compilation-set-window-height (window)
851231e9 1667 "Set the height of WINDOW according to `compilation-window-height'."
9ac57479
KS
1668 (let ((height (buffer-local-value 'compilation-window-height (window-buffer window))))
1669 (and height
0dad3dfe 1670 (window-full-width-p window)
9ac57479
KS
1671 ;; If window is alone in its frame, aside from a minibuffer,
1672 ;; don't change its height.
1673 (not (eq window (frame-root-window (window-frame window))))
b3ef54c5
DP
1674 ;; Stef said that doing the saves in this order is safer:
1675 (save-excursion
9ac57479 1676 (save-selected-window
b3ef54c5
DP
1677 (select-window window)
1678 (enlarge-window (- height (window-height))))))))
c94b02d6 1679
4282eba1 1680(defvar compilation-menu-map
93260283
DN
1681 (let ((map (make-sparse-keymap "Errors"))
1682 (opt-map (make-sparse-keymap "Skip")))
4282eba1 1683 (define-key map [stop-subjob]
38805987
DN
1684 '(menu-item "Stop Compilation" kill-compilation
1685 :help "Kill the process made by the M-x compile or M-x grep commands"))
93260283
DN
1686 (define-key map [compilation-mode-separator3]
1687 '("----" . nil))
1688 (define-key map [compilation-next-error-follow-minor-mode]
1689 '(menu-item
1690 "Auto Error Display" next-error-follow-minor-mode
1691 :help "Display the error under cursor when moving the cursor"
1692 :button (:toggle . next-error-follow-minor-mode)))
1693 (define-key map [compilation-skip]
1694 (cons "Skip Less Important Messages" opt-map))
1695 (define-key opt-map [compilation-skip-none]
1696 '(menu-item "Don't Skip Any Messages"
1697 (lambda ()
1698 (interactive)
1699 (customize-set-variable 'compilation-skip-threshold 0))
1700 :help "Do not skip any type of messages"
1701 :button (:radio . (eq compilation-skip-threshold 0))))
1702 (define-key opt-map [compilation-skip-info]
1703 '(menu-item "Skip Info"
1704 (lambda ()
1705 (interactive)
1706 (customize-set-variable 'compilation-skip-threshold 1))
1707 :help "Skip anything less than warning"
1708 :button (:radio . (eq compilation-skip-threshold 1))))
1709 (define-key opt-map [compilation-skip-warning-and-info]
1710 '(menu-item "Skip Warnings and Info"
1711 (lambda ()
1712 (interactive)
1713 (customize-set-variable 'compilation-skip-threshold 2))
1714 :help "Skip over Warnings and Info, stop for errors"
1715 :button (:radio . (eq compilation-skip-threshold 2))))
4282eba1
SM
1716 (define-key map [compilation-mode-separator2]
1717 '("----" . nil))
9ac57479 1718 (define-key map [compilation-first-error]
38805987
DN
1719 '(menu-item "First Error" first-error
1720 :help "Restart at the first error, visit corresponding source code"))
9ac57479 1721 (define-key map [compilation-previous-error]
38805987
DN
1722 '(menu-item "Previous Error" previous-error
1723 :help "Visit previous `next-error' message and corresponding source code"))
9ac57479 1724 (define-key map [compilation-next-error]
38805987
DN
1725 '(menu-item "Next Error" next-error
1726 :help "Visit next `next-error' message and corresponding source code"))
4282eba1
SM
1727 map))
1728
0b18a8f6 1729(defvar compilation-minor-mode-map
55dfd2c4 1730 (let ((map (make-sparse-keymap)))
abef340a 1731 (set-keymap-parent map special-mode-map)
9da85ee5 1732 (define-key map [mouse-2] 'compile-goto-error)
0ac804df 1733 (define-key map [follow-link] 'mouse-face)
55dfd2c4 1734 (define-key map "\C-c\C-c" 'compile-goto-error)
4e7ce12e 1735 (define-key map "\C-m" 'compile-goto-error)
d3cb357b 1736 (define-key map "\C-c\C-k" 'kill-compilation)
646bd331
RM
1737 (define-key map "\M-n" 'compilation-next-error)
1738 (define-key map "\M-p" 'compilation-previous-error)
d1ed4475
RM
1739 (define-key map "\M-{" 'compilation-previous-file)
1740 (define-key map "\M-}" 'compilation-next-file)
86c7460f 1741 (define-key map "g" 'recompile) ; revert
4282eba1
SM
1742 ;; Set up the menu-bar
1743 (define-key map [menu-bar compilation]
1744 (cons "Errors" compilation-menu-map))
55dfd2c4 1745 map)
4f6e4ad6 1746 "Keymap for `compilation-minor-mode'.")
0b18a8f6 1747
a24770bc
RS
1748(defvar compilation-shell-minor-mode-map
1749 (let ((map (make-sparse-keymap)))
a24770bc
RS
1750 (define-key map "\M-\C-m" 'compile-goto-error)
1751 (define-key map "\M-\C-n" 'compilation-next-error)
1752 (define-key map "\M-\C-p" 'compilation-previous-error)
1753 (define-key map "\M-{" 'compilation-previous-file)
1754 (define-key map "\M-}" 'compilation-next-file)
1755 ;; Set up the menu-bar
4282eba1
SM
1756 (define-key map [menu-bar compilation]
1757 (cons "Errors" compilation-menu-map))
a24770bc
RS
1758 map)
1759 "Keymap for `compilation-shell-minor-mode'.")
1760
60470fd2
SM
1761(defvar compilation-button-map
1762 (let ((map (make-sparse-keymap)))
1763 (define-key map [mouse-2] 'compile-goto-error)
0ac804df 1764 (define-key map [follow-link] 'mouse-face)
60470fd2
SM
1765 (define-key map "\C-m" 'compile-goto-error)
1766 map)
1767 "Keymap for compilation-message buttons.")
1768(fset 'compilation-button-map compilation-button-map)
1769
0b18a8f6 1770(defvar compilation-mode-map
4282eba1 1771 (let ((map (make-sparse-keymap)))
261b01c6
RS
1772 ;; Don't inherit from compilation-minor-mode-map,
1773 ;; because that introduces a menu bar item we don't want.
1774 ;; That confuses C-down-mouse-3.
abef340a 1775 (set-keymap-parent map special-mode-map)
5988691b 1776 (define-key map [mouse-2] 'compile-goto-error)
0ac804df 1777 (define-key map [follow-link] 'mouse-face)
5988691b
RS
1778 (define-key map "\C-c\C-c" 'compile-goto-error)
1779 (define-key map "\C-m" 'compile-goto-error)
1780 (define-key map "\C-c\C-k" 'kill-compilation)
1781 (define-key map "\M-n" 'compilation-next-error)
1782 (define-key map "\M-p" 'compilation-previous-error)
1783 (define-key map "\M-{" 'compilation-previous-file)
1784 (define-key map "\M-}" 'compilation-next-file)
70fec115
JL
1785 (define-key map "\t" 'compilation-next-error)
1786 (define-key map [backtab] 'compilation-previous-error)
86c7460f 1787 (define-key map "g" 'recompile) ; revert
5988691b 1788
221206e3 1789 (define-key map "\C-c\C-f" 'next-error-follow-minor-mode)
9ac57479 1790
e60476ca 1791 ;; Set up the menu-bar
5988691b
RS
1792 (let ((submap (make-sparse-keymap "Compile")))
1793 (define-key map [menu-bar compilation]
1794 (cons "Compile" submap))
1795 (set-keymap-parent submap compilation-menu-map))
4282eba1 1796 (define-key map [menu-bar compilation compilation-separator2]
e60476ca 1797 '("----" . nil))
9ac57479 1798 (define-key map [menu-bar compilation compilation-grep]
38805987
DN
1799 '(menu-item "Search Files (grep)..." grep
1800 :help "Run grep, with user-specified args, and collect output in a buffer"))
9ac57479 1801 (define-key map [menu-bar compilation compilation-recompile]
38805987
DN
1802 '(menu-item "Recompile" recompile
1803 :help "Re-compile the program including the current buffer"))
9ac57479 1804 (define-key map [menu-bar compilation compilation-compile]
38805987
DN
1805 '(menu-item "Compile..." compile
1806 :help "Compile the program including the current buffer. Default: run `make'"))
0b18a8f6
RM
1807 map)
1808 "Keymap for compilation log buffers.
4282eba1 1809`compilation-minor-mode-map' is a parent of this.")
55dfd2c4 1810
c45e48d2 1811(defvar compilation-mode-tool-bar-map
b4bd2cbe
CY
1812 ;; When bootstrapping, tool-bar-map is not properly initialized yet,
1813 ;; so don't do anything.
900503ae
CY
1814 (when (keymapp tool-bar-map)
1815 (let ((map (copy-keymap tool-bar-map)))
1816 (define-key map [undo] nil)
1817 (define-key map [separator-2] nil)
1818 (define-key-after map [separator-compile] menu-bar-separator)
b4bd2cbe
CY
1819 (tool-bar-local-item
1820 "left-arrow" 'previous-error-no-select 'previous-error-no-select map
1821 :rtl "right-arrow"
1822 :help "Goto previous error")
1823 (tool-bar-local-item
1824 "right-arrow" 'next-error-no-select 'next-error-no-select map
1825 :rtl "left-arrow"
1826 :help "Goto next error")
1827 (tool-bar-local-item
1828 "cancel" 'kill-compilation 'kill-compilation map
1829 :enable '(let ((buffer (compilation-find-buffer)))
1830 (get-buffer-process buffer))
1831 :help "Stop compilation")
1832 (tool-bar-local-item
1833 "refresh" 'recompile 'recompile map
1834 :help "Restart compilation")
900503ae 1835 map)))
c45e48d2 1836
0a35bd79
RS
1837(put 'compilation-mode 'mode-class 'special)
1838
501cf428 1839;;;###autoload
d42c87ab 1840(defun compilation-mode (&optional name-of-mode)
55dfd2c4
RS
1841 "Major mode for compilation log buffers.
1842\\<compilation-mode-map>To visit the source for a line-numbered error,
d3cb357b 1843move point to the error message line and type \\[compile-goto-error].
7c163413
RM
1844To kill the compilation, type \\[kill-compilation].
1845
2894bd96 1846Runs `compilation-mode-hook' with `run-mode-hooks' (which see).
8ff2ed52
RS
1847
1848\\{compilation-mode-map}"
55dfd2c4 1849 (interactive)
9af0d309 1850 (kill-all-local-variables)
55dfd2c4 1851 (use-local-map compilation-mode-map)
a1562258
SM
1852 ;; Let windows scroll along with the output.
1853 (set (make-local-variable 'window-point-insertion-type) t)
c45e48d2 1854 (set (make-local-variable 'tool-bar-map) compilation-mode-tool-bar-map)
175069ef 1855 (setq major-mode 'compilation-mode ; FIXME: Use define-derived-mode.
d42c87ab 1856 mode-name (or name-of-mode "Compilation"))
7837c247
SM
1857 (set (make-local-variable 'page-delimiter)
1858 compilation-page-delimiter)
8fe52384 1859 ;; (set (make-local-variable 'compilation-buffer-modtime) nil)
0b18a8f6 1860 (compilation-setup)
bd8c6db5 1861 (setq buffer-read-only t)
7837c247
SM
1862 (run-mode-hooks 'compilation-mode-hook))
1863
1864(defmacro define-compilation-mode (mode name doc &rest body)
1865 "This is like `define-derived-mode' without the PARENT argument.
1866The parent is always `compilation-mode' and the customizable `compilation-...'
bac3a1c9
JL
1867variables are also set from the name of the mode you have chosen,
1868by replacing the first word, e.g `compilation-scroll-output' from
1869`grep-scroll-output' if that variable exists."
7837c247
SM
1870 (let ((mode-name (replace-regexp-in-string "-mode\\'" "" (symbol-name mode))))
1871 `(define-derived-mode ,mode compilation-mode ,name
1872 ,doc
1873 ,@(mapcar (lambda (v)
1874 (setq v (cons v
1875 (intern-soft (replace-regexp-in-string
1876 "^compilation" mode-name
1877 (symbol-name v)))))
1878 (and (cdr v)
1879 (or (boundp (cdr v))
07b741a7 1880 ;; FIXME: This is hackish, using undocumented info.
7837c247
SM
1881 (if (boundp 'byte-compile-bound-variables)
1882 (memq (cdr v) byte-compile-bound-variables)))
1883 `(set (make-local-variable ',(car v)) ,(cdr v))))
1884 '(compilation-buffer-name-function
1885 compilation-directory-matcher
1886 compilation-error
1887 compilation-error-regexp-alist
1888 compilation-error-regexp-alist-alist
1889 compilation-error-screen-columns
1890 compilation-finish-function
1891 compilation-finish-functions
1892 compilation-first-column
1893 compilation-mode-font-lock-keywords
1894 compilation-page-delimiter
1895 compilation-parse-errors-filename-function
1896 compilation-process-setup-function
1897 compilation-scroll-output
1898 compilation-search-path
1899 compilation-skip-threshold
1900 compilation-window-height))
1901 ,@body)))
0b18a8f6 1902
58856335 1903(defun compilation-revert-buffer (ignore-auto noconfirm)
9ed2ab9f
RS
1904 (if buffer-file-name
1905 (let (revert-buffer-function)
9ac57479 1906 (revert-buffer ignore-auto noconfirm))
9ed2ab9f 1907 (if (or noconfirm (yes-or-no-p (format "Restart compilation? ")))
7837c247
SM
1908 (apply 'compilation-start compilation-arguments))))
1909
c536bb39
SM
1910(defvar compilation-current-error nil
1911 "Marker to the location from where the next error will be found.
1912The global commands next/previous/first-error/goto-error use this.")
51c8ad03 1913
9b7b51a2
SM
1914(defvar compilation-messages-start nil
1915 "Buffer position of the beginning of the compilation messages.
1916If nil, use the beginning of buffer.")
1917
7837c247 1918(defun compilation-setup (&optional minor)
6f5b7627
SM
1919 "Prepare the buffer for the compilation parsing commands to work.
1920Optional argument MINOR indicates this is called from
1921`compilation-minor-mode'."
51c8ad03 1922 (make-local-variable 'compilation-current-error)
9b7b51a2 1923 (make-local-variable 'compilation-messages-start)
18aac618 1924 (make-local-variable 'compilation-error-screen-columns)
b3a7f48f 1925 (make-local-variable 'overlay-arrow-position)
8b71e4d1 1926 (set (make-local-variable 'overlay-arrow-string) "")
6a1cdc5b
JL
1927 (setq next-error-overlay-arrow-position nil)
1928 (add-hook 'kill-buffer-hook
1929 (lambda () (setq next-error-overlay-arrow-position nil)) nil t)
9b7b51a2
SM
1930 ;; Note that compilation-next-error-function is for interfacing
1931 ;; with the next-error function in simple.el, and it's only
1932 ;; coincidentally named similarly to compilation-next-error.
1933 (setq next-error-function 'compilation-next-error-function)
00d6fd04
MA
1934 (set (make-local-variable 'comint-file-name-prefix)
1935 (or (file-remote-p default-directory) ""))
7837c247
SM
1936 (set (make-local-variable 'compilation-locs)
1937 (make-hash-table :test 'equal :weakness 'value))
55fb9013
SM
1938 ;; It's generally preferable to use after-change-functions since they
1939 ;; can be subject to combine-after-change-calls, but if we do that, we risk
1940 ;; running our hook after font-lock, resulting in incorrect refontification.
1941 (add-hook 'before-change-functions 'compilation--flush-parse nil t)
1942 ;; Also for minor mode, since it's not permanent-local.
1943 (add-hook 'change-major-mode-hook #'compilation--remove-properties nil t)
963b2040 1944 (if minor
55fb9013 1945 (progn
f6164cdd 1946 (font-lock-add-keywords nil (compilation-mode-font-lock-keywords))
f6164cdd 1947 (if font-lock-mode
55fb9013
SM
1948 (font-lock-fontify-buffer)))
1949 (setq font-lock-defaults '(compilation-mode-font-lock-keywords t))))
0b18a8f6 1950
07b741a7
SM
1951(defun compilation--unsetup ()
1952 ;; Only for minor mode.
1953 (font-lock-remove-keywords nil (compilation-mode-font-lock-keywords))
55fb9013
SM
1954 (remove-hook 'before-change-functions 'compilation--flush-parse t)
1955 (kill-local-variable 'compilation--parsed)
1956 (compilation--remove-properties)
07b741a7
SM
1957 (if font-lock-mode
1958 (font-lock-fontify-buffer)))
1959
7052680b 1960;;;###autoload
4282eba1 1961(define-minor-mode compilation-shell-minor-mode
7052680b
RS
1962 "Toggle compilation shell minor mode.
1963With arg, turn compilation mode on if and only if arg is positive.
4282eba1
SM
1964In this minor mode, all the error-parsing commands of the
1965Compilation major mode are available but bound to keys that don't
1966collide with Shell mode. See `compilation-mode'.
7052680b 1967Turning the mode on runs the normal hook `compilation-shell-minor-mode-hook'."
7837c247 1968 nil " Shell-Compile"
d408fed8 1969 :group 'compilation
7837c247
SM
1970 (if compilation-shell-minor-mode
1971 (compilation-setup t)
07b741a7 1972 (compilation--unsetup)))
7052680b 1973
d6bd8dca 1974;;;###autoload
4282eba1 1975(define-minor-mode compilation-minor-mode
0b18a8f6
RM
1976 "Toggle compilation minor mode.
1977With arg, turn compilation mode on if and only if arg is positive.
4282eba1
SM
1978In this minor mode, all the error-parsing commands of the
1979Compilation major mode are available. See `compilation-mode'.
fee3f63a 1980Turning the mode on runs the normal hook `compilation-minor-mode-hook'."
7837c247 1981 nil " Compilation"
d408fed8 1982 :group 'compilation
7837c247
SM
1983 (if compilation-minor-mode
1984 (compilation-setup t)
07b741a7 1985 (compilation--unsetup)))
55dfd2c4 1986
fd5e58d7 1987(defun compilation-handle-exit (process-status exit-status msg)
f441be5b 1988 "Write MSG in the current buffer and hack its `mode-line-process'."
d42c87ab 1989 (let ((inhibit-read-only t)
fd5e58d7
RM
1990 (status (if compilation-exit-message-function
1991 (funcall compilation-exit-message-function
1992 process-status exit-status msg)
1993 (cons msg exit-status)))
1994 (omax (point-max))
c96e025a
GM
1995 (opoint (point))
1996 (cur-buffer (current-buffer)))
b3a7f48f 1997 ;; Record where we put the message, so we can ignore it later on.
fd5e58d7
RM
1998 (goto-char omax)
1999 (insert ?\n mode-name " " (car status))
0eac1faa 2000 (if (and (numberp compilation-window-height)
7837c247
SM
2001 (zerop compilation-window-height))
2002 (message "%s" (cdr status)))
01c50447
RS
2003 (if (bolp)
2004 (forward-char -1))
fd5e58d7 2005 (insert " at " (substring (current-time-string) 0 19))
01c50447 2006 (goto-char (point-max))
47092737
RS
2007 ;; Prevent that message from being recognized as a compilation error.
2008 (add-text-properties omax (point)
2009 (append '(compilation-handle-exit t) nil))
a8bdd228
DN
2010 (setq mode-line-process
2011 (let ((out-string (format ":%s [%s]" process-status (cdr status)))
a46b95a8 2012 (msg (format "%s %s" mode-name
07b741a7
SM
2013 (replace-regexp-in-string "\n?$" ""
2014 (car status)))))
a46b95a8
JL
2015 (message "%s" msg)
2016 (propertize out-string
2017 'help-echo msg 'face (if (> exit-status 0)
2018 'compilation-error
2019 'compilation-info))))
fd5e58d7
RM
2020 ;; Force mode line redisplay soon.
2021 (force-mode-line-update)
2022 (if (and opoint (< opoint omax))
2023 (goto-char opoint))
a5f1c37e
RS
2024 (with-no-warnings
2025 (if compilation-finish-function
c96e025a
GM
2026 (funcall compilation-finish-function cur-buffer msg)))
2027 (run-hook-with-args 'compilation-finish-functions cur-buffer msg)))
fd5e58d7 2028
55dfd2c4 2029;; Called when compilation process changes state.
55dfd2c4 2030(defun compilation-sentinel (proc msg)
d3cb357b 2031 "Sentinel for compilation buffers."
b3a7f48f
DP
2032 (if (memq (process-status proc) '(exit signal))
2033 (let ((buffer (process-buffer proc)))
2034 (if (null (buffer-name buffer))
2035 ;; buffer killed
2036 (set-process-buffer proc nil)
2037 (with-current-buffer buffer
2038 ;; Write something in the compilation buffer
2039 ;; and hack its mode line.
2040 (compilation-handle-exit (process-status proc)
2041 (process-exit-status proc)
2042 msg)
2043 ;; Since the buffer and mode line will show that the
2044 ;; process is dead, we can delete it now. Otherwise it
2045 ;; will stay around until M-x list-processes.
2046 (delete-process proc)))
2047 (setq compilation-in-progress (delq proc compilation-in-progress)))))
55dfd2c4 2048
ad62b7f1
RM
2049(defun compilation-filter (proc string)
2050 "Process filter for compilation buffers.
20179516
SS
2051Just inserts the text,
2052handles carriage motion (see `comint-inhibit-carriage-motion'),
2053and runs `compilation-filter-hook'."
ec4e0abc
SM
2054 (when (buffer-live-p (process-buffer proc))
2055 (with-current-buffer (process-buffer proc)
2056 (let ((inhibit-read-only t)
2057 ;; `save-excursion' doesn't use the right insertion-type for us.
0b508a27 2058 (pos (copy-marker (point) t))
07b741a7
SM
2059 ;; `save-restriction' doesn't use the right insertion type either:
2060 ;; If we are inserting at the end of the accessible part of the
2061 ;; buffer, keep the inserted text visible.
0b508a27 2062 (min (point-min-marker))
d9c54a06
CY
2063 (max (copy-marker (point-max) t))
2064 (compilation-filter-start (marker-position (process-mark proc))))
ec4e0abc
SM
2065 (unwind-protect
2066 (progn
0b508a27 2067 (widen)
d9c54a06 2068 (goto-char compilation-filter-start)
ec4e0abc
SM
2069 ;; We used to use `insert-before-markers', so that windows with
2070 ;; point at `process-mark' scroll along with the output, but we
2071 ;; now use window-point-insertion-type instead.
2072 (insert string)
20179516
SS
2073 (unless comint-inhibit-carriage-motion
2074 (comint-carriage-motion (process-mark proc) (point)))
ec4e0abc 2075 (set-marker (process-mark proc) (point))
8fe52384
SM
2076 ;; (set (make-local-variable 'compilation-buffer-modtime)
2077 ;; (current-time))
ec4e0abc 2078 (run-hooks 'compilation-filter-hook))
0b508a27
RS
2079 (goto-char pos)
2080 (narrow-to-region min max)
07b741a7 2081 (set-marker pos nil)
0b508a27
RS
2082 (set-marker min nil)
2083 (set-marker max nil))))))
b5bb472e 2084
5d9f0de2
KS
2085;;; test if a buffer is a compilation buffer, assuming we're in the buffer
2086(defsubst compilation-buffer-internal-p ()
2087 "Test if inside a compilation buffer."
2088 (local-variable-p 'compilation-locs))
2089
2090;;; test if a buffer is a compilation buffer, using compilation-buffer-internal-p
51ba27e7 2091(defsubst compilation-buffer-p (buffer)
5d9f0de2
KS
2092 "Test if BUFFER is a compilation buffer."
2093 (with-current-buffer buffer
2094 (compilation-buffer-internal-p)))
7837c247 2095
060d5dc1
CY
2096(defmacro compilation-loop (< property-change 1+ error limit)
2097 `(let (opt)
2098 (while (,< n 0)
2099 (setq opt pt)
07b741a7 2100 (or (setq pt (,property-change pt 'compilation-message))
060d5dc1
CY
2101 ;; Handle the case where where the first error message is
2102 ;; at the start of the buffer, and n < 0.
07b741a7
SM
2103 (if (or (eq (get-text-property ,limit 'compilation-message)
2104 (get-text-property opt 'compilation-message))
060d5dc1
CY
2105 (eq pt opt))
2106 (error ,error compilation-error)
2107 (setq pt ,limit)))
07b741a7 2108 ;; prop 'compilation-message usually has 2 changes, on and off, so
060d5dc1 2109 ;; re-search if off
07b741a7
SM
2110 (or (setq msg (get-text-property pt 'compilation-message))
2111 (if (setq pt (,property-change pt 'compilation-message nil ,limit))
2112 (setq msg (get-text-property pt 'compilation-message)))
060d5dc1 2113 (error ,error compilation-error))
8fe52384 2114 (or (< (compilation--message->type msg) compilation-skip-threshold)
060d5dc1 2115 (if different-file
8fe52384
SM
2116 (eq (prog1 last
2117 (setq last (compilation--loc->file-struct
2118 (compilation--message->loc msg))))
060d5dc1
CY
2119 last))
2120 (if compilation-skip-visited
8fe52384 2121 (compilation--loc->visited (compilation--message->loc msg)))
060d5dc1 2122 (if compilation-skip-to-next-location
8fe52384 2123 (eq (compilation--message->loc msg) loc))
060d5dc1
CY
2124 ;; count this message only if none of the above are true
2125 (setq n (,1+ n))))))
7837c247 2126
55fb9013
SM
2127(defun compilation-next-single-property-change (position prop
2128 &optional object limit)
2129 (let (parsed res)
2130 (while (progn
2131 ;; We parse the buffer here "on-demand" by chunks of 500 chars.
2132 ;; But we could also just parse the whole buffer.
2133 (compilation--ensure-parse
2134 (setq parsed (max compilation--parsed
2135 (min (+ position 500)
2136 (or limit (point-max))))))
2137 (and (or (not (setq res (next-single-property-change
2138 position prop object limit)))
2139 (eq res limit))
2140 (< position (or limit (point-max)))))
2141 (setq position parsed))
2142 res))
2143
51c8ad03 2144(defun compilation-next-error (n &optional different-file pt)
646bd331 2145 "Move point to the next error in the compilation buffer.
d0048c60 2146This function does NOT find the source line like \\[next-error].
851231e9
DL
2147Prefix arg N says how many error messages to move forwards (or
2148backwards, if negative).
d0048c60
EZ
2149Optional arg DIFFERENT-FILE, if non-nil, means find next error for a
2150file that is different from the current one.
2151Optional arg PT, if non-nil, specifies the value of point to start
2152looking for the next message."
646bd331
RM
2153 (interactive "p")
2154 (or (compilation-buffer-p (current-buffer))
851231e9 2155 (error "Not in a compilation buffer"))
51c8ad03 2156 (or pt (setq pt (point)))
07b741a7 2157 (let* ((msg (get-text-property pt 'compilation-message))
8fe52384 2158 ;; `loc', `msg', and `last' are used by the compilation-loop macro.
7d116647 2159 (loc (and msg (compilation--message->loc msg)))
51c8ad03 2160 last)
7837c247
SM
2161 (if (zerop n)
2162 (unless (or msg ; find message near here
c536bb39 2163 (setq msg (get-text-property (max (1- pt) (point-min))
07b741a7
SM
2164 'compilation-message)))
2165 (setq pt (previous-single-property-change pt 'compilation-message nil
c536bb39 2166 (line-beginning-position)))
07b741a7
SM
2167 (unless (setq msg (get-text-property (max (1- pt) (point-min))
2168 'compilation-message))
2169 (setq pt (next-single-property-change pt 'compilation-message nil
c536bb39 2170 (line-end-position)))
07b741a7 2171 (or (setq msg (get-text-property pt 'compilation-message))
b3a7f48f 2172 (setq pt (point)))))
7d116647 2173 (setq last (compilation--loc->file-struct loc))
51c8ad03 2174 (if (>= n 0)
55fb9013 2175 (compilation-loop > compilation-next-single-property-change 1-
51c8ad03
DP
2176 (if (get-buffer-process (current-buffer))
2177 "No more %ss yet"
060d5dc1
CY
2178 "Moved past last %s")
2179 (point-max))
55fb9013 2180 (compilation--ensure-parse pt)
c536bb39
SM
2181 ;; Don't move "back" to message at or before point.
2182 ;; Pass an explicit (point-min) to make sure pt is non-nil.
07b741a7
SM
2183 (setq pt (previous-single-property-change
2184 pt 'compilation-message nil (point-min)))
51c8ad03 2185 (compilation-loop < previous-single-property-change 1+
060d5dc1 2186 "Moved back before first %s" (point-min))))
7837c247
SM
2187 (goto-char pt)
2188 (or msg
2189 (error "No %s here" compilation-error))))
646bd331
RM
2190
2191(defun compilation-previous-error (n)
2192 "Move point to the previous error in the compilation buffer.
851231e9
DL
2193Prefix arg N says how many error messages to move backwards (or
2194forwards, if negative).
7837c247 2195Does NOT find the source line like \\[previous-error]."
646bd331
RM
2196 (interactive "p")
2197 (compilation-next-error (- n)))
2198
b5bb472e 2199(defun compilation-next-file (n)
24299582
DP
2200 "Move point to the next error for a different file than the current one.
2201Prefix arg N says how many files to move forwards (or backwards, if negative)."
b5bb472e 2202 (interactive "p")
7837c247 2203 (compilation-next-error n t))
b5bb472e
RM
2204
2205(defun compilation-previous-file (n)
24299582
DP
2206 "Move point to the previous error for a different file than the current one.
2207Prefix arg N says how many files to move backwards (or forwards, if negative)."
b5bb472e
RM
2208 (interactive "p")
2209 (compilation-next-file (- n)))
2210
55dfd2c4 2211(defun kill-compilation ()
b765ba64 2212 "Kill the process made by the \\[compile] or \\[grep] commands."
55dfd2c4 2213 (interactive)
d3cb357b 2214 (let ((buffer (compilation-find-buffer)))
55dfd2c4 2215 (if (get-buffer-process buffer)
d3cb357b 2216 (interrupt-process (get-buffer-process buffer))
bac3a1c9 2217 (error "The %s process is not running" (downcase mode-name)))))
d3cb357b 2218
9da85ee5 2219(defalias 'compile-mouse-goto-error 'compile-goto-error)
c536bb39 2220
9da85ee5
SM
2221(defun compile-goto-error (&optional event)
2222 "Visit the source for the error message at point.
7837c247 2223Use this command in a compilation log buffer. Sets the mark at point there."
9da85ee5 2224 (interactive (list last-input-event))
a6cd3f65 2225 (if event (posn-set-point (event-end event)))
d3cb357b 2226 (or (compilation-buffer-p (current-buffer))
851231e9 2227 (error "Not in a compilation buffer"))
55fb9013 2228 (compilation--ensure-parse (point))
07b741a7
SM
2229 (if (get-text-property (point) 'compilation-directory)
2230 (dired-other-window
2231 (car (get-text-property (point) 'compilation-directory)))
b3a7f48f
DP
2232 (push-mark)
2233 (setq compilation-current-error (point))
942c40e3 2234 (next-error-internal)))
55dfd2c4 2235
07b741a7
SM
2236;; This is mostly unused, but we keep it for the sake of some external
2237;; packages which seem to make use of it.
749354f0 2238(defun compilation-find-buffer (&optional avoid-current)
7d1dad0c 2239 "Return a compilation buffer.
0dad3dfe
MR
2240If AVOID-CURRENT is nil, and the current buffer is a compilation buffer,
2241return it. If AVOID-CURRENT is non-nil, return the current buffer only
2242as a last resort."
2243 (if (and (compilation-buffer-internal-p) (not avoid-current))
7d1dad0c
RS
2244 (current-buffer)
2245 (next-error-find-buffer avoid-current 'compilation-buffer-internal-p)))
d3cb357b
RM
2246
2247;;;###autoload
5d9f0de2 2248(defun compilation-next-error-function (n &optional reset)
a5f1c37e
RS
2249 "Advance to the next error message and visit the file where the error was.
2250This is the value of `next-error-function' in Compilation buffers."
7837c247 2251 (interactive "p")
5d9f0de2
KS
2252 (when reset
2253 (setq compilation-current-error nil))
7837c247 2254 (let* ((columns compilation-error-screen-columns) ; buffer's local value
e02f48d7 2255 (last 1)
07b741a7 2256 (msg (compilation-next-error (or n 1) nil
9b7b51a2
SM
2257 (or compilation-current-error
2258 compilation-messages-start
2259 (point-min))))
8fe52384
SM
2260 (loc (compilation--message->loc msg))
2261 (end-loc (compilation--message->end-loc msg))
7837c247 2262 (marker (point-marker)))
51c8ad03 2263 (setq compilation-current-error (point-marker)
b3a7f48f
DP
2264 overlay-arrow-position
2265 (if (bolp)
2266 compilation-current-error
07b741a7 2267 (copy-marker (line-beginning-position))))
b84acff6
SS
2268 ;; If loc contains no marker, no error in that file has been visited.
2269 ;; If the marker is invalid the buffer has been killed.
b84acff6 2270 ;; So, recalculate all markers for that file.
8fe52384
SM
2271 (unless (and (compilation--loc->marker loc)
2272 (marker-buffer (compilation--loc->marker loc))
2273 ;; FIXME-omake: For "omake -P", which automatically recompiles
2274 ;; when the file is modified, the line numbers of new output
2275 ;; may not be related to line numbers from earlier output
2276 ;; (earlier markers), so we used to try to detect it here and
2277 ;; force a reparse. But that caused more problems elsewhere,
2278 ;; so instead we now flush the file-structure when we see
2279 ;; omake's message telling it's about to recompile a file.
2280 ;; (or (null (compilation--loc->timestamp loc)) ;A fake-loc
2281 ;; (equal (compilation--loc->timestamp loc)
2282 ;; (setq timestamp compilation-buffer-modtime)))
2283 )
2284 (with-current-buffer
2285 (compilation-find-file
2286 marker
2287 (caar (compilation--loc->file-struct loc))
2288 (cadr (car (compilation--loc->file-struct loc))))
7837c247
SM
2289 (save-restriction
2290 (widen)
c536bb39 2291 (goto-char (point-min))
7837c247 2292 ;; Treat file's found lines in forward order, 1 by 1.
8fe52384 2293 (dolist (line (reverse (cddr (compilation--loc->file-struct loc))))
7837c247
SM
2294 (when (car line) ; else this is a filename w/o a line#
2295 (beginning-of-line (- (car line) last -1))
2296 (setq last (car line)))
2297 ;; Treat line's found columns and store/update a marker for each.
2298 (dolist (col (cdr line))
8fe52384
SM
2299 (if (compilation--loc->col col)
2300 (if (eq (compilation--loc->col col) -1)
2301 ;; Special case for range end.
7837c247 2302 (end-of-line)
8fe52384
SM
2303 (compilation-move-to-column (compilation--loc->col col)
2304 columns))
7837c247
SM
2305 (beginning-of-line)
2306 (skip-chars-forward " \t"))
8fe52384
SM
2307 (if (compilation--loc->marker col)
2308 (set-marker (compilation--loc->marker col) (point))
2309 (setf (compilation--loc->marker col) (point-marker)))
2310 ;; (setf (compilation--loc->timestamp col) timestamp)
2311 )))))
2312 (compilation-goto-locus marker (compilation--loc->marker loc)
2313 (compilation--loc->marker end-loc))
2314 (setf (compilation--loc->visited loc) t)))
7837c247 2315
e3bef839
SM
2316(defvar compilation-gcpro nil
2317 "Internal variable used to keep some values from being GC'd.")
2318(make-variable-buffer-local 'compilation-gcpro)
2319
eb6fb6e2
DP
2320(defun compilation-fake-loc (marker file &optional line col)
2321 "Preassociate MARKER with FILE.
dbd97672 2322FILE should be ABSOLUTE-FILENAME or (RELATIVE-FILENAME . DIRNAME).
eb6fb6e2
DP
2323This is useful when you compile temporary files, but want
2324automatic translation of the messages to the real buffer from
07b741a7
SM
2325which the temporary file came. This may also affect previous messages
2326about FILE.
eb6fb6e2
DP
2327
2328Optional args LINE and COL default to 1 and beginning of
2329indentation respectively. The marker is expected to reflect
2330this. In the simplest case the marker points to the first line
2331of the region that was saved to the temp file.
2332
2333If you concatenate several regions into the temp file (e.g. a
2334header with variable assignments and a code region), you must
2335call this several times, once each for the last line of one
2336region and the first line of the next region."
2337 (or (consp file) (setq file (list file)))
07b741a7
SM
2338 (compilation--flush-file-structure file)
2339 (let ((fs (compilation-get-file-structure file)))
2340 ;; Between the current call to compilation-fake-loc and the first
2341 ;; occurrence of an error message referring to `file', the data is
2342 ;; only kept in the weak hash-table compilation-locs, so we need
2343 ;; to prevent this entry in compilation-locs from being GC'd
2344 ;; away. --Stef
2345 (push fs compilation-gcpro)
2346 (let ((loc (compilation-assq (or line 1) (cdr fs))))
2347 (setq loc (compilation-assq col loc))
8fe52384
SM
2348 (assert (null (cdr loc)))
2349 (setcdr loc (compilation--make-cdrloc line fs marker))
07b741a7 2350 loc)))
eb6fb6e2 2351
8b71e4d1
NR
2352(defcustom compilation-context-lines nil
2353 "Display this many lines of leading context before the current message.
2354If nil and the left fringe is displayed, don't scroll the
2355compilation output window; an arrow in the left fringe points to
2356the current message. If nil and there is no left fringe, the message
2357displays at the top of the window; there is no arrow."
a3a9c080 2358 :type '(choice integer (const :tag "No window scrolling" nil))
f6164cdd 2359 :group 'compilation
bf247b6e 2360 :version "22.1")
7837c247
SM
2361
2362(defsubst compilation-set-window (w mk)
6f5b7627 2363 "Align the compilation output window W with marker MK near top."
a3a9c080
JL
2364 (if (integerp compilation-context-lines)
2365 (set-window-start w (save-excursion
8b71e4d1
NR
2366 (goto-char mk)
2367 (beginning-of-line
2368 (- 1 compilation-context-lines))
2369 (point)))
3c9e7f42
RS
2370 ;; If there is no left fringe.
2371 (if (equal (car (window-fringes)) 0)
8b71e4d1
NR
2372 (set-window-start w (save-excursion
2373 (goto-char mk)
2374 (beginning-of-line 1)
2375 (point)))))
2376 (set-window-point w mk))
7837c247 2377
0ea50e43
RS
2378(defvar next-error-highlight-timer)
2379
7837c247 2380(defun compilation-goto-locus (msg mk end-mk)
6f5b7627 2381 "Jump to an error corresponding to MSG at MK.
9dc3a46a
JL
2382All arguments are markers. If END-MK is non-nil, mark is set there
2383and overlay is highlighted between MK and END-MK."
eaa3cac5 2384 ;; Show compilation buffer in other window, scrolled to this error.
e5456e73
SM
2385 (let* ((from-compilation-buffer (eq (window-buffer (selected-window))
2386 (marker-buffer msg)))
2387 ;; Use an existing window if it is in a visible frame.
7bbbd31f 2388 (pre-existing (get-buffer-window (marker-buffer msg) 0))
e5456e73
SM
2389 (w (if (and from-compilation-buffer pre-existing)
2390 ;; Calling display-buffer here may end up (partly) hiding
2391 ;; the error location if the two buffers are in two
2392 ;; different frames. So don't do it if it's not necessary.
2393 pre-existing
2394 (let ((display-buffer-reuse-frames t)
2395 (pop-up-windows t))
dce34635 2396 ;; Pop up a window.
e5456e73 2397 (display-buffer (marker-buffer msg)))))
7837c247
SM
2398 (highlight-regexp (with-current-buffer (marker-buffer msg)
2399 ;; also do this while we change buffer
2400 (compilation-set-window w msg)
9ac57479 2401 compilation-highlight-regexp)))
7bbbd31f
SM
2402 ;; Ideally, the window-size should be passed to `display-buffer' (via
2403 ;; something like special-display-buffer) so it's only used when
2404 ;; creating a new window.
2405 (unless pre-existing (compilation-set-window-height w))
9ac57479 2406
e5456e73
SM
2407 (if from-compilation-buffer
2408 ;; If the compilation buffer window was selected,
2409 ;; keep the compilation buffer in this window;
2410 ;; display the source in another window.
2411 (let ((pop-up-windows t))
2412 (pop-to-buffer (marker-buffer mk) 'other-window))
2dcdbdd9 2413 (pop-to-buffer-same-window (marker-buffer mk)))
e5456e73 2414 (unless (eq (goto-char mk) (point))
1fc01b08 2415 ;; If narrowing gets in the way of going to the right place, widen.
e5456e73 2416 (widen)
1fc01b08
RS
2417 (if next-error-move-function
2418 (funcall next-error-move-function msg mk)
2419 (goto-char mk)))
e5456e73
SM
2420 (if end-mk
2421 (push-mark end-mk t)
2422 (if mark-active (setq mark-active)))
2423 ;; If hideshow got in the way of
2424 ;; seeing the right place, open permanently.
2425 (dolist (ov (overlays-at (point)))
2426 (when (eq 'hs (overlay-get ov 'invisible))
2427 (delete-overlay ov)
2428 (goto-char mk)))
2429
9dc3a46a 2430 (when highlight-regexp
073fcaf6
JL
2431 (if (timerp next-error-highlight-timer)
2432 (cancel-timer next-error-highlight-timer))
9ac57479 2433 (unless compilation-highlight-overlay
c536bb39
SM
2434 (setq compilation-highlight-overlay
2435 (make-overlay (point-min) (point-min)))
2beb6aa0 2436 (overlay-put compilation-highlight-overlay 'face 'next-error))
7837c247 2437 (with-current-buffer (marker-buffer mk)
9ac57479 2438 (save-excursion
9dc3a46a 2439 (if end-mk (goto-char end-mk) (end-of-line))
c536bb39 2440 (let ((end (point)))
9dc3a46a 2441 (if mk (goto-char mk) (beginning-of-line))
9ac57479 2442 (if (and (stringp highlight-regexp)
7837c247 2443 (re-search-forward highlight-regexp end t))
9ac57479
KS
2444 (progn
2445 (goto-char (match-beginning 0))
2beb6aa0
JL
2446 (move-overlay compilation-highlight-overlay
2447 (match-beginning 0) (match-end 0)
2448 (current-buffer)))
2449 (move-overlay compilation-highlight-overlay
2450 (point) end (current-buffer)))
63522e3a
RS
2451 (if (or (eq next-error-highlight t)
2452 (numberp next-error-highlight))
2453 ;; We want highlighting: delete overlay on next input.
2454 (add-hook 'pre-command-hook
2455 'compilation-goto-locus-delete-o)
2456 ;; We don't want highlighting: delete overlay now.
2457 (delete-overlay compilation-highlight-overlay))
2458 ;; We want highlighting for a limited time:
2459 ;; set up a timer to delete it.
2460 (when (numberp next-error-highlight)
2461 (setq next-error-highlight-timer
2462 (run-at-time next-error-highlight nil
2463 'compilation-goto-locus-delete-o)))))))
2beb6aa0 2464 (when (and (eq next-error-highlight 'fringe-arrow))
63522e3a 2465 ;; We want a fringe arrow (instead of highlighting).
6a1cdc5b
JL
2466 (setq next-error-overlay-arrow-position
2467 (copy-marker (line-beginning-position))))))
2468
63522e3a
RS
2469(defun compilation-goto-locus-delete-o ()
2470 (delete-overlay compilation-highlight-overlay)
2471 ;; Get rid of timer and hook that would try to do this again.
2472 (if (timerp next-error-highlight-timer)
2473 (cancel-timer next-error-highlight-timer))
2474 (remove-hook 'pre-command-hook
2475 'compilation-goto-locus-delete-o))
eaa3cac5 2476\f
7957baea 2477(defun compilation-find-file (marker filename directory &rest formats)
851231e9 2478 "Find a buffer for file FILENAME.
5099d512
EZ
2479If FILENAME is not found at all, ask the user where to find it.
2480Pop up the buffer containing MARKER and scroll to MARKER if we ask
2481the user where to find the file.
ffb4b7a1
SM
2482Search the directories in `compilation-search-path'.
2483A nil in `compilation-search-path' means to try the
7957baea 2484\"current\" directory, which is passed in DIRECTORY.
f441be5b
JB
2485If DIRECTORY is relative, it is combined with `default-directory'.
2486If DIRECTORY is nil, that means use `default-directory'.
5099d512
EZ
2487FORMATS, if given, is a list of formats to reformat FILENAME when
2488looking for it: for each element FMT in FORMATS, this function
2489attempts to find a file whose name is produced by (format FMT FILENAME)."
20c1daec 2490 (or formats (setq formats '("%s")))
b8fa0ffd
SM
2491 (let ((dirs compilation-search-path)
2492 (spec-dir (if directory
2493 (expand-file-name directory)
2494 default-directory))
2495 buffer thisdir fmts name)
2496 (if (file-name-absolute-p filename)
2497 ;; The file name is absolute. Use its explicit directory as
2498 ;; the first in the search path, and strip it from FILENAME.
2499 (setq filename (abbreviate-file-name (expand-file-name filename))
2500 dirs (cons (file-name-directory filename) dirs)
2501 filename (file-name-nondirectory filename)))
2502 ;; Now search the path.
2503 (while (and dirs (null buffer))
2504 (setq thisdir (or (car dirs) spec-dir)
2505 fmts formats)
2506 ;; For each directory, try each format string.
2507 (while (and fmts (null buffer))
2508 (setq name (expand-file-name (format (car fmts) filename) thisdir)
2509 buffer (and (file-exists-p name)
2510 (find-file-noselect name))
2511 fmts (cdr fmts)))
2512 (setq dirs (cdr dirs)))
f65b9df2
SM
2513 (while (null buffer) ;Repeat until the user selects an existing file.
2514 ;; The file doesn't exist. Ask the user where to find it.
2515 (save-excursion ;This save-excursion is probably not right.
2516 (let ((pop-up-windows t))
2517 (compilation-set-window (display-buffer (marker-buffer marker))
2518 marker)
2519 (let* ((name (read-file-name
2520 (format "Find this %s in (default %s): "
2521 compilation-error filename)
44038dc8
SM
2522 spec-dir filename t nil
2523 ;; The predicate below is fine when called from
2524 ;; minibuffer-complete-and-exit, but it's too
2525 ;; restrictive otherwise, since it also prevents the
2526 ;; user from completing "fo" to "foo/" when she
2527 ;; wants to enter "foo/bar".
f441be5b 2528 ;;
44038dc8
SM
2529 ;; Try to make sure the user can only select
2530 ;; a valid answer. This predicate may be ignored,
2531 ;; tho, so we still have to double-check afterwards.
2532 ;; TODO: We should probably fix read-file-name so
2533 ;; that it never ignores this predicate, even when
2534 ;; using popup dialog boxes.
2535 ;; (lambda (name)
2536 ;; (if (file-directory-p name)
2537 ;; (setq name (expand-file-name filename name)))
2538 ;; (file-exists-p name))
2539 ))
f65b9df2
SM
2540 (origname name))
2541 (cond
2542 ((not (file-exists-p name))
2543 (message "Cannot find file `%s'" name)
2544 (ding) (sit-for 2))
2545 ((and (file-directory-p name)
2546 (not (file-exists-p
2547 (setq name (expand-file-name filename name)))))
2548 (message "No `%s' in directory %s" filename origname)
2549 (ding) (sit-for 2))
2550 (t
2551 (setq buffer (find-file-noselect name))))))))
b8fa0ffd 2552 ;; Make intangible overlays tangible.
f65b9df2
SM
2553 ;; This is weird: it's not even clear which is the current buffer,
2554 ;; so the code below can't be expected to DTRT here. -- Stef
2555 (dolist (ov (overlays-in (point-min) (point-max)))
2556 (when (overlay-get ov 'intangible)
2557 (overlay-put ov 'intangible nil)))
b8fa0ffd 2558 buffer))
721cfafe 2559
dbd97672
DP
2560(defun compilation-get-file-structure (file &optional fmt)
2561 "Retrieve FILE's file-structure or create a new one.
7957baea
RS
2562FILE should be (FILENAME) or (RELATIVE-FILENAME . DIRNAME).
2563In the former case, FILENAME may be relative or absolute.
dbd97672 2564
7957baea 2565The file-structure looks like this:
07b741a7 2566 ((FILENAME [DIR-FROM-PREV-MSG]) FMT LINE-STRUCT...)"
dbd97672
DP
2567 (or (gethash file compilation-locs)
2568 ;; File was not previously encountered, at least not in the form passed.
2569 ;; Let's normalize it and look again.
2570 (let ((filename (car file))
7957baea
RS
2571 ;; Get the specified directory from FILE.
2572 (spec-directory (if (cdr file)
2573 (file-truename (cdr file)))))
dbd97672
DP
2574
2575 ;; Check for a comint-file-name-prefix and prepend it if appropriate.
2576 ;; (This is very useful for compilation-minor-mode in an rlogin-mode
2577 ;; buffer.)
7957baea
RS
2578 (when (and (boundp 'comint-file-name-prefix)
2579 (not (equal comint-file-name-prefix "")))
2580 (if (file-name-absolute-p filename)
2581 (setq filename
2582 (concat comint-file-name-prefix filename))
2583 (if spec-directory
2584 (setq spec-directory
2585 (file-truename
2586 (concat comint-file-name-prefix spec-directory))))))
dbd97672
DP
2587
2588 ;; If compilation-parse-errors-filename-function is
2589 ;; defined, use it to process the filename.
2590 (when compilation-parse-errors-filename-function
2591 (setq filename
2592 (funcall compilation-parse-errors-filename-function
2593 filename)))
2594
2595 ;; Some compilers (e.g. Sun's java compiler, reportedly) produce bogus
2596 ;; file names like "./bar//foo.c" for file "bar/foo.c";
2597 ;; expand-file-name will collapse these into "/foo.c" and fail to find
2598 ;; the appropriate file. So we look for doubled slashes in the file
2599 ;; name and fix them.
2600 (setq filename (command-line-normalize-file-name filename))
2601
dbd97672
DP
2602 ;; Store it for the possibly unnormalized name
2603 (puthash file
2604 ;; Retrieve or create file-structure for normalized name
e68b1841
GM
2605 ;; The gethash used to not use spec-directory, but
2606 ;; this leads to errors when files in different
2607 ;; directories have the same name:
2608 ;; http://lists.gnu.org/archive/html/emacs-devel/2007-08/msg00463.html
2609 (or (gethash (cons filename spec-directory) compilation-locs)
34a9bf20 2610 (puthash (cons filename spec-directory)
8fe52384
SM
2611 (compilation--make-file-struct
2612 (list filename spec-directory) fmt)
7957baea 2613 compilation-locs))
dbd97672 2614 compilation-locs))))
51501e54 2615
07b741a7
SM
2616(defun compilation--flush-file-structure (file)
2617 (or (consp file) (setq file (list file)))
2618 (let ((fs (compilation-get-file-structure file)))
2619 (assert (eq fs (gethash file compilation-locs)))
2620 (assert (eq fs (gethash (cons (caar fs) (cadr (car fs)))
2621 compilation-locs)))
2622 (maphash (lambda (k v)
2623 (if (eq v fs) (remhash k compilation-locs)))
2624 compilation-locs)))
2625
2626(add-to-list 'debug-ignored-errors "\\`No more [-a-z ]+s yet\\'")
2627(add-to-list 'debug-ignored-errors "\\`Moved past last .*")
f1ed9461 2628
c536bb39
SM
2629;;; Compatibility with the old compile.el.
2630
07b741a7
SM
2631(defvaralias 'compilation-last-buffer 'next-error-last-buffer)
2632(defvar compilation-parsing-end (make-marker))
2633(defvar compilation-error-list nil)
2634(defvar compilation-old-error-list nil)
c536bb39 2635
07b741a7 2636(defun compilation--compat-error-properties (err)
6f5b7627 2637 "Map old-style error ERR to new-style message."
efb0e677
SM
2638 ;; Old-style structure is (MARKER (FILE DIR) LINE COL) or
2639 ;; (MARKER . MARKER).
2640 (let ((dst (cdr err)))
2641 (if (markerp dst)
55fb9013 2642 `(compilation-message ,(compilation--make-message
8fe52384
SM
2643 (cons nil (compilation--make-cdrloc
2644 nil nil dst))
2645 2 nil)
efb0e677
SM
2646 help-echo "mouse-2: visit the source location"
2647 keymap compilation-button-map
2648 mouse-face highlight)
2649 ;; Too difficult to do it by hand: dispatch to the normal code.
2650 (let* ((file (pop dst))
2651 (line (pop dst))
2652 (col (pop dst))
2653 (filename (pop file))
2654 (dirname (pop file))
2655 (fmt (pop file)))
2656 (compilation-internal-error-properties
2657 (cons filename dirname) line nil col nil 2 fmt)))))
c536bb39 2658
07b741a7 2659(defun compilation--compat-parse-errors (limit)
c536bb39
SM
2660 (when compilation-parse-errors-function
2661 ;; FIXME: We should remove the rest of the compilation keywords
2662 ;; but we can't do that from here because font-lock is using
07b741a7 2663 ;; the value right now. --Stef
c536bb39
SM
2664 (save-excursion
2665 (setq compilation-error-list nil)
2666 ;; Reset compilation-parsing-end each time because font-lock
2667 ;; might force us the re-parse many times (typically because
2668 ;; some code adds some text-property to the output that we
2669 ;; already parsed). You might say "why reparse", well:
07b741a7
SM
2670 ;; because font-lock has just removed the `compilation-message' property
2671 ;; so have to do it all over again.
c536bb39
SM
2672 (if compilation-parsing-end
2673 (set-marker compilation-parsing-end (point))
2674 (setq compilation-parsing-end (point-marker)))
2675 (condition-case nil
2676 ;; Ignore any error: we're calling this function earlier than
2677 ;; in the old compile.el so things might not all be setup yet.
2678 (funcall compilation-parse-errors-function limit nil)
2679 (error nil))
2680 (dolist (err (if (listp compilation-error-list) compilation-error-list))
2681 (let* ((src (car err))
2682 (dst (cdr err))
8fe52384
SM
2683 (loc (cond ((markerp dst)
2684 (cons nil
2685 (compilation--make-cdrloc nil nil dst)))
c536bb39 2686 ((consp dst)
8fe52384
SM
2687 (cons (nth 2 dst)
2688 (compilation--make-cdrloc
2689 (nth 1 dst)
2690 (cons (cdar dst) (caar dst))
2691 nil))))))
c536bb39
SM
2692 (when loc
2693 (goto-char src)
07b741a7
SM
2694 ;; (put-text-property src (line-end-position)
2695 ;; 'font-lock-face 'font-lock-warning-face)
c536bb39 2696 (put-text-property src (line-end-position)
8fe52384
SM
2697 'compilation-message
2698 (compilation--make-message loc 2 nil)))))))
c536bb39
SM
2699 (goto-char limit)
2700 nil)
2701
07b741a7 2702;; Beware! this is not only compatibility code. New code also uses it. --Stef
c536bb39
SM
2703(defun compilation-forget-errors ()
2704 ;; In case we hit the same file/line specs, we want to recompute a new
2705 ;; marker for them, so flush our cache.
331b2b90 2706 (clrhash compilation-locs)
e3bef839 2707 (setq compilation-gcpro nil)
c536bb39
SM
2708 ;; FIXME: the old code reset the directory-stack, so maybe we should
2709 ;; put a `directory change' marker of some sort, but where? -stef
b3a7f48f 2710 ;;
c536bb39
SM
2711 ;; FIXME: The old code moved compilation-current-error (which was
2712 ;; virtually represented by a mix of compilation-parsing-end and
2713 ;; compilation-error-list) to point-min, but that was only meaningful for
2714 ;; the internal uses of compilation-forget-errors: all calls from external
2715 ;; packages seem to be followed by a move of compilation-parsing-end to
b956d64f 2716 ;; something equivalent to point-max. So we heuristically move
c536bb39 2717 ;; compilation-current-error to point-max (since the external package
b956d64f 2718 ;; won't know that it should do it). --Stef
9b7b51a2
SM
2719 (setq compilation-current-error nil)
2720 (let* ((proc (get-buffer-process (current-buffer)))
2721 (mark (if proc (process-mark proc)))
2722 (pos (or mark (point-max))))
2723 (setq compilation-messages-start
2724 ;; In the future, ignore the text already present in the buffer.
2725 ;; Since many process filter functions insert before markers,
2726 ;; we need to put ours just before the insertion point rather
2727 ;; than at the insertion point. If that's not possible, then
2728 ;; don't use a marker. --Stef
b956d64f
SM
2729 (if (> pos (point-min)) (copy-marker (1- pos)) pos)))
2730 ;; Again, since this command is used in buffers that contain several
2731 ;; compilations, to set the beginning of "this compilation", it's a good
2732 ;; place to reset compilation-auto-jump-to-next.
2733 (set (make-local-variable 'compilation-auto-jump-to-next)
78dc87a2
JL
2734 (or compilation-auto-jump-to-first-error
2735 (eq compilation-scroll-output 'first-error))))
c536bb39 2736
4746118a 2737(provide 'compile)
fad160d5
ER
2738
2739;;; compile.el ends here