Commit | Line | Data |
---|---|---|
daa37602 | 1 | ;;; compile.el --- run compiler as inferior of Emacs, parse error messages. |
fad160d5 | 2 | |
e93b2a55 | 3 | ;; Copyright (C) 1985, 86, 87, 93, 94, 95, 96, 1997 Free Software Foundation, Inc. |
3a801d0c | 4 | |
29add8b9 | 5 | ;; Author: Roland McGrath <roland@prep.ai.mit.edu> |
d1c7011d | 6 | ;; Maintainer: FSF |
e9571d2a | 7 | ;; Keywords: tools, processes |
d1c7011d | 8 | |
55dfd2c4 RS |
9 | ;; This file is part of GNU Emacs. |
10 | ||
29add8b9 RM |
11 | ;; GNU Emacs is free software; you can redistribute it and/or modify |
12 | ;; it under the terms of the GNU General Public License as published by | |
13 | ;; the Free Software Foundation; either version 2, or (at your option) | |
14 | ;; any later version. | |
15 | ||
55dfd2c4 | 16 | ;; GNU Emacs is distributed in the hope that it will be useful, |
29add8b9 RM |
17 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
18 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
19 | ;; GNU General Public License for more details. | |
20 | ||
21 | ;; You should have received a copy of the GNU General Public License | |
b578f267 EN |
22 | ;; along with GNU Emacs; see the file COPYING. If not, write to the |
23 | ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
24 | ;; Boston, MA 02111-1307, USA. | |
55dfd2c4 | 25 | |
5cc57841 ER |
26 | ;;; Commentary: |
27 | ||
28 | ;; This package provides the compile and grep facilities documented in | |
29 | ;; the Emacs user's manual. | |
30 | ||
d1c7011d ER |
31 | ;;; Code: |
32 | ||
c5049fa0 RS |
33 | (defgroup compilation nil |
34 | "Run compiler as inferior of Emacs, parse error messages." | |
35 | :group 'tools | |
36 | :group 'processes) | |
37 | ||
38 | ||
7c163413 | 39 | ;;;###autoload |
c5049fa0 RS |
40 | (defcustom compilation-mode-hook nil |
41 | "*List of hook functions run by `compilation-mode' (see `run-hooks')." | |
42 | :type 'hook | |
43 | :group 'compilation) | |
7c163413 RM |
44 | |
45 | ;;;###autoload | |
c5049fa0 RS |
46 | (defcustom compilation-window-height nil |
47 | "*Number of lines in a compilation window. If nil, use Emacs default." | |
48 | :type '(choice (const :tag "Default" nil) | |
49 | integer) | |
50 | :group 'compilation) | |
d3cb357b | 51 | |
01e6e8c9 | 52 | (defvar compile-auto-highlight nil |
37f5f978 | 53 | "*Specify how many compiler errors to highlight (and parse) initially. |
a24770bc | 54 | \(Highlighting applies to an error message when the mouse is over it.) |
37f5f978 RS |
55 | If this is a number N, all compiler error messages in the first N lines |
56 | are highlighted and parsed as soon as they arrive in Emacs. | |
01e6e8c9 | 57 | If t, highlight and parse the whole compilation output as soon as it arrives. |
37f5f978 RS |
58 | If nil, don't highlight or parse any of the buffer until you try to |
59 | move to the error messages. | |
60 | ||
01e6e8c9 | 61 | Those messages which are not parsed and highlighted initially |
37f5f978 RS |
62 | will be parsed and highlighted as soon as you try to move to them.") |
63 | ||
55dfd2c4 RS |
64 | (defvar compilation-error-list nil |
65 | "List of error message descriptors for visiting erring functions. | |
fc0094d7 RM |
66 | Each error descriptor is a cons (or nil). Its car is a marker pointing to |
67 | an error message. If its cdr is a marker, it points to the text of the | |
533304f8 RM |
68 | line the message is about. If its cdr is a cons, it is a list |
69 | \(\(DIRECTORY . FILE\) LINE [COLUMN]\). Or its cdr may be nil if that | |
70 | error is not interesting. | |
d3cb357b RM |
71 | |
72 | The value may be t instead of a list; this means that the buffer of | |
29478cc5 JB |
73 | error messages should be reparsed the next time the list of errors is wanted. |
74 | ||
75 | Some other commands (like `diff') use this list to control the error | |
9c09c008 | 76 | message tracking facilities; if you change its structure, you should make |
29478cc5 JB |
77 | sure you also change those packages. Perhaps it is better not to change |
78 | it at all.") | |
55dfd2c4 RS |
79 | |
80 | (defvar compilation-old-error-list nil | |
81 | "Value of `compilation-error-list' after errors were parsed.") | |
82 | ||
501cf428 | 83 | (defvar compilation-parse-errors-function 'compilation-parse-errors |
b2bb6ec8 | 84 | "Function to call to parse error messages from a compilation. |
c540863c RM |
85 | It takes args LIMIT-SEARCH and FIND-AT-LEAST. |
86 | If LIMIT-SEARCH is non-nil, don't bother parsing past that location. | |
501cf428 | 87 | If FIND-AT-LEAST is non-nil, don't bother parsing after finding that |
e78e10ca | 88 | many new errors. |
d3cb357b RM |
89 | It should read in the source files which have errors and set |
90 | `compilation-error-list' to a list with an element for each error message | |
91 | found. See that variable for more info.") | |
55dfd2c4 | 92 | |
49683a13 EZ |
93 | ;;;###autoload |
94 | (defvar compilation-process-setup-function nil | |
95 | "*Function to call to customize the compilation process. | |
96 | This functions is called immediately before the compilation process is | |
97 | started. It can be used to set any variables or functions that are used | |
98 | while processing the output of the compilation process.") | |
99 | ||
aa228418 | 100 | ;;;###autoload |
d3cb357b | 101 | (defvar compilation-buffer-name-function nil |
6c43f2f9 RS |
102 | "Function to compute the name of a compilation buffer. |
103 | The function receives one argument, the name of the major mode of the | |
104 | compilation buffer. It should return a string. | |
105 | nil means compute the name with `(concat \"*\" (downcase major-mode) \"*\")'.") | |
55dfd2c4 | 106 | |
aa228418 | 107 | ;;;###autoload |
d3cb357b | 108 | (defvar compilation-finish-function nil |
c5049fa0 | 109 | "Function to call when a compilation process finishes. |
d3cb357b RM |
110 | It is called with two arguments: the compilation buffer, and a string |
111 | describing how the process finished.") | |
55dfd2c4 | 112 | |
4cc36b17 RS |
113 | ;;;###autoload |
114 | (defvar compilation-finish-functions nil | |
c5049fa0 | 115 | "Functions to call when a compilation process finishes. |
4cc36b17 RS |
116 | Each function is called with two arguments: the compilation buffer, |
117 | and a string describing how the process finished.") | |
118 | ||
d3cb357b | 119 | (defvar compilation-last-buffer nil |
6c43f2f9 RS |
120 | "The most recent compilation buffer. |
121 | A buffer becomes most recent when its compilation is started | |
122 | or when it is used with \\[next-error] or \\[compile-goto-error].") | |
55dfd2c4 | 123 | |
ebff767c RM |
124 | (defvar compilation-in-progress nil |
125 | "List of compilation processes now running.") | |
126 | (or (assq 'compilation-in-progress minor-mode-alist) | |
127 | (setq minor-mode-alist (cons '(compilation-in-progress " Compiling") | |
128 | minor-mode-alist))) | |
129 | ||
d3cb357b RM |
130 | (defvar compilation-parsing-end nil |
131 | "Position of end of buffer when last error messages were parsed.") | |
132 | ||
133 | (defvar compilation-error-message "No more errors" | |
6c43f2f9 RS |
134 | "Message to print when no more matches are found.") |
135 | ||
58856335 RS |
136 | (defvar compilation-arguments nil |
137 | "Arguments that were given to `compile-internal'.") | |
138 | ||
6c43f2f9 | 139 | (defvar compilation-num-errors-found) |
d3cb357b RM |
140 | |
141 | (defvar compilation-error-regexp-alist | |
142 | '( | |
d86bdede | 143 | ;; NOTE! See also grep-regexp-alist, below. |
7ee790ac | 144 | |
d3cb357b | 145 | ;; 4.3BSD grep, cc, lint pass 1: |
7ee790ac RM |
146 | ;; /usr/src/foo/foo.c(8): warning: w may be used before set |
147 | ;; or GNU utilities: | |
148 | ;; foo.c:8: error message | |
149 | ;; or HP-UX 7.0 fc: | |
150 | ;; foo.f :16 some horrible error message | |
08b1edf4 RM |
151 | ;; or GNU utilities with column (GNAT 1.82): |
152 | ;; foo.adb:2:1: Unit name does not match file name | |
501cf428 | 153 | ;; |
57c8389c JB |
154 | ;; We'll insist that the number be followed by a colon or closing |
155 | ;; paren, because otherwise this matches just about anything | |
156 | ;; containing a number with spaces around it. | |
a24770bc | 157 | ("\\([a-zA-Z]?:?[^:( \t\n]+\\)[:(][ \t]*\\([0-9]+\\)\\([) \t]\\|\ |
08b1edf4 | 158 | :\\([^0-9\n]\\|\\([0-9]+:\\)\\)\\)" 1 2 5) |
69d4d27f | 159 | |
0c43cc89 RS |
160 | ;; Microsoft C/C++: |
161 | ;; keyboard.c(537) : warning C4005: 'min' : macro redefinition | |
162 | ;; d:\tmp\test.c(23) : error C2143: syntax error : missing ';' before 'if' | |
9cab952d RS |
163 | ;; This used to be less selective and allow characters other than |
164 | ;; parens around the line number, but that caused confusion for | |
165 | ;; GNU-style error messages. | |
d2705a18 RS |
166 | ;; This used to reject spaces and dashes in file names, |
167 | ;; but they are valudnow; so I made it more strict about the error | |
168 | ;; message that follows. | |
169 | ("\\(\\([a-zA-Z]:\\)?[^:(\t\n]+\\)(\\([0-9]+\\)) \ | |
170 | : \\(error\\|warning\\) C[0-9]+:" 1 3) | |
0c43cc89 | 171 | |
69d4d27f RS |
172 | ;; Borland C++: |
173 | ;; Error ping.c 15: Unable to open include file 'sys/types.h' | |
174 | ;; Warning ping.c 68: Call to function 'func' with no prototype | |
2fa55e20 | 175 | ("\\(Error\\|Warning\\) \\([a-zA-Z]?:?[^:( \t\n]+\\)\ |
69d4d27f | 176 | \\([0-9]+\\)\\([) \t]\\|:[^0-9\n]\\)" 2 3) |
7ee790ac | 177 | |
d3cb357b | 178 | ;; 4.3BSD lint pass 2 |
7ee790ac | 179 | ;; strcmp: variable # of args. llib-lc(359) :: /usr/src/foo/foo.c(8) |
2fa55e20 | 180 | (".*[ \t:]\\([a-zA-Z]?:?[^:( \t\n]+\\)[:(](+[ \t]*\\([0-9]+\\))[:) \t]*$" |
3e8258e7 | 181 | 1 2) |
7ee790ac | 182 | |
d3cb357b | 183 | ;; 4.3BSD lint pass 3 |
7ee790ac | 184 | ;; bloofle defined( /users/wolfgang/foo.c(4) ), but never used |
daa37602 | 185 | ;; This used to be |
3e8258e7 | 186 | ;; ("[ \t(]+\\([a-zA-Z]?:?[^:( \t\n]+\\)[:( \t]+\\([0-9]+\\)[:) \t]+" 1 2) |
daa37602 | 187 | ;; which is regexp Impressionism - it matches almost anything! |
2fa55e20 | 188 | (".*([ \t]*\\([a-zA-Z]?:?[^:( \t\n]+\\)[:(][ \t]*\\([0-9]+\\))" 1 2) |
7ee790ac | 189 | |
369d3cdc RM |
190 | ;; MIPS lint pass<n>; looks good for SunPro lint also |
191 | ;; TrimMask (255) in solomon.c may be indistinguishable from TrimMasks (93) in solomon.c due to truncation | |
2fa55e20 | 192 | ("[^\n ]+ (\\([0-9]+\\)) in \\([^ \n]+\\)" 2 1) |
369d3cdc | 193 | ;; name defined but never used: LinInt in cmap_calc.c(199) |
2fa55e20 | 194 | (".*in \\([^(\n]+\\)(\\([0-9]+\\))$" 1 2) |
369d3cdc | 195 | |
ff735134 | 196 | ;; Ultrix 3.0 f77: |
f89fdaed | 197 | ;; fort: Severe: addstf.f, line 82: Missing operator or delimiter symbol |
984ae4ed RM |
198 | ;; Some SGI cc version: |
199 | ;; cfe: Warning 835: foo.c, line 2: something | |
2fa55e20 | 200 | ("\\(cfe\\|fort\\): [^:\n]*: \\([^ \n]*\\), line \\([0-9]+\\):" 2 3) |
501cf428 | 201 | ;; Error on line 3 of t.f: Execution error unclassifiable statement |
ff735134 | 202 | ;; Unknown who does this: |
9c09c008 | 203 | ;; Line 45 of "foo.c": bloofle undefined |
5ff3b093 RM |
204 | ;; Absoft FORTRAN 77 Compiler 3.1.3 |
205 | ;; error on line 19 of fplot.f: spelling error? | |
206 | ;; warning on line 17 of fplot.f: data type is undefined for variable d | |
a24770bc | 207 | ("\\(.* on \\)?[Ll]ine[ \t]+\\([0-9]+\\)[ \t]+\ |
3e8258e7 | 208 | of[ \t]+\"?\\([a-zA-Z]?:?[^\":\n]+\\)\"?:" 3 2) |
7ee790ac RM |
209 | |
210 | ;; Apollo cc, 4.3BSD fc: | |
211 | ;; "foo.f", line 3: Error: syntax error near end of statement | |
6d68d793 RS |
212 | ;; IBM RS6000: |
213 | ;; "vvouch.c", line 19.5: 1506-046 (S) Syntax error. | |
a0c567b5 RM |
214 | ;; Microtec mcc68k: |
215 | ;; "foo.c", line 32 pos 1; (E) syntax error; unexpected symbol: "lossage" | |
501cf428 | 216 | ;; GNAT (as of July 94): |
37fd2208 | 217 | ;; "foo.adb", line 2(11): warning: file name does not match ... |
b1707ae4 RM |
218 | ;; IBM AIX xlc compiler: |
219 | ;; "src/swapping.c", line 30.34: 1506-342 (W) "/*" detected in comment. | |
2fa55e20 | 220 | (".*\"\\([^,\" \n\t]+\\)\", lines? \ |
b1707ae4 | 221 | \\([0-9]+\\)\\([\(.]\\([0-9]+\\)\)?\\)?[:., (-]" 1 2 4) |
18710add | 222 | |
96db060f RS |
223 | ;; Caml compiler: |
224 | ;; File "foobar.ml", lines 5-8, characters 20-155: blah blah | |
225 | ("^File \"\\([^,\" \n\t]+\\)\", lines? \\([0-9]+\\)[-0-9]*, characters? \\([0-9]+\\)" 1 2 3) | |
226 | ||
18710add | 227 | ;; MIPS RISC CC - the one distributed with Ultrix: |
7ee790ac | 228 | ;; ccom: Error: foo.c, line 2: syntax error |
dfb89664 | 229 | ;; DEC AXP OSF/1 cc |
501cf428 | 230 | ;; /usr/lib/cmplrs/cc/cfe: Error: foo.c: 1: blah blah |
2f5f9dbd | 231 | ("[a-z/]+: \\([eE]rror\\|[wW]arning\\): \\([^,\" \n\t]+\\)[,:] \\(line \\)?\\([0-9]+\\):" 2 4) |
7ee790ac RM |
232 | |
233 | ;; IBM AIX PS/2 C version 1.1: | |
234 | ;; ****** Error number 140 in line 8 of file errors.c ****** | |
2fa55e20 | 235 | (".*in line \\([0-9]+\\) of file \\([^ \n]+[^. \n]\\)\\.? " 2 1) |
d3cb357b RM |
236 | ;; IBM AIX lint is too painful to do right this way. File name |
237 | ;; prefixes entire sections rather than being on each line. | |
57c8389c | 238 | |
a24770bc RS |
239 | ;; SPARCcompiler Pascal: |
240 | ;; 20 linjer : array[1..4] of linje; | |
241 | ;; e 18480-----------^--- Inserted ';' | |
242 | ;; and | |
243 | ;; E 18520 line 61 - 0 is undefined | |
244 | ;; These messages don't contain a file name. Instead the compiler gives | |
245 | ;; a message whenever the file being compiled is changed. | |
246 | (" +\\([0-9]+\\) +.*\n[ew] [0-9]+-+" nil 1) | |
247 | ("[Ew] +[0-9]+ line \\([0-9]+\\) - " nil 1) | |
248 | ||
72244bea RM |
249 | ;; Lucid Compiler, lcc 3.x |
250 | ;; E, file.cc(35,52) Illegal operation on pointers | |
2fa55e20 | 251 | ("[EW], \\([^(\n]*\\)(\\([0-9]+\\),[ \t]*\\([0-9]+\\)" 1 2 3) |
72244bea | 252 | |
9cab952d RS |
253 | ;;; This seems to be superfluous because the first pattern matches it. |
254 | ;;; ;; GNU messages with program name and optional column number. | |
255 | ;;; ("[a-zA-Z]?:?[^0-9 \n\t:]+[^ \n\t:]*:[ \t]*\\([^ \n\t:]+\\):\ | |
256 | ;;;\\([0-9]+\\):\\(\\([0-9]+\\)[: \t]\\)?" 1 2 4) | |
4dbf8a2c RM |
257 | |
258 | ;; Cray C compiler error messages | |
a24770bc RS |
259 | ("\\(cc\\| cft\\)-[0-9]+ c\\(c\\|f77\\): ERROR \\([^,\n]+, \\)* File = \ |
260 | \\([^,\n]+\\), Line = \\([0-9]+\\)" 4 5) | |
4dbf8a2c RM |
261 | |
262 | ;; IBM C/C++ Tools 2.01: | |
263 | ;; foo.c(2:0) : informational EDC0804: Function foo is not referenced. | |
264 | ;; foo.c(3:8) : warning EDC0833: Implicit return statement encountered. | |
265 | ;; foo.c(5:5) : error EDC0350: Syntax error. | |
2fa55e20 | 266 | ("\\([^( \n\t]+\\)(\\([0-9]+\\):\\([0-9]+\\)) : " 1 2 3) |
cfda7e6d | 267 | |
b1b56e01 RS |
268 | ;; IAR Systems C Compiler: |
269 | ;; "foo.c",3 Error[32]: Error message | |
270 | ;; "foo.c",3 Warning[32]: Error message | |
271 | ("\"\\(.*\\)\",\\([0-9]+\\)\\s-+\\(Error\\|Warning\\)\\[[0-9]+\\]:" 1 2) | |
272 | ||
cfda7e6d RM |
273 | ;; Sun ada (VADS, Solaris): |
274 | ;; /home3/xdhar/rcds_rc/main.a, line 361, char 6:syntax error: "," inserted | |
2fa55e20 | 275 | ("\\([^, \n\t]+\\), line \\([0-9]+\\), char \\([0-9]+\\)[:., \(-]" 1 2 3) |
cbf7f476 RS |
276 | |
277 | ;; Perl -w: | |
278 | ;; syntax error at automake line 922, near "':'" | |
a24770bc | 279 | (".* at \\([^ ]+\\) line \\([0-9]+\\)," 1 2) |
7ce22b41 RS |
280 | |
281 | ;; Oracle pro*c: | |
282 | ;; Semantic error at line 528, column 5, file erosacqdb.pc: | |
283 | ("Semantic error at line \\([0-9]+\\), column \\([0-9]+\\), file \\(.*\\):" | |
284 | 3 1 2) | |
5dfa3d35 RS |
285 | |
286 | ;; EPC F90 compiler: | |
287 | ;; Error 24 at (2:progran.f90) : syntax error | |
288 | ("Error [0-9]+ at (\\([0-9]*\\):\\([^)\n]+\\))" 2 1) | |
c7c5bbc0 KH |
289 | |
290 | ;; Sun F90 error messages: | |
291 | ;; cf90-113 f90comp: ERROR NSE, File = Hoved.f90, Line = 16, Column = 3 | |
292 | (".* ERROR [a-zA-Z0-9 ]+, File = \\(.+\\), Line = \\([0-9]+\\), Column = \\([0-9]+\\)" | |
293 | 1 2 3) | |
d3cb357b | 294 | ) |
6c43f2f9 | 295 | "Alist that specifies how to match errors in compiler output. |
20c1daec | 296 | Each elt has the form (REGEXP FILE-IDX LINE-IDX [COLUMN-IDX FILE-FORMAT...]) |
72244bea RM |
297 | If REGEXP matches, the FILE-IDX'th subexpression gives the file name, and |
298 | the LINE-IDX'th subexpression gives the line number. If COLUMN-IDX is | |
20c1daec RM |
299 | given, the COLUMN-IDX'th subexpression gives the column number on that line. |
300 | If any FILE-FORMAT is given, each is a format string to produce a file name to | |
301 | try; %s in the string is replaced by the text matching the FILE-IDX'th | |
302 | subexpression.") | |
55dfd2c4 | 303 | |
a24770bc RS |
304 | (defvar compilation-enter-directory-regexp-alist |
305 | '( | |
306 | ;; Matches lines printed by the `-w' option of GNU Make. | |
307 | (".*: Entering directory `\\(.*\\)'$" 1) | |
308 | ) | |
309 | "Alist specifying how to match lines that indicate a new current directory. | |
310 | Note that the match is done at the beginning of lines. | |
311 | Each elt has the form (REGEXP IDX). | |
312 | If REGEXP matches, the IDX'th subexpression gives the directory name. | |
313 | ||
314 | The default value matches lines printed by the `-w' option of GNU Make.") | |
315 | ||
316 | (defvar compilation-leave-directory-regexp-alist | |
317 | '( | |
318 | ;; Matches lines printed by the `-w' option of GNU Make. | |
319 | (".*: Leaving directory `\\(.*\\)'$" 1) | |
320 | ) | |
321 | "Alist specifying how to match lines that indicate restoring current directory. | |
322 | Note that the match is done at the beginning of lines. | |
323 | Each elt has the form (REGEXP IDX). | |
324 | If REGEXP matches, the IDX'th subexpression gives the name of the directory | |
325 | being moved from. If IDX is nil, the last directory entered \(by a line | |
326 | matching `compilation-enter-directory-regexp-alist'\) is assumed. | |
327 | ||
328 | The default value matches lines printed by the `-w' option of GNU Make.") | |
329 | ||
330 | (defvar compilation-file-regexp-alist | |
331 | '( | |
332 | ;; This matches entries with date time year file-name: like | |
333 | ;; Thu May 14 10:46:12 1992 mom3.p: | |
334 | ("\\w\\w\\w \\w\\w\\w +[0-9]+ [0-9][0-9]:[0-9][0-9]:[0-9][0-9] [0-9][0-9][0-9][0-9] \\(.*\\):$" 1) | |
335 | ) | |
336 | "Alist specifying how to match lines that indicate a new current file. | |
337 | Note that the match is done at the beginning of lines. | |
338 | Each elt has the form (REGEXP IDX). | |
339 | If REGEXP matches, the IDX'th subexpression gives the file name. This is | |
340 | used with compilers that don't indicate file name in every error message.") | |
341 | ||
342 | ;; There is no generally useful regexp that will match non messages, but | |
343 | ;; in special cases there might be one. The lines that are not matched by | |
344 | ;; a regexp take much longer time than the ones that are recognized so if | |
345 | ;; you have same regexeps here, parsing is faster. | |
346 | (defvar compilation-nomessage-regexp-alist | |
347 | '( | |
348 | ) | |
349 | "Alist specifying how to match lines that have no message. | |
350 | Note that the match is done at the beginning of lines. | |
351 | Each elt has the form (REGEXP). This alist is by default empty, but if | |
352 | you have some good regexps here, the parsing of messages will be faster.") | |
353 | ||
c5049fa0 RS |
354 | (defcustom compilation-read-command t |
355 | "*If not nil, M-x compile reads the compilation command to use. | |
356 | Otherwise, M-x compile just uses the value of `compile-command'." | |
357 | :type 'boolean | |
358 | :group 'compilation) | |
90016295 | 359 | |
e83be080 | 360 | ;;;###autoload |
c5049fa0 RS |
361 | (defcustom compilation-ask-about-save t |
362 | "*If not nil, M-x compile asks which buffers to save before compiling. | |
363 | Otherwise, it saves all modified buffers without asking." | |
364 | :type 'boolean | |
365 | :group 'compilation) | |
90016295 | 366 | |
15d1a8da | 367 | (defvar grep-regexp-alist |
a24770bc | 368 | '(("\\([a-zA-Z]?:?[^:( \t\n]+\\)[:( \t]+\\([0-9]+\\)[:) \t]" 1 2)) |
15d1a8da RM |
369 | "Regexp used to match grep hits. See `compilation-error-regexp-alist'.") |
370 | ||
54bfce8a RS |
371 | ;; The system null device. (Should reference NULL_DEVICE from C.) |
372 | (defvar grep-null-device "/dev/null" "The system null device.") | |
373 | ||
201bf332 | 374 | (defvar grep-program |
000a6a76 RS |
375 | ;; Currently zgrep has trouble. It runs egrep instead of grep, |
376 | ;; and it doesn't pass along long options right. | |
377 | "grep" | |
378 | ;;; (if (equal (condition-case nil ; in case "zgrep" isn't in exec-path | |
379 | ;;; (call-process "zgrep" nil nil nil | |
380 | ;;; "foo" grep-null-device) | |
381 | ;;; (error nil)) | |
382 | ;;; 1) | |
383 | ;;; "zgrep" | |
384 | ;;; "grep") | |
201bf332 RS |
385 | "The default grep program for `grep-command' and `grep-find-command'.") |
386 | ||
387 | ;; Use -e if grep supports it, | |
388 | ;; because that avoids lossage if the pattern starts with `-'. | |
389 | (defvar grep-command | |
390 | (if (equal (condition-case nil ; in case "grep" isn't in exec-path | |
391 | (call-process grep-program nil nil nil | |
392 | "-e" "foo" grep-null-device) | |
393 | (error nil)) | |
394 | 1) | |
395 | (format "%s -n -e " grep-program) | |
396 | (format "%s -n " grep-program)) | |
397 | "The default grep command for \\[grep].") | |
398 | ||
399 | (defvar grep-find-use-xargs | |
400 | (if (equal (call-process "find" nil nil nil | |
401 | grep-null-device "-print0") | |
402 | 0) | |
403 | 'gnu) | |
404 | "Whether \\[grep-find] uses the `xargs' utility by default. | |
405 | ||
406 | If nil, it uses `grep -exec'; if `gnu', it uses `find -print0' and `xargs -0'; | |
407 | if not nil and not `gnu', it uses `find -print' and `xargs'. | |
408 | ||
409 | This variable's value takes effect when `compile.el' is loaded | |
410 | by influencing the default value for the variable `grep-find-command'.") | |
411 | ||
412 | (defvar grep-find-command | |
413 | (cond ((eq grep-find-use-xargs 'gnu) | |
414 | (format "find . -type f -print0 | xargs -0 -e %s" grep-command)) | |
415 | (grep-find-use-xargs | |
416 | (format "find . -type f -print | xargs %s" grep-command)) | |
417 | (t (cons (format "find . -type f -exec %s {} /dev/null \\;" | |
418 | grep-command) | |
419 | (+ 22 (length grep-command))))) | |
420 | "The default find command for \\[grep-find].") | |
98b63c41 | 421 | |
7c163413 | 422 | ;;;###autoload |
c5049fa0 | 423 | (defcustom compilation-search-path '(nil) |
7c163413 | 424 | "*List of directories to search for source files named in error messages. |
d3cb357b | 425 | Elements should be directory names, not file names of directories. |
c5049fa0 RS |
426 | nil as an element means to try the default directory." |
427 | :type '(repeat (choice (const :tag "Default" nil) | |
428 | (string :tag "Directory"))) | |
429 | :group 'compilation) | |
55dfd2c4 | 430 | |
c5049fa0 RS |
431 | (defcustom compile-command "make -k " |
432 | "*Last shell command used to do a compilation; default for next compilation. | |
55dfd2c4 RS |
433 | |
434 | Sometimes it is useful for files to supply local values for this variable. | |
435 | You might also use mode hooks to specify it in certain modes, like this: | |
436 | ||
61c4aaf8 RS |
437 | (add-hook 'c-mode-hook |
438 | (function | |
439 | (lambda () | |
440 | (unless (or (file-exists-p \"makefile\") | |
441 | (file-exists-p \"Makefile\")) | |
442 | (make-local-variable 'compile-command) | |
443 | (setq compile-command | |
444 | (concat \"make -k \" | |
445 | (file-name-sans-extension buffer-file-name)))))))" | |
c5049fa0 RS |
446 | :type 'string |
447 | :group 'compilation) | |
55dfd2c4 | 448 | |
d3cb357b | 449 | (defvar compilation-directory-stack nil |
6c43f2f9 RS |
450 | "Stack of previous directories for `compilation-leave-directory-regexp'. |
451 | The head element is the directory the compilation was started in.") | |
d3cb357b | 452 | |
01f89d11 RM |
453 | (defvar compilation-exit-message-function nil "\ |
454 | If non-nil, called when a compilation process dies to return a status message. | |
fd5e58d7 RM |
455 | This should be a function of three arguments: process status, exit status, |
456 | and exit message; it returns a cons (MESSAGE . MODELINE) of the strings to | |
457 | write into the compilation buffer, and to put in its mode line.") | |
01f89d11 | 458 | |
770970cb RS |
459 | ;; History of compile commands. |
460 | (defvar compile-history nil) | |
461 | ;; History of grep commands. | |
462 | (defvar grep-history nil) | |
201bf332 | 463 | (defvar grep-find-history nil) |
770970cb | 464 | |
e93b2a55 SM |
465 | (defun compilation-mode-font-lock-keywords () |
466 | "Return expressions to highlight in Compilation mode." | |
467 | (nconc | |
468 | ;; | |
469 | ;; Compiler warning/error lines. | |
5dfa3d35 RS |
470 | (mapcar (function |
471 | (lambda (item) | |
472 | ;; Prepend "^", adjusting FILE-IDX and LINE-IDX accordingly. | |
22052f1d KH |
473 | (let ((file-idx (nth 1 item)) |
474 | (line-idx (nth 2 item)) | |
475 | (col-idx (nth 3 item)) | |
476 | keyword) | |
477 | (when (numberp col-idx) | |
478 | (setq keyword | |
479 | (cons (list (1+ col-idx) 'font-lock-type-face nil t) | |
480 | keyword))) | |
5dfa3d35 RS |
481 | (when (numberp line-idx) |
482 | (setq keyword | |
483 | (cons (list (1+ line-idx) 'font-lock-variable-name-face) | |
484 | keyword))) | |
485 | (when (numberp file-idx) | |
486 | (setq keyword | |
487 | (cons (list (1+ file-idx) 'font-lock-warning-face) | |
488 | keyword))) | |
489 | (cons (concat "^\\(" (nth 0 item) "\\)") keyword)))) | |
e93b2a55 SM |
490 | compilation-error-regexp-alist) |
491 | (list | |
492 | ;; | |
a24770bc | 493 | ;; Compiler output lines. Recognize `make[n]:' lines too. |
e93b2a55 SM |
494 | '("^\\([A-Za-z_0-9/\.+-]+\\)\\(\\[\\([0-9]+\\)\\]\\)?[ \t]*:" |
495 | (1 font-lock-function-name-face) (3 font-lock-comment-face nil t))) | |
496 | )) | |
01f89d11 | 497 | \f |
d3cb357b | 498 | ;;;###autoload |
55dfd2c4 RS |
499 | (defun compile (command) |
500 | "Compile the program including the current buffer. Default: run `make'. | |
501 | Runs COMMAND, a shell command, in a separate process asynchronously | |
502 | with output going to the buffer `*compilation*'. | |
d3cb357b | 503 | |
55dfd2c4 RS |
504 | You can then use the command \\[next-error] to find the next error message |
505 | and move to the source code that caused it. | |
506 | ||
08b1edf4 RM |
507 | Interactively, prompts for the command if `compilation-read-command' is |
508 | non-nil; otherwise uses `compile-command'. With prefix arg, always prompts. | |
509 | ||
55dfd2c4 | 510 | To run more than one compilation at once, start one and rename the |
d3cb357b RM |
511 | \`*compilation*' buffer to some other name with \\[rename-buffer]. |
512 | Then start the next one. | |
513 | ||
514 | The name used for the buffer is actually whatever is returned by | |
515 | the function in `compilation-buffer-name-function', so you can set that | |
516 | to a function that generates a unique name." | |
90016295 | 517 | (interactive |
08b1edf4 | 518 | (if (or compilation-read-command current-prefix-arg) |
90016295 RS |
519 | (list (read-from-minibuffer "Compile command: " |
520 | compile-command nil nil | |
521 | '(compile-history . 1))) | |
522 | (list compile-command))) | |
55dfd2c4 | 523 | (setq compile-command command) |
90016295 | 524 | (save-some-buffers (not compilation-ask-about-save) nil) |
d3cb357b | 525 | (compile-internal compile-command "No more errors")) |
55dfd2c4 | 526 | |
e60476ca RS |
527 | ;;; run compile with the default command line |
528 | (defun recompile () | |
529 | "Re-compile the program including the current buffer." | |
530 | (interactive) | |
531 | (save-some-buffers (not compilation-ask-about-save) nil) | |
532 | (compile-internal compile-command "No more errors")) | |
09843b4a | 533 | |
acffd065 EZ |
534 | (defun grep-process-setup () |
535 | "Set up `compilation-exit-message-function' for `grep'." | |
536 | (set (make-local-variable 'compilation-exit-message-function) | |
537 | (lambda (status code msg) | |
538 | (if (eq status 'exit) | |
539 | (cond ((zerop code) | |
540 | '("finished (matches found)\n" . "matched")) | |
541 | ((= code 1) | |
542 | '("finished with no matches found\n" . "no match")) | |
543 | (t | |
544 | (cons msg code))) | |
545 | (cons msg code))))) | |
546 | ||
d3cb357b | 547 | ;;;###autoload |
55dfd2c4 RS |
548 | (defun grep (command-args) |
549 | "Run grep, with user-specified args, and collect output in a buffer. | |
550 | While grep runs asynchronously, you can use the \\[next-error] command | |
d3cb357b RM |
551 | to find the text that grep hits refer to. |
552 | ||
770970cb RS |
553 | This command uses a special history list for its arguments, so you can |
554 | easily repeat a grep command." | |
55dfd2c4 | 555 | (interactive |
770970cb | 556 | (list (read-from-minibuffer "Run grep (like this): " |
98b63c41 | 557 | grep-command nil nil 'grep-history))) |
acffd065 EZ |
558 | ;; Setting process-setup-function makes exit-message-function work |
559 | ;; even when async processes aren't supported. | |
560 | (let* ((compilation-process-setup-function 'grep-process-setup) | |
201bf332 RS |
561 | (buf (compile-internal (if grep-null-device |
562 | (concat command-args " " grep-null-device) | |
563 | command-args) | |
acffd065 EZ |
564 | "No more grep hits" "grep" |
565 | ;; Give it a simpler regexp to match. | |
566 | nil grep-regexp-alist))))) | |
55dfd2c4 | 567 | |
201bf332 RS |
568 | |
569 | ;;;###autoload | |
570 | (defun grep-find (command-args) | |
571 | "Run grep via find, with user-specified args, and collect output in a buffer. | |
572 | While find runs asynchronously, you can use the \\[next-error] command | |
573 | to find the text that grep hits refer to. | |
574 | ||
575 | This command uses a special history list for its arguments, so you can | |
576 | easily repeat a find command." | |
577 | (interactive | |
578 | (list (read-from-minibuffer "Run find (like this): " | |
579 | grep-find-command nil nil 'grep-find-history))) | |
580 | (let ((grep-null-device nil)) ; see grep | |
581 | (grep command-args))) | |
582 | ||
55dfd2c4 | 583 | (defun compile-internal (command error-message |
a24770bc RS |
584 | &optional name-of-mode parser |
585 | error-regexp-alist name-function | |
586 | enter-regexp-alist leave-regexp-alist | |
587 | file-regexp-alist nomessage-regexp-alist) | |
55dfd2c4 RS |
588 | "Run compilation command COMMAND (low level interface). |
589 | ERROR-MESSAGE is a string to print if the user asks to see another error | |
a24770bc RS |
590 | and there are no more errors. The rest of the arguments, 3-10 are optional. |
591 | For them nil means use the default. | |
592 | NAME-OF-MODE is the name to display as the major mode in the compilation | |
593 | buffer. PARSER is the error parser function. ERROR-REGEXP-ALIST is the error | |
594 | message regexp alist to use. NAME-FUNCTION is a function called to name the | |
595 | buffer. ENTER-REGEXP-ALIST is the enter directory message regexp alist to use. | |
596 | LEAVE-REGEXP-ALIST is the leave directory message regexp alist to use. | |
597 | FILE-REGEXP-ALIST is the change current file message regexp alist to use. | |
598 | NOMESSAGE-REGEXP-ALIST is the nomessage regexp alist to use. | |
599 | The defaults for these variables are the global values of | |
600 | \`compilation-parse-errors-function', `compilation-error-regexp-alist', | |
601 | \`compilation-buffer-name-function', `compilation-enter-directory-regexp-alist', | |
602 | \`compilation-leave-directory-regexp-alist', `compilation-file-regexp-alist', | |
603 | \ and `compilation-nomessage-regexp-alist', respectively. | |
604 | For arg 7-10 a value `t' means an empty alist. | |
646bd331 RM |
605 | |
606 | Returns the compilation buffer created." | |
d3cb357b | 607 | (let (outbuf) |
55dfd2c4 | 608 | (save-excursion |
d3cb357b RM |
609 | (or name-of-mode |
610 | (setq name-of-mode "Compilation")) | |
611 | (setq outbuf | |
612 | (get-buffer-create | |
613 | (funcall (or name-function compilation-buffer-name-function | |
614 | (function (lambda (mode) | |
615 | (concat "*" (downcase mode) "*")))) | |
616 | name-of-mode))) | |
617 | (set-buffer outbuf) | |
618 | (let ((comp-proc (get-buffer-process (current-buffer)))) | |
619 | (if comp-proc | |
620 | (if (or (not (eq (process-status comp-proc) 'run)) | |
621 | (yes-or-no-p | |
bea1d57a JB |
622 | (format "A %s process is running; kill it? " |
623 | name-of-mode))) | |
d3cb357b RM |
624 | (condition-case () |
625 | (progn | |
626 | (interrupt-process comp-proc) | |
627 | (sit-for 1) | |
628 | (delete-process comp-proc)) | |
629 | (error nil)) | |
630 | (error "Cannot have two processes in `%s' at once" | |
631 | (buffer-name)) | |
632 | ))) | |
633 | ;; In case the compilation buffer is current, make sure we get the global | |
634 | ;; values of compilation-error-regexp-alist, etc. | |
635 | (kill-all-local-variables)) | |
a24770bc RS |
636 | (or error-regexp-alist |
637 | (setq error-regexp-alist compilation-error-regexp-alist)) | |
638 | (or enter-regexp-alist | |
639 | (setq enter-regexp-alist compilation-enter-directory-regexp-alist)) | |
640 | (or leave-regexp-alist | |
641 | (setq leave-regexp-alist compilation-leave-directory-regexp-alist)) | |
642 | (or file-regexp-alist | |
643 | (setq file-regexp-alist compilation-file-regexp-alist)) | |
644 | (or nomessage-regexp-alist | |
645 | (setq nomessage-regexp-alist compilation-nomessage-regexp-alist)) | |
646 | (or parser (setq parser compilation-parse-errors-function)) | |
647 | (let ((thisdir default-directory) | |
501cf428 | 648 | outwin) |
d3cb357b RM |
649 | (save-excursion |
650 | ;; Clear out the compilation buffer and make it writable. | |
651 | ;; Change its default-directory to the directory where the compilation | |
652 | ;; will happen, and insert a `cd' command to indicate this. | |
653 | (set-buffer outbuf) | |
654 | (setq buffer-read-only nil) | |
5d5ab7ac | 655 | (buffer-disable-undo (current-buffer)) |
d3cb357b | 656 | (erase-buffer) |
5d5ab7ac | 657 | (buffer-enable-undo (current-buffer)) |
d3cb357b RM |
658 | (setq default-directory thisdir) |
659 | (insert "cd " thisdir "\n" command "\n") | |
660 | (set-buffer-modified-p nil)) | |
661 | ;; If we're already in the compilation buffer, go to the end | |
662 | ;; of the buffer, so point will track the compilation output. | |
663 | (if (eq outbuf (current-buffer)) | |
664 | (goto-char (point-max))) | |
665 | ;; Pop up the compilation buffer. | |
666 | (setq outwin (display-buffer outbuf)) | |
d4ece679 RS |
667 | (save-excursion |
668 | (set-buffer outbuf) | |
669 | (compilation-mode) | |
a72ba929 | 670 | ;; (setq buffer-read-only t) ;;; Non-ergonomic. |
d4ece679 RS |
671 | (set (make-local-variable 'compilation-parse-errors-function) parser) |
672 | (set (make-local-variable 'compilation-error-message) error-message) | |
a24770bc RS |
673 | (set (make-local-variable 'compilation-error-regexp-alist) |
674 | error-regexp-alist) | |
675 | (set (make-local-variable 'compilation-enter-directory-regexp-alist) | |
676 | enter-regexp-alist) | |
677 | (set (make-local-variable 'compilation-leave-directory-regexp-alist) | |
678 | leave-regexp-alist) | |
679 | (set (make-local-variable 'compilation-file-regexp-alist) | |
680 | file-regexp-alist) | |
681 | (set (make-local-variable 'compilation-nomessage-regexp-alist) | |
682 | nomessage-regexp-alist) | |
58856335 RS |
683 | (set (make-local-variable 'compilation-arguments) |
684 | (list command error-message | |
685 | name-of-mode parser | |
686 | error-regexp-alist name-function | |
687 | enter-regexp-alist leave-regexp-alist | |
688 | file-regexp-alist nomessage-regexp-alist)) | |
d4ece679 RS |
689 | (setq default-directory thisdir |
690 | compilation-directory-stack (list default-directory)) | |
691 | (set-window-start outwin (point-min)) | |
692 | (setq mode-name name-of-mode) | |
693 | (or (eq outwin (selected-window)) | |
694 | (set-window-point outwin (point-min))) | |
c94b02d6 | 695 | (compilation-set-window-height outwin) |
49683a13 EZ |
696 | (if compilation-process-setup-function |
697 | (funcall compilation-process-setup-function)) | |
d4ece679 | 698 | ;; Start the compilation. |
35f7e85b | 699 | (if (fboundp 'start-process) |
2bb240a9 RS |
700 | (let* ((process-environment (cons "EMACS=t" process-environment)) |
701 | (proc (start-process-shell-command (downcase mode-name) | |
702 | outbuf | |
703 | command))) | |
35f7e85b RS |
704 | (set-process-sentinel proc 'compilation-sentinel) |
705 | (set-process-filter proc 'compilation-filter) | |
706 | (set-marker (process-mark proc) (point) outbuf) | |
501cf428 | 707 | (setq compilation-in-progress |
35f7e85b | 708 | (cons proc compilation-in-progress))) |
fd5e58d7 RM |
709 | ;; No asynchronous processes available. |
710 | (message "Executing `%s'..." command) | |
d3e56891 RS |
711 | ;; Fake modeline display as if `start-process' were run. |
712 | (setq mode-line-process ":run") | |
fd5e58d7 RM |
713 | (force-mode-line-update) |
714 | (sit-for 0) ; Force redisplay | |
35f7e85b | 715 | (let ((status (call-process shell-file-name nil outbuf nil "-c" |
fd5e58d7 RM |
716 | command))) |
717 | (cond ((numberp status) | |
718 | (compilation-handle-exit 'exit status | |
719 | (if (zerop status) | |
720 | "finished\n" | |
721 | (format "\ | |
722 | exited abnormally with code %d\n" | |
723 | status)))) | |
724 | ((stringp status) | |
725 | (compilation-handle-exit 'signal status | |
726 | (concat status "\n"))) | |
727 | (t | |
728 | (compilation-handle-exit 'bizarre status status)))) | |
729 | (message "Executing `%s'...done" command)))) | |
d3cb357b RM |
730 | ;; Make it so the next C-x ` will use this buffer. |
731 | (setq compilation-last-buffer outbuf))) | |
55dfd2c4 | 732 | |
c94b02d6 RS |
733 | ;; Set the height of WINDOW according to compilation-window-height. |
734 | (defun compilation-set-window-height (window) | |
735 | (and compilation-window-height | |
736 | (= (window-width window) (frame-width (window-frame window))) | |
737 | ;; If window is alone in its frame, aside from a minibuffer, | |
738 | ;; don't change its height. | |
739 | (not (eq window (frame-root-window (window-frame window)))) | |
8205cbfc RS |
740 | ;; This save-excursion prevents us from changing the current buffer, |
741 | ;; which might not be the same as the selected window's buffer. | |
742 | (save-excursion | |
743 | (let ((w (selected-window))) | |
744 | (unwind-protect | |
745 | (progn | |
746 | (select-window window) | |
747 | (enlarge-window (- compilation-window-height | |
748 | (window-height)))) | |
749 | (select-window w)))))) | |
c94b02d6 | 750 | |
0b18a8f6 | 751 | (defvar compilation-minor-mode-map |
55dfd2c4 | 752 | (let ((map (make-sparse-keymap))) |
f98494a4 | 753 | (define-key map [mouse-2] 'compile-mouse-goto-error) |
55dfd2c4 | 754 | (define-key map "\C-c\C-c" 'compile-goto-error) |
4e7ce12e | 755 | (define-key map "\C-m" 'compile-goto-error) |
d3cb357b | 756 | (define-key map "\C-c\C-k" 'kill-compilation) |
646bd331 RM |
757 | (define-key map "\M-n" 'compilation-next-error) |
758 | (define-key map "\M-p" 'compilation-previous-error) | |
d1ed4475 RM |
759 | (define-key map "\M-{" 'compilation-previous-file) |
760 | (define-key map "\M-}" 'compilation-next-file) | |
55dfd2c4 | 761 | map) |
4f6e4ad6 | 762 | "Keymap for `compilation-minor-mode'.") |
0b18a8f6 | 763 | |
a24770bc RS |
764 | (defvar compilation-shell-minor-mode-map |
765 | (let ((map (make-sparse-keymap))) | |
766 | (define-key map [mouse-2] 'compile-mouse-goto-error) | |
767 | (define-key map "\M-\C-m" 'compile-goto-error) | |
768 | (define-key map "\M-\C-n" 'compilation-next-error) | |
769 | (define-key map "\M-\C-p" 'compilation-previous-error) | |
770 | (define-key map "\M-{" 'compilation-previous-file) | |
771 | (define-key map "\M-}" 'compilation-next-file) | |
772 | ;; Set up the menu-bar | |
773 | (define-key map [menu-bar errors-menu] | |
774 | (cons "Errors" (make-sparse-keymap "Errors"))) | |
775 | (define-key map [menu-bar errors-menu stop-subjob] | |
776 | '("Stop" . comint-interrupt-subjob)) | |
777 | (define-key map [menu-bar errors-menu compilation-mode-separator2] | |
778 | '("----" . nil)) | |
779 | (define-key map [menu-bar errors-menu compilation-mode-first-error] | |
780 | '("First Error" . first-error)) | |
781 | (define-key map [menu-bar errors-menu compilation-mode-previous-error] | |
782 | '("Previous Error" . previous-error)) | |
783 | (define-key map [menu-bar errors-menu compilation-mode-next-error] | |
784 | '("Next Error" . next-error)) | |
785 | map) | |
786 | "Keymap for `compilation-shell-minor-mode'.") | |
787 | ||
0b18a8f6 RM |
788 | (defvar compilation-mode-map |
789 | (let ((map (cons 'keymap compilation-minor-mode-map))) | |
790 | (define-key map " " 'scroll-up) | |
791 | (define-key map "\^?" 'scroll-down) | |
e60476ca RS |
792 | ;; Set up the menu-bar |
793 | (define-key map [menu-bar compilation-menu] | |
794 | (cons "Compile" (make-sparse-keymap "Compile"))) | |
795 | ||
796 | (define-key map [menu-bar compilation-menu compilation-mode-kill-compilation] | |
0949ba2b | 797 | '("Stop Compilation" . kill-compilation)) |
e60476ca RS |
798 | (define-key map [menu-bar compilation-menu compilation-mode-separator2] |
799 | '("----" . nil)) | |
800 | (define-key map [menu-bar compilation-menu compilation-mode-first-error] | |
0949ba2b | 801 | '("First Error" . first-error)) |
e60476ca | 802 | (define-key map [menu-bar compilation-menu compilation-mode-previous-error] |
0949ba2b | 803 | '("Previous Error" . previous-error)) |
e60476ca | 804 | (define-key map [menu-bar compilation-menu compilation-mode-next-error] |
0949ba2b | 805 | '("Next Error" . next-error)) |
e60476ca RS |
806 | (define-key map [menu-bar compilation-menu compilation-separator2] |
807 | '("----" . nil)) | |
808 | (define-key map [menu-bar compilation-menu compilation-mode-grep] | |
7933678b | 809 | '("Search Files (grep)" . grep)) |
e60476ca RS |
810 | (define-key map [menu-bar compilation-menu compilation-mode-recompile] |
811 | '("Recompile" . recompile)) | |
812 | (define-key map [menu-bar compilation-menu compilation-mode-compile] | |
32f4ab17 | 813 | '("Compile..." . compile)) |
0b18a8f6 RM |
814 | map) |
815 | "Keymap for compilation log buffers. | |
4f6e4ad6 | 816 | `compilation-minor-mode-map' is a cdr of this.") |
55dfd2c4 | 817 | |
0a35bd79 RS |
818 | (put 'compilation-mode 'mode-class 'special) |
819 | ||
501cf428 | 820 | ;;;###autoload |
55dfd2c4 RS |
821 | (defun compilation-mode () |
822 | "Major mode for compilation log buffers. | |
823 | \\<compilation-mode-map>To visit the source for a line-numbered error, | |
d3cb357b | 824 | move point to the error message line and type \\[compile-goto-error]. |
7c163413 RM |
825 | To kill the compilation, type \\[kill-compilation]. |
826 | ||
827 | Runs `compilation-mode-hook' with `run-hooks' (which see)." | |
55dfd2c4 | 828 | (interactive) |
9af0d309 | 829 | (kill-all-local-variables) |
55dfd2c4 | 830 | (use-local-map compilation-mode-map) |
0b18a8f6 RM |
831 | (setq major-mode 'compilation-mode |
832 | mode-name "Compilation") | |
833 | (compilation-setup) | |
63a2daf6 SM |
834 | (set (make-local-variable 'font-lock-defaults) |
835 | '(compilation-mode-font-lock-keywords t)) | |
58856335 RS |
836 | (set (make-local-variable 'revert-buffer-function) |
837 | 'compilation-revert-buffer) | |
0b18a8f6 RM |
838 | (run-hooks 'compilation-mode-hook)) |
839 | ||
58856335 RS |
840 | (defun compilation-revert-buffer (ignore-auto noconfirm) |
841 | (if (or noconfirm (yes-or-no-p (format "Restart compilation? "))) | |
842 | (apply 'compile-internal compilation-arguments))) | |
843 | ||
0b18a8f6 RM |
844 | ;; Prepare the buffer for the compilation parsing commands to work. |
845 | (defun compilation-setup () | |
846 | ;; Make the buffer's mode line show process state. | |
ebf0b439 | 847 | (setq mode-line-process '(":%s")) |
d3cb357b RM |
848 | (set (make-local-variable 'compilation-error-list) nil) |
849 | (set (make-local-variable 'compilation-old-error-list) nil) | |
850 | (set (make-local-variable 'compilation-parsing-end) 1) | |
851 | (set (make-local-variable 'compilation-directory-stack) nil) | |
0b18a8f6 RM |
852 | (setq compilation-last-buffer (current-buffer))) |
853 | ||
a24770bc RS |
854 | (defvar compilation-shell-minor-mode nil |
855 | "Non-nil when in compilation-shell-minor-mode. | |
856 | In this minor mode, all the error-parsing commands of the | |
857 | Compilation major mode are available but bound to keys that don't | |
858 | collide with Shell mode.") | |
859 | (make-variable-buffer-local 'compilation-shell-minor-mode) | |
860 | ||
861 | (or (assq 'compilation-shell-minor-mode minor-mode-alist) | |
862 | (setq minor-mode-alist | |
863 | (cons '(compilation-shell-minor-mode " Shell-Compile") | |
864 | minor-mode-alist))) | |
865 | (or (assq 'compilation-shell-minor-mode minor-mode-map-alist) | |
866 | (setq minor-mode-map-alist (cons (cons 'compilation-shell-minor-mode | |
867 | compilation-shell-minor-mode-map) | |
868 | minor-mode-map-alist))) | |
869 | ||
0b18a8f6 RM |
870 | (defvar compilation-minor-mode nil |
871 | "Non-nil when in compilation-minor-mode. | |
872 | In this minor mode, all the error-parsing commands of the | |
873 | Compilation major mode are available.") | |
d6bd8dca | 874 | (make-variable-buffer-local 'compilation-minor-mode) |
0b18a8f6 RM |
875 | |
876 | (or (assq 'compilation-minor-mode minor-mode-alist) | |
877 | (setq minor-mode-alist (cons '(compilation-minor-mode " Compilation") | |
878 | minor-mode-alist))) | |
879 | (or (assq 'compilation-minor-mode minor-mode-map-alist) | |
4f6e4ad6 RS |
880 | (setq minor-mode-map-alist (cons (cons 'compilation-minor-mode |
881 | compilation-minor-mode-map) | |
0b18a8f6 RM |
882 | minor-mode-map-alist))) |
883 | ||
d6bd8dca | 884 | ;;;###autoload |
0b18a8f6 RM |
885 | (defun compilation-minor-mode (&optional arg) |
886 | "Toggle compilation minor mode. | |
887 | With arg, turn compilation mode on if and only if arg is positive. | |
fee3f63a RM |
888 | See `compilation-mode'. |
889 | Turning the mode on runs the normal hook `compilation-minor-mode-hook'." | |
0b18a8f6 RM |
890 | (interactive "P") |
891 | (if (setq compilation-minor-mode (if (null arg) | |
892 | (null compilation-minor-mode) | |
893 | (> (prefix-numeric-value arg) 0))) | |
fee3f63a RM |
894 | (progn |
895 | (compilation-setup) | |
b90a00f2 | 896 | (run-hooks 'compilation-minor-mode-hook)))) |
55dfd2c4 | 897 | |
fd5e58d7 RM |
898 | ;; Write msg in the current buffer and hack its mode-line-process. |
899 | (defun compilation-handle-exit (process-status exit-status msg) | |
900 | (let ((buffer-read-only nil) | |
901 | (status (if compilation-exit-message-function | |
902 | (funcall compilation-exit-message-function | |
903 | process-status exit-status msg) | |
904 | (cons msg exit-status))) | |
905 | (omax (point-max)) | |
906 | (opoint (point))) | |
907 | ;; Record where we put the message, so we can ignore it | |
908 | ;; later on. | |
909 | (goto-char omax) | |
910 | (insert ?\n mode-name " " (car status)) | |
911 | (forward-char -1) | |
912 | (insert " at " (substring (current-time-string) 0 19)) | |
913 | (forward-char 1) | |
52f84622 | 914 | (setq mode-line-process (format ":%s [%s]" process-status (cdr status))) |
fd5e58d7 RM |
915 | ;; Force mode line redisplay soon. |
916 | (force-mode-line-update) | |
917 | (if (and opoint (< opoint omax)) | |
918 | (goto-char opoint)) | |
01e6e8c9 RS |
919 | ;; Automatically parse (and mouse-highlight) error messages: |
920 | (cond ((eq compile-auto-highlight t) | |
37f5f978 | 921 | (compile-reinitialize-errors nil (point-max))) |
01e6e8c9 RS |
922 | ((numberp compile-auto-highlight) |
923 | (compile-reinitialize-errors nil | |
924 | (save-excursion | |
925 | (goto-line compile-auto-highlight) | |
926 | (point))))) | |
fd5e58d7 | 927 | (if compilation-finish-function |
4cc36b17 RS |
928 | (funcall compilation-finish-function (current-buffer) msg)) |
929 | (let ((functions compilation-finish-functions)) | |
930 | (while functions | |
931 | (funcall (car functions) (current-buffer) msg) | |
932 | (setq functions (cdr functions)))))) | |
fd5e58d7 | 933 | |
55dfd2c4 | 934 | ;; Called when compilation process changes state. |
55dfd2c4 | 935 | (defun compilation-sentinel (proc msg) |
d3cb357b RM |
936 | "Sentinel for compilation buffers." |
937 | (let ((buffer (process-buffer proc))) | |
ebff767c RM |
938 | (if (memq (process-status proc) '(signal exit)) |
939 | (progn | |
940 | (if (null (buffer-name buffer)) | |
941 | ;; buffer killed | |
942 | (set-process-buffer proc nil) | |
fd5e58d7 | 943 | (let ((obuf (current-buffer))) |
ebff767c RM |
944 | ;; save-excursion isn't the right thing if |
945 | ;; process-buffer is current-buffer | |
946 | (unwind-protect | |
947 | (progn | |
948 | ;; Write something in the compilation buffer | |
949 | ;; and hack its mode line. | |
950 | (set-buffer buffer) | |
fd5e58d7 RM |
951 | (compilation-handle-exit (process-status proc) |
952 | (process-exit-status proc) | |
953 | msg) | |
954 | ;; Since the buffer and mode line will show that the | |
955 | ;; process is dead, we can delete it now. Otherwise it | |
956 | ;; will stay around until M-x list-processes. | |
957 | (delete-process proc)) | |
6c43f2f9 | 958 | (set-buffer obuf)))) |
ebff767c RM |
959 | (setq compilation-in-progress (delq proc compilation-in-progress)) |
960 | )))) | |
55dfd2c4 | 961 | |
ad62b7f1 RM |
962 | (defun compilation-filter (proc string) |
963 | "Process filter for compilation buffers. | |
4f6e4ad6 | 964 | Just inserts the text, but uses `insert-before-markers'." |
991c70f8 | 965 | (if (buffer-name (process-buffer proc)) |
ad62b7f1 | 966 | (save-excursion |
991c70f8 RS |
967 | (set-buffer (process-buffer proc)) |
968 | (let ((buffer-read-only nil)) | |
969 | (save-excursion | |
970 | (goto-char (process-mark proc)) | |
971 | (insert-before-markers string) | |
d89793b7 | 972 | (run-hooks 'compilation-filter-hook) |
991c70f8 | 973 | (set-marker (process-mark proc) (point))))))) |
ad62b7f1 | 974 | |
b5bb472e RM |
975 | ;; Return the cdr of compilation-old-error-list for the error containing point. |
976 | (defun compile-error-at-point () | |
977 | (compile-reinitialize-errors nil (point)) | |
978 | (let ((errors compilation-old-error-list)) | |
979 | (while (and errors | |
980 | (> (point) (car (car errors)))) | |
981 | (setq errors (cdr errors))) | |
982 | errors)) | |
983 | ||
51ba27e7 | 984 | (defsubst compilation-buffer-p (buffer) |
20c1daec RM |
985 | (save-excursion |
986 | (set-buffer buffer) | |
a24770bc RS |
987 | (or compilation-shell-minor-mode compilation-minor-mode |
988 | (eq major-mode 'compilation-mode)))) | |
51ba27e7 | 989 | |
646bd331 RM |
990 | (defun compilation-next-error (n) |
991 | "Move point to the next error in the compilation buffer. | |
992 | Does NOT find the source line like \\[next-error]." | |
993 | (interactive "p") | |
994 | (or (compilation-buffer-p (current-buffer)) | |
995 | (error "Not in a compilation buffer.")) | |
996 | (setq compilation-last-buffer (current-buffer)) | |
b5bb472e RM |
997 | |
998 | (let ((errors (compile-error-at-point))) | |
999 | ||
1000 | ;; Move to the error after the one containing point. | |
1001 | (goto-char (car (if (< n 0) | |
1002 | (let ((i 0) | |
1003 | (e compilation-old-error-list)) | |
1004 | ;; See how many cdrs away ERRORS is from the start. | |
1005 | (while (not (eq e errors)) | |
1006 | (setq i (1+ i) | |
1007 | e (cdr e))) | |
1008 | (if (> (- n) i) | |
1009 | (error "Moved back past first error") | |
1010 | (nth (+ i n) compilation-old-error-list))) | |
1011 | (let ((compilation-error-list (cdr errors))) | |
1012 | (compile-reinitialize-errors nil nil n) | |
1013 | (if compilation-error-list | |
1014 | (nth (1- n) compilation-error-list) | |
1015 | (error "Moved past last error")))))))) | |
646bd331 RM |
1016 | |
1017 | (defun compilation-previous-error (n) | |
1018 | "Move point to the previous error in the compilation buffer. | |
1019 | Does NOT find the source line like \\[next-error]." | |
1020 | (interactive "p") | |
1021 | (compilation-next-error (- n))) | |
1022 | ||
1023 | ||
fc0094d7 RM |
1024 | ;; Given an elt of `compilation-error-list', return an object representing |
1025 | ;; the referenced file which is equal to (but not necessarily eq to) what | |
1026 | ;; this function would return for another error in the same file. | |
1027 | (defsubst compilation-error-filedata (data) | |
b5bb472e RM |
1028 | (setq data (cdr data)) |
1029 | (if (markerp data) | |
fc0094d7 | 1030 | (marker-buffer data) |
aead2f9f | 1031 | (car data))) |
b5bb472e | 1032 | |
fc0094d7 RM |
1033 | ;; Return a string describing a value from compilation-error-filedata. |
1034 | ;; This value is not necessarily useful as a file name, but should be | |
1035 | ;; indicative to the user of what file's errors are being referred to. | |
1036 | (defsubst compilation-error-filedata-file-name (filedata) | |
1037 | (if (bufferp filedata) | |
1038 | (buffer-file-name filedata) | |
1039 | (car filedata))) | |
1040 | ||
b5bb472e RM |
1041 | (defun compilation-next-file (n) |
1042 | "Move point to the next error for a different file than the current one." | |
1043 | (interactive "p") | |
1044 | (or (compilation-buffer-p (current-buffer)) | |
1045 | (error "Not in a compilation buffer.")) | |
1046 | (setq compilation-last-buffer (current-buffer)) | |
1047 | ||
1048 | (let ((reversed (< n 0)) | |
fc0094d7 | 1049 | errors filedata) |
b5bb472e RM |
1050 | |
1051 | (if (not reversed) | |
1052 | (setq errors (or (compile-error-at-point) | |
1053 | (error "Moved past last error"))) | |
1054 | ||
1055 | ;; Get a reversed list of the errors up through the one containing point. | |
1056 | (compile-reinitialize-errors nil (point)) | |
1057 | (setq errors (reverse compilation-old-error-list) | |
1058 | n (- n)) | |
1059 | ||
1060 | ;; Ignore errors after point. (car ERRORS) will be the error | |
1061 | ;; containing point, (cadr ERRORS) the one before it. | |
1062 | (while (and errors | |
1063 | (< (point) (car (car errors)))) | |
1064 | (setq errors (cdr errors)))) | |
1065 | ||
1066 | (while (> n 0) | |
fc0094d7 RM |
1067 | (setq filedata (compilation-error-filedata (car errors))) |
1068 | ||
1069 | ;; Skip past the following errors for this file. | |
1070 | (while (equal filedata | |
1071 | (compilation-error-filedata | |
1072 | (car (or errors | |
1073 | (if reversed | |
1074 | (error "%s the first erring file" | |
1075 | (compilation-error-filedata-file-name | |
1076 | filedata)) | |
1077 | (let ((compilation-error-list nil)) | |
1078 | ;; Parse some more. | |
1079 | (compile-reinitialize-errors nil nil 2) | |
1080 | (setq errors compilation-error-list))) | |
501cf428 | 1081 | (error "%s is the last erring file" |
fc0094d7 RM |
1082 | (compilation-error-filedata-file-name |
1083 | filedata)))))) | |
b5bb472e RM |
1084 | (setq errors (cdr errors))) |
1085 | ||
1086 | (setq n (1- n))) | |
1087 | ||
1088 | ;; Move to the following error. | |
1089 | (goto-char (car (car (or errors | |
1090 | (if reversed | |
1091 | (error "This is the first erring file") | |
1092 | (let ((compilation-error-list nil)) | |
1093 | ;; Parse the last one. | |
1094 | (compile-reinitialize-errors nil nil 1) | |
1095 | compilation-error-list)))))))) | |
1096 | ||
1097 | (defun compilation-previous-file (n) | |
1098 | "Move point to the previous error for a different file than the current one." | |
1099 | (interactive "p") | |
1100 | (compilation-next-file (- n))) | |
1101 | ||
1102 | ||
55dfd2c4 RS |
1103 | (defun kill-compilation () |
1104 | "Kill the process made by the \\[compile] command." | |
1105 | (interactive) | |
d3cb357b | 1106 | (let ((buffer (compilation-find-buffer))) |
55dfd2c4 | 1107 | (if (get-buffer-process buffer) |
d3cb357b RM |
1108 | (interrupt-process (get-buffer-process buffer)) |
1109 | (error "The compilation process is not running.")))) | |
1110 | ||
55dfd2c4 | 1111 | |
d3cb357b RM |
1112 | ;; Parse any new errors in the compilation buffer, |
1113 | ;; or reparse from the beginning if the user has asked for that. | |
eaa3cac5 RM |
1114 | (defun compile-reinitialize-errors (reparse |
1115 | &optional limit-search find-at-least) | |
d3cb357b RM |
1116 | (save-excursion |
1117 | (set-buffer compilation-last-buffer) | |
1118 | ;; If we are out of errors, or if user says "reparse", | |
1119 | ;; discard the info we have, to force reparsing. | |
1120 | (if (or (eq compilation-error-list t) | |
eaa3cac5 | 1121 | reparse) |
51ba27e7 | 1122 | (compilation-forget-errors)) |
c540863c | 1123 | (if (and compilation-error-list |
b5bb472e RM |
1124 | (or (not limit-search) |
1125 | (> compilation-parsing-end limit-search)) | |
c540863c | 1126 | (or (not find-at-least) |
a72ba929 | 1127 | (>= (length compilation-error-list) find-at-least))) |
d3cb357b RM |
1128 | ;; Since compilation-error-list is non-nil, it points to a specific |
1129 | ;; error the user wanted. So don't move it around. | |
1130 | nil | |
51ba27e7 RM |
1131 | ;; This was here for a long time (before my rewrite); why? --roland |
1132 | ;;(switch-to-buffer compilation-last-buffer) | |
55dfd2c4 | 1133 | (set-buffer-modified-p nil) |
b5bb472e | 1134 | (if (< compilation-parsing-end (point-max)) |
51ba27e7 | 1135 | ;; compilation-error-list might be non-nil if we have a non-nil |
676a14e1 | 1136 | ;; LIMIT-SEARCH or FIND-AT-LEAST arg. In that case its value |
51ba27e7 RM |
1137 | ;; records the current position in the error list, and we must |
1138 | ;; preserve that after reparsing. | |
1139 | (let ((error-list-pos compilation-error-list)) | |
b5bb472e | 1140 | (funcall compilation-parse-errors-function |
51ba27e7 RM |
1141 | limit-search |
1142 | (and find-at-least | |
1143 | ;; We only need enough new parsed errors to reach | |
1144 | ;; FIND-AT-LEAST errors past the current | |
1145 | ;; position. | |
1146 | (- find-at-least (length compilation-error-list)))) | |
1147 | ;; Remember the entire list for compilation-forget-errors. If | |
1148 | ;; this is an incremental parse, append to previous list. If | |
1149 | ;; we are parsing anew, compilation-forget-errors cleared | |
1150 | ;; compilation-old-error-list above. | |
1151 | (setq compilation-old-error-list | |
1152 | (nconc compilation-old-error-list compilation-error-list)) | |
1153 | (if error-list-pos | |
1154 | ;; We started in the middle of an existing list of parsed | |
1155 | ;; errors before parsing more; restore that position. | |
1156 | (setq compilation-error-list error-list-pos)) | |
01e6e8c9 | 1157 | ;; Mouse-Highlight (the first line of) each error message when the |
37f5f978 RS |
1158 | ;; mouse pointer moves over it: |
1159 | (let ((inhibit-read-only t) | |
1160 | (error-list compilation-error-list)) | |
1161 | (while error-list | |
1162 | (save-excursion | |
1163 | (put-text-property (goto-char (car (car error-list))) | |
1164 | (progn (end-of-line) (point)) | |
1165 | 'mouse-face 'highlight)) | |
1166 | (setq error-list (cdr error-list)))) | |
b5bb472e | 1167 | ))))) |
55dfd2c4 | 1168 | |
f98494a4 RS |
1169 | (defun compile-mouse-goto-error (event) |
1170 | (interactive "e") | |
e78e10ca KH |
1171 | (save-excursion |
1172 | (set-buffer (window-buffer (posn-window (event-end event)))) | |
1173 | (goto-char (posn-point (event-end event))) | |
1174 | ||
1175 | (or (compilation-buffer-p (current-buffer)) | |
1176 | (error "Not in a compilation buffer.")) | |
1177 | (setq compilation-last-buffer (current-buffer)) | |
167d1418 EZ |
1178 | ;; `compile-reinitialize-errors' needs to see the complete filename |
1179 | ;; on the line where they clicked the mouse. Since it only looks | |
a24770bc | 1180 | ;; up to point, moving point to eol makes sure the filename is |
167d1418 EZ |
1181 | ;; visible to `compile-reinitialize-errors'. |
1182 | (end-of-line) | |
e78e10ca KH |
1183 | (compile-reinitialize-errors nil (point)) |
1184 | ||
1185 | ;; Move to bol; the marker for the error on this line will point there. | |
1186 | (beginning-of-line) | |
1187 | ||
1188 | ;; Move compilation-error-list to the elt of compilation-old-error-list | |
1189 | ;; we want. | |
1190 | (setq compilation-error-list compilation-old-error-list) | |
1191 | (while (and compilation-error-list | |
1192 | (> (point) (car (car compilation-error-list)))) | |
1193 | (setq compilation-error-list (cdr compilation-error-list))) | |
1194 | (or compilation-error-list | |
1195 | (error "No error to go to"))) | |
1196 | (select-window (posn-window (event-end event))) | |
1197 | ;; Move to another window, so that next-error's window changes | |
1198 | ;; result in the desired setup. | |
1199 | (or (one-window-p) | |
1200 | (progn | |
1201 | (other-window -1) | |
1202 | ;; other-window changed the selected buffer, | |
1203 | ;; but we didn't want to do that. | |
1204 | (set-buffer compilation-last-buffer))) | |
1205 | ||
1206 | (push-mark) | |
1207 | (next-error 1)) | |
f98494a4 | 1208 | |
55dfd2c4 RS |
1209 | (defun compile-goto-error (&optional argp) |
1210 | "Visit the source for the error message point is on. | |
31efa7c9 | 1211 | Use this command in a compilation log buffer. Sets the mark at point there. |
b2bb6ec8 | 1212 | \\[universal-argument] as a prefix arg means to reparse the buffer's error messages first; |
55dfd2c4 RS |
1213 | other kinds of prefix arguments are ignored." |
1214 | (interactive "P") | |
d3cb357b RM |
1215 | (or (compilation-buffer-p (current-buffer)) |
1216 | (error "Not in a compilation buffer.")) | |
1217 | (setq compilation-last-buffer (current-buffer)) | |
eaa3cac5 | 1218 | (compile-reinitialize-errors (consp argp) (point)) |
646bd331 | 1219 | |
15d1a8da RM |
1220 | ;; Move to bol; the marker for the error on this line will point there. |
1221 | (beginning-of-line) | |
1222 | ||
646bd331 | 1223 | ;; Move compilation-error-list to the elt of compilation-old-error-list |
643f763f | 1224 | ;; we want. |
646bd331 | 1225 | (setq compilation-error-list compilation-old-error-list) |
643f763f RM |
1226 | (while (and compilation-error-list |
1227 | (> (point) (car (car compilation-error-list)))) | |
646bd331 RM |
1228 | (setq compilation-error-list (cdr compilation-error-list))) |
1229 | ||
55dfd2c4 RS |
1230 | ;; Move to another window, so that next-error's window changes |
1231 | ;; result in the desired setup. | |
1232 | (or (one-window-p) | |
646bd331 RM |
1233 | (progn |
1234 | (other-window -1) | |
1235 | ;; other-window changed the selected buffer, | |
1236 | ;; but we didn't want to do that. | |
1237 | (set-buffer compilation-last-buffer))) | |
1238 | ||
31efa7c9 | 1239 | (push-mark) |
643f763f | 1240 | (next-error 1)) |
55dfd2c4 | 1241 | |
d3cb357b RM |
1242 | ;; Return a compilation buffer. |
1243 | ;; If the current buffer is a compilation buffer, return it. | |
1244 | ;; If compilation-last-buffer is set to a live buffer, use that. | |
1245 | ;; Otherwise, look for a compilation buffer and signal an error | |
1246 | ;; if there are none. | |
4746118a JB |
1247 | (defun compilation-find-buffer (&optional other-buffer) |
1248 | (if (and (not other-buffer) | |
1249 | (compilation-buffer-p (current-buffer))) | |
d3cb357b RM |
1250 | ;; The current buffer is a compilation buffer. |
1251 | (current-buffer) | |
4746118a | 1252 | (if (and compilation-last-buffer (buffer-name compilation-last-buffer) |
95d219b5 | 1253 | (compilation-buffer-p compilation-last-buffer) |
4746118a JB |
1254 | (or (not other-buffer) (not (eq compilation-last-buffer |
1255 | (current-buffer))))) | |
d3cb357b RM |
1256 | compilation-last-buffer |
1257 | (let ((buffers (buffer-list))) | |
4746118a JB |
1258 | (while (and buffers (or (not (compilation-buffer-p (car buffers))) |
1259 | (and other-buffer | |
1260 | (eq (car buffers) (current-buffer))))) | |
d3cb357b RM |
1261 | (setq buffers (cdr buffers))) |
1262 | (if buffers | |
1263 | (car buffers) | |
4746118a JB |
1264 | (or (and other-buffer |
1265 | (compilation-buffer-p (current-buffer)) | |
1266 | ;; The current buffer is a compilation buffer. | |
1267 | (progn | |
1268 | (if other-buffer | |
1269 | (message "This is the only compilation buffer.")) | |
1270 | (current-buffer))) | |
1271 | (error "No compilation started!"))))))) | |
d3cb357b RM |
1272 | |
1273 | ;;;###autoload | |
55dfd2c4 RS |
1274 | (defun next-error (&optional argp) |
1275 | "Visit next compilation error message and corresponding source code. | |
1276 | This operates on the output from the \\[compile] command. | |
1277 | If all preparsed error messages have been processed, | |
1278 | the error message buffer is checked for new ones. | |
1279 | ||
1280 | A prefix arg specifies how many error messages to move; | |
1281 | negative means move back to previous error messages. | |
1282 | Just C-u as a prefix means reparse the error message buffer | |
1283 | and start at the first error. | |
1284 | ||
1285 | \\[next-error] normally applies to the most recent compilation started, | |
1286 | but as long as you are in the middle of parsing errors from one compilation | |
1287 | output buffer, you stay with that compilation output buffer. | |
1288 | ||
1289 | Use \\[next-error] in a compilation output buffer to switch to | |
1290 | processing errors from that compilation. | |
1291 | ||
d3cb357b RM |
1292 | See variables `compilation-parse-errors-function' and |
1293 | \`compilation-error-regexp-alist' for customization ideas." | |
55dfd2c4 | 1294 | (interactive "P") |
d3cb357b | 1295 | (setq compilation-last-buffer (compilation-find-buffer)) |
eaa3cac5 RM |
1296 | (compilation-goto-locus (compilation-next-error-locus |
1297 | ;; We want to pass a number here only if | |
1298 | ;; we got a numeric prefix arg, not just C-u. | |
1299 | (and (not (consp argp)) | |
1300 | (prefix-numeric-value argp)) | |
1301 | (consp argp)))) | |
1302 | ;;;###autoload (define-key ctl-x-map "`" 'next-error) | |
1303 | ||
e60476ca RS |
1304 | (defun previous-error () |
1305 | "Visit previous compilation error message and corresponding source code. | |
1306 | This operates on the output from the \\[compile] command." | |
1307 | (interactive) | |
eae2c972 | 1308 | (next-error -1)) |
e60476ca RS |
1309 | |
1310 | (defun first-error () | |
d9b73ccc | 1311 | "Reparse the error message buffer and start at the first error. |
e60476ca RS |
1312 | Visit corresponding source code. |
1313 | This operates on the output from the \\[compile] command." | |
1314 | (interactive) | |
eae2c972 | 1315 | (next-error '(4))) |
e60476ca | 1316 | |
c41fe446 KH |
1317 | (defvar compilation-skip-to-next-location nil |
1318 | "*If non-nil, skip multiple error messages for the same source location.") | |
1319 | ||
b4300a1a | 1320 | (defun compilation-next-error-locus (&optional move reparse silent) |
eaa3cac5 RM |
1321 | "Visit next compilation error and return locus in corresponding source code. |
1322 | This operates on the output from the \\[compile] command. | |
1323 | If all preparsed error messages have been processed, | |
1324 | the error message buffer is checked for new ones. | |
1325 | ||
1326 | Returns a cons (ERROR . SOURCE) of two markers: ERROR is a marker at the | |
1327 | location of the error message in the compilation buffer, and SOURCE is a | |
1328 | marker at the location in the source code indicated by the error message. | |
1329 | ||
1330 | Optional first arg MOVE says how many error messages to move forwards (or | |
1331 | backwards, if negative); default is 1. Optional second arg REPARSE, if | |
1332 | non-nil, says to reparse the error message buffer and reset to the first | |
501cf428 | 1333 | error (plus MOVE - 1). If optional third argument SILENT is non-nil, return |
b4300a1a | 1334 | nil instead of raising an error if there are no more errors. |
eaa3cac5 RM |
1335 | |
1336 | The current buffer should be the desired compilation output buffer." | |
1337 | (or move (setq move 1)) | |
1338 | (compile-reinitialize-errors reparse nil (and (not reparse) | |
1339 | (if (< move 1) 0 (1- move)))) | |
d3cb357b | 1340 | (let (next-errors next-error) |
7fb63acd RS |
1341 | (catch 'no-next-error |
1342 | (save-excursion | |
1343 | (set-buffer compilation-last-buffer) | |
1344 | ;; compilation-error-list points to the "current" error. | |
501cf428 | 1345 | (setq next-errors |
7fb63acd RS |
1346 | (if (> move 0) |
1347 | (nthcdr (1- move) | |
1348 | compilation-error-list) | |
1349 | ;; Zero or negative arg; we need to move back in the list. | |
1350 | (let ((n (1- move)) | |
1351 | (i 0) | |
1352 | (e compilation-old-error-list)) | |
1353 | ;; See how many cdrs away the current error is from the start. | |
1354 | (while (not (eq e compilation-error-list)) | |
1355 | (setq i (1+ i) | |
1356 | e (cdr e))) | |
1357 | (if (> (- n) i) | |
1358 | (error "Moved back past first error") | |
1359 | (nthcdr (+ i n) compilation-old-error-list)))) | |
1360 | next-error (car next-errors)) | |
1361 | (while | |
1362 | (if (null next-error) | |
1363 | (progn | |
1364 | (and move (/= move 1) | |
1365 | (error (if (> move 0) | |
1366 | "Moved past last error") | |
1367 | "Moved back past first error")) | |
1368 | ;; Forget existing error messages if compilation has finished. | |
1369 | (if (not (and (get-buffer-process (current-buffer)) | |
1370 | (eq (process-status | |
1371 | (get-buffer-process | |
1372 | (current-buffer))) | |
1373 | 'run))) | |
1374 | (compilation-forget-errors)) | |
1375 | (if silent | |
1376 | (throw 'no-next-error nil) | |
1377 | (error (concat compilation-error-message | |
1378 | (and (get-buffer-process (current-buffer)) | |
1379 | (eq (process-status | |
1380 | (get-buffer-process | |
1381 | (current-buffer))) | |
1382 | 'run) | |
b4300a1a | 1383 | " yet"))))) |
7fb63acd RS |
1384 | (setq compilation-error-list (cdr next-errors)) |
1385 | (if (null (cdr next-error)) | |
1386 | ;; This error is boring. Go to the next. | |
1387 | t | |
1388 | (or (markerp (cdr next-error)) | |
1389 | ;; This error has a filename/lineno pair. | |
1390 | ;; Find the file and turn it into a marker. | |
1391 | (let* ((fileinfo (car (cdr next-error))) | |
20c1daec RM |
1392 | (buffer (apply 'compilation-find-file |
1393 | (car next-error) fileinfo))) | |
7fb63acd RS |
1394 | (if (null buffer) |
1395 | ;; We can't find this error's file. | |
1396 | ;; Remove all errors in the same file. | |
1397 | (progn | |
1398 | (setq next-errors compilation-old-error-list) | |
1399 | (while next-errors | |
1400 | (and (consp (cdr (car next-errors))) | |
1401 | (equal (car (cdr (car next-errors))) | |
1402 | fileinfo) | |
1403 | (progn | |
1404 | (set-marker (car (car next-errors)) nil) | |
1405 | (setcdr (car next-errors) nil))) | |
1406 | (setq next-errors (cdr next-errors))) | |
1407 | ;; Look for the next error. | |
1408 | t) | |
1409 | ;; We found the file. Get a marker for this error. | |
1410 | ;; compilation-old-error-list is a buffer-local | |
1411 | ;; variable, so we must be careful to extract its value | |
1412 | ;; before switching to the source file buffer. | |
1413 | (let ((errors compilation-old-error-list) | |
1414 | (last-line (nth 1 (cdr next-error))) | |
1415 | (column (nth 2 (cdr next-error)))) | |
1416 | (set-buffer buffer) | |
1417 | (save-excursion | |
1418 | (save-restriction | |
1419 | (widen) | |
1420 | (goto-line last-line) | |
4dbf8a2c | 1421 | (if (and column (> column 0)) |
4ad26d84 RM |
1422 | ;; Columns in error msgs are 1-origin. |
1423 | (move-to-column (1- column)) | |
7fb63acd RS |
1424 | (beginning-of-line)) |
1425 | (setcdr next-error (point-marker)) | |
1426 | ;; Make all the other error messages referring | |
1427 | ;; to the same file have markers into the buffer. | |
1428 | (while errors | |
1429 | (and (consp (cdr (car errors))) | |
1430 | (equal (car (cdr (car errors))) fileinfo) | |
1431 | (let* ((this (nth 1 (cdr (car errors)))) | |
1432 | (column (nth 2 (cdr (car errors)))) | |
1433 | (lines (- this last-line))) | |
1434 | (if (eq selective-display t) | |
1435 | ;; When selective-display is t, | |
1436 | ;; each C-m is a line boundary, | |
1437 | ;; as well as each newline. | |
1438 | (if (< lines 0) | |
1439 | (re-search-backward "[\n\C-m]" | |
1440 | nil 'end | |
1441 | (- lines)) | |
1442 | (re-search-forward "[\n\C-m]" | |
1443 | nil 'end | |
1444 | lines)) | |
1445 | (forward-line lines)) | |
eae2c972 RM |
1446 | (if (and column (> column 1)) |
1447 | (move-to-column (1- column)) | |
1448 | (beginning-of-line)) | |
7fb63acd RS |
1449 | (setq last-line this) |
1450 | (setcdr (car errors) (point-marker)))) | |
1451 | (setq errors (cdr errors))))))))) | |
1452 | ;; If we didn't get a marker for this error, or this | |
1453 | ;; marker's buffer was killed, go on to the next one. | |
1454 | (or (not (markerp (cdr next-error))) | |
1455 | (not (marker-buffer (cdr next-error)))))) | |
1456 | (setq next-errors compilation-error-list | |
b4300a1a | 1457 | next-error (car next-errors))))) |
d3cb357b | 1458 | |
c41fe446 KH |
1459 | (if compilation-skip-to-next-location |
1460 | ;; Skip over multiple error messages for the same source location, | |
1461 | ;; so the next C-x ` won't go to an error in the same place. | |
1462 | (while (and compilation-error-list | |
a24770bc RS |
1463 | (equal (cdr (car compilation-error-list)) |
1464 | (cdr next-error))) | |
c41fe446 | 1465 | (setq compilation-error-list (cdr compilation-error-list)))) |
d3cb357b | 1466 | |
eaa3cac5 RM |
1467 | ;; We now have a marker for the position of the error source code. |
1468 | ;; NEXT-ERROR is a cons (ERROR . SOURCE) of two markers. | |
1469 | next-error)) | |
1470 | ||
1471 | (defun compilation-goto-locus (next-error) | |
1472 | "Jump to an error locus returned by `compilation-next-error-locus'. | |
1473 | Takes one argument, a cons (ERROR . SOURCE) of two markers. | |
1474 | Selects a window with point at SOURCE, with another window displaying ERROR." | |
e89a7d77 RS |
1475 | (if (and (window-dedicated-p (selected-window)) |
1476 | (eq (selected-window) (frame-root-window))) | |
1477 | (switch-to-buffer-other-frame (marker-buffer (cdr next-error))) | |
1478 | (switch-to-buffer (marker-buffer (cdr next-error)))) | |
eaa3cac5 RM |
1479 | (goto-char (cdr next-error)) |
1480 | ;; If narrowing got in the way of | |
1481 | ;; going to the right place, widen. | |
1482 | (or (= (point) (marker-position (cdr next-error))) | |
1483 | (progn | |
1484 | (widen) | |
1485 | (goto-char (cdr next-error)))) | |
1486 | ||
1487 | ;; Show compilation buffer in other window, scrolled to this error. | |
1488 | (let* ((pop-up-windows t) | |
eae2c972 | 1489 | ;; Use an existing window if it is in a visible frame. |
c94b02d6 | 1490 | (w (or (get-buffer-window (marker-buffer (car next-error)) 'visible) |
eae2c972 | 1491 | ;; Pop up a window. |
c94b02d6 | 1492 | (display-buffer (marker-buffer (car next-error)))))) |
eaa3cac5 | 1493 | (set-window-point w (car next-error)) |
c94b02d6 RS |
1494 | (set-window-start w (car next-error)) |
1495 | (compilation-set-window-height w))) | |
eaa3cac5 | 1496 | \f |
d3cb357b RM |
1497 | ;; Find a buffer for file FILENAME. |
1498 | ;; Search the directories in compilation-search-path. | |
1499 | ;; A nil in compilation-search-path means to try the | |
1500 | ;; current directory, which is passed in DIR. | |
1501 | ;; If FILENAME is not found at all, ask the user where to find it. | |
1502 | ;; Pop up the buffer containing MARKER and scroll to MARKER if we ask the user. | |
20c1daec RM |
1503 | (defun compilation-find-file (marker filename dir &rest formats) |
1504 | (or formats (setq formats '("%s"))) | |
d3cb357b | 1505 | (let ((dirs compilation-search-path) |
cd494de4 RM |
1506 | buffer thisdir fmts name) |
1507 | (if (file-name-absolute-p filename) | |
1508 | ;; The file name is absolute. Use its explicit directory as | |
1509 | ;; the first in the search path, and strip it from FILENAME. | |
1510 | (setq filename (abbreviate-file-name (expand-file-name filename)) | |
1511 | dirs (cons (file-name-directory filename) dirs) | |
1512 | filename (file-name-nondirectory filename))) | |
1513 | ;; Now search the path. | |
1514 | (while (and dirs (null buffer)) | |
20c1daec RM |
1515 | (setq thisdir (or (car dirs) dir) |
1516 | fmts formats) | |
cd494de4 RM |
1517 | ;; For each directory, try each format string. |
1518 | (while (and fmts (null buffer)) | |
20c1daec | 1519 | (setq name (expand-file-name (format (car fmts) filename) thisdir) |
cd494de4 | 1520 | buffer (and (file-exists-p name) |
20c1daec RM |
1521 | (find-file-noselect name)) |
1522 | fmts (cdr fmts))) | |
1523 | (setq dirs (cdr dirs))) | |
cd494de4 | 1524 | (or buffer |
d3cb357b RM |
1525 | ;; The file doesn't exist. |
1526 | ;; Ask the user where to find it. | |
1527 | ;; If he hits C-g, then the next time he does | |
1528 | ;; next-error, he'll skip past it. | |
cd494de4 RM |
1529 | (let* ((pop-up-windows t) |
1530 | (w (display-buffer (marker-buffer marker)))) | |
1531 | (set-window-point w marker) | |
1532 | (set-window-start w marker) | |
1533 | (let ((name (expand-file-name | |
1534 | (read-file-name | |
1535 | (format "Find this error in: (default %s) " | |
1536 | filename) | |
1537 | dir filename t)))) | |
1538 | (if (file-directory-p name) | |
1539 | (setq name (expand-file-name filename name))) | |
1540 | (and (file-exists-p name) | |
1541 | (find-file-noselect name))))))) | |
d3cb357b RM |
1542 | |
1543 | ;; Set compilation-error-list to nil, and unchain the markers that point to the | |
1544 | ;; error messages and their text, so that they no longer slow down gap motion. | |
1545 | ;; This would happen anyway at the next garbage collection, but it is better to | |
646bd331 | 1546 | ;; do it right away. |
55dfd2c4 RS |
1547 | (defun compilation-forget-errors () |
1548 | (while compilation-old-error-list | |
1549 | (let ((next-error (car compilation-old-error-list))) | |
1550 | (set-marker (car next-error) nil) | |
d3cb357b RM |
1551 | (if (markerp (cdr next-error)) |
1552 | (set-marker (cdr next-error) nil))) | |
55dfd2c4 | 1553 | (setq compilation-old-error-list (cdr compilation-old-error-list))) |
bd3910fe | 1554 | (setq compilation-error-list nil |
355345fd | 1555 | compilation-directory-stack (list default-directory) |
37f5f978 RS |
1556 | compilation-parsing-end 1) |
1557 | ;; Remove the highlighting added by compile-reinitialize-errors: | |
1558 | (let ((inhibit-read-only t)) | |
1559 | (remove-text-properties (point-min) (point-max) '(mouse-face highlight))) | |
1560 | ) | |
d3cb357b RM |
1561 | |
1562 | ||
a24770bc RS |
1563 | ;; This function is not needed any more by compilation mode. |
1564 | ;; Does anyone else need it or can it be deleted? | |
d3cb357b RM |
1565 | (defun count-regexp-groupings (regexp) |
1566 | "Return the number of \\( ... \\) groupings in REGEXP (a string)." | |
1567 | (let ((groupings 0) | |
1568 | (len (length regexp)) | |
1569 | (i 0) | |
1570 | c) | |
1571 | (while (< i len) | |
1572 | (setq c (aref regexp i) | |
1573 | i (1+ i)) | |
1574 | (cond ((= c ?\[) | |
1575 | ;; Find the end of this [...]. | |
1576 | (while (and (< i len) | |
1577 | (not (= (aref regexp i) ?\]))) | |
1578 | (setq i (1+ i)))) | |
1579 | ((= c ?\\) | |
1580 | (if (< i len) | |
1581 | (progn | |
1582 | (setq c (aref regexp i) | |
1583 | i (1+ i)) | |
1584 | (if (= c ?\)) | |
1585 | ;; We found the end of a grouping, | |
1586 | ;; so bump our counter. | |
1587 | (setq groupings (1+ groupings)))))))) | |
1588 | groupings)) | |
55dfd2c4 | 1589 | |
a24770bc RS |
1590 | (defvar compilation-current-file nil |
1591 | "Used by compilation-parse-errors to store filename for file being compiled") | |
1592 | ||
1593 | ;; This variable is not used as a global variable. It's defined here just to | |
1594 | ;; shut up the byte compiler. It's bound and used by compilation-parse-errors | |
1595 | ;; and set by compile-collect-regexps. | |
1596 | (defvar compilation-regexps nil) | |
1597 | ||
c540863c | 1598 | (defun compilation-parse-errors (limit-search find-at-least) |
a24770bc | 1599 | "Parse the current buffer as grep, cc, lint or other error messages. |
d3cb357b | 1600 | See variable `compilation-parse-errors-function' for the interface it uses." |
55dfd2c4 RS |
1601 | (setq compilation-error-list nil) |
1602 | (message "Parsing error messages...") | |
a24770bc RS |
1603 | (if (null compilation-error-regexp-alist) |
1604 | (error "compilation-error-regexp-alist is empty!")) | |
1605 | (let* ((compilation-regexps nil) ; Variable set by compile-collect-regexps. | |
355345fd | 1606 | (default-directory default-directory) |
a24770bc RS |
1607 | (found-desired nil) |
1608 | (compilation-num-errors-found 0) | |
1609 | ;; Set up now the expanded, abbreviated directory variables | |
1610 | ;; that compile-abbreviate-directory will need, so we can | |
1611 | ;; compute them just once here. | |
1612 | (orig (abbreviate-file-name default-directory)) | |
1613 | (orig-expanded (abbreviate-file-name | |
1614 | (file-truename default-directory))) | |
1615 | (parent-expanded (abbreviate-file-name | |
1616 | (expand-file-name "../" orig-expanded)))) | |
1617 | ||
1618 | ;; Make a list of all the regexps. Each element has the form | |
1619 | ;; (REGEXP TYPE IDX1 IDX2 ...) | |
1620 | ;; where TYPE is one of leave, enter, file, error or nomessage. | |
1621 | (compile-collect-regexps 'leave compilation-leave-directory-regexp-alist) | |
1622 | (compile-collect-regexps 'enter compilation-enter-directory-regexp-alist) | |
1623 | (compile-collect-regexps 'file compilation-file-regexp-alist) | |
1624 | (compile-collect-regexps 'nomessage compilation-nomessage-regexp-alist) | |
1625 | (compile-collect-regexps 'error compilation-error-regexp-alist) | |
d3cb357b | 1626 | |
55dfd2c4 RS |
1627 | ;; Don't reparse messages already seen at last parse. |
1628 | (goto-char compilation-parsing-end) | |
9cab952d RS |
1629 | (when (and (bobp) |
1630 | (eq major-mode 'compilation-mode)) | |
1631 | (setq compilation-current-file nil) ; No current file at start. | |
1632 | ;; Don't parse the first two lines as error messages. | |
1633 | ;; This matters for grep. | |
1634 | (forward-line 2)) | |
a24770bc RS |
1635 | |
1636 | ;; Parse messages. | |
1637 | (while (not (or found-desired (eobp))) | |
1638 | (let ((this compilation-regexps) (prev nil) (alist nil) type) | |
1639 | ;; Go through the regular expressions. If a match is found, | |
1640 | ;; variable alist is set to the corresponding alist and the | |
1641 | ;; matching regexp is moved to the front of compilation-regexps | |
1642 | ;; to make it match faster next time. | |
1643 | (while (and this (null alist)) | |
1644 | (if (not (looking-at (car (car this)))) | |
1645 | (progn (setq prev this) ; No match, go to next. | |
1646 | (setq this (cdr this))) | |
1647 | (setq alist (cdr (car this))) ; Got a match. | |
1648 | ;;; (if prev ; If not the first regexp, | |
1649 | ;;; (progn ; move it to the front. | |
1650 | ;;; (setcdr prev (cdr this)) | |
1651 | ;;; (setcdr this compilation-regexps) | |
1652 | ;;; (setq compilation-regexps this))) | |
1653 | )) | |
1654 | (if (and alist ; Seen a match and not to | |
1655 | (not (eq (setq type (car alist)) 'nomessage))) ; be ignored. | |
1656 | (let* ((end-of-match (match-end 0)) | |
1657 | (filename | |
1658 | (compile-buffer-substring (car (setq alist (cdr alist))))) | |
1659 | stack) | |
1660 | (if (eq type 'error) ; error message | |
1661 | (let* ((linenum (if (numberp (car (setq alist (cdr alist)))) | |
1662 | (string-to-int | |
1663 | (compile-buffer-substring (car alist))) | |
1664 | ;; (car alist) is not a number, must be a | |
1665 | ;; function that is called below to return | |
1666 | ;; an error position descriptor. | |
1667 | (car alist))) | |
1668 | ;; Convert to integer later if linenum not a function. | |
1669 | (column (compile-buffer-substring | |
1670 | (car (setq alist (cdr alist))))) | |
1671 | this-error) | |
1672 | ||
1673 | ;; Check that we have a file name. | |
1674 | (or filename | |
1675 | ;; No file name in message, we must have seen it before | |
1676 | (setq filename compilation-current-file) | |
1677 | (error "\ | |
1678 | An error message with no file name and no file name has been seen earlier.")) | |
1679 | ||
1680 | ;; Check for a comint-file-name-prefix and prepend it if | |
1681 | ;; appropriate. (This is very useful for | |
1682 | ;; compilation-minor-mode in an rlogin-mode buffer.) | |
1683 | (and (boundp 'comint-file-name-prefix) | |
1684 | ;; If file name is relative, default-directory will | |
1685 | ;; already contain the comint-file-name-prefix (done | |
1686 | ;; by compile-abbreviate-directory). | |
1687 | (file-name-absolute-p filename) | |
1688 | (setq filename | |
1689 | (concat comint-file-name-prefix filename))) | |
1690 | ||
1691 | ;; Some compilers (e.g. Sun's java compiler, reportedly) | |
1692 | ;; produce bogus file names like "./bar//foo.c" for file | |
1693 | ;; "bar/foo.c"; expand-file-name will collapse these into | |
1694 | ;; "/foo.c" and fail to find the appropriate file. So we | |
1695 | ;; look for doubled slashes in the file name and fix them | |
1696 | ;; up in the buffer. | |
1697 | (setq filename (command-line-normalize-file-name filename)) | |
1698 | ||
1699 | (setq filename | |
1700 | (cons filename (cons default-directory (cdr alist)))) | |
1701 | ||
1702 | ;; Locate the erring file and line. | |
1703 | ;; Make this-error a new elt for compilation-error-list, | |
1704 | ;; giving a marker for the current compilation buffer | |
1705 | ;; location, and the file and line number of the error. | |
1706 | ;; Save, as the start of the error, the beginning of the | |
1707 | ;; line containing the match. | |
bb40e751 RS |
1708 | (setq this-error |
1709 | (if (numberp linenum) | |
1710 | (list (point-marker) filename linenum | |
1711 | (and column (string-to-int column))) | |
1712 | ;; If linenum is not a number then it must be | |
1713 | ;; a function returning an error position | |
1714 | ;; descriptor or nil (meaning no position). | |
1715 | (save-excursion | |
1716 | (funcall linenum filename column)))) | |
a24770bc | 1717 | |
bb40e751 RS |
1718 | ;; We have an error position descriptor. |
1719 | ;; If we have found as many new errors as the user | |
1720 | ;; wants, or if we are past the buffer position he | |
1721 | ;; indicated, then we continue to parse until we have | |
1722 | ;; seen all consecutive errors in the same file. This | |
1723 | ;; means that all the errors of a source file will be | |
1724 | ;; seen in one parsing run, so that the error positions | |
1725 | ;; will be recorded as markers in the source file | |
1726 | ;; buffer that will move when the buffer is changed. | |
1727 | (if (and this-error | |
1728 | compilation-error-list ; At least one previous. | |
1729 | (or (and find-at-least | |
1730 | (>= compilation-num-errors-found | |
1731 | find-at-least)) | |
1732 | (and limit-search | |
1733 | (>= end-of-match limit-search))) | |
1734 | (not (equal ; Same filename? | |
1735 | (car (cdr (car compilation-error-list))) | |
1736 | (car (cdr this-error))))) | |
1737 | ;; We are past the limits and the last error | |
1738 | ;; parsed, didn't belong to the same source file | |
1739 | ;; as the earlier ones i.e. we have seen all the | |
1740 | ;; errors belonging to the earlier file. We don't | |
1741 | ;; add the error just parsed so that the next | |
1742 | ;; parsing run can get it and the following errors | |
1743 | ;; in the same file all at once. | |
1744 | (setq found-desired t) | |
1745 | ||
1746 | (goto-char end-of-match) ; Prepare for next message. | |
1747 | ;; Don't add the same source line more than once. | |
1748 | (and this-error | |
1749 | (not (and | |
1750 | compilation-error-list | |
1751 | (equal (cdr (car compilation-error-list)) | |
1752 | (cdr this-error)))) | |
1753 | (setq compilation-error-list | |
1754 | (cons this-error compilation-error-list) | |
1755 | compilation-num-errors-found | |
1756 | (1+ compilation-num-errors-found))))) | |
a24770bc RS |
1757 | |
1758 | ;; Not an error message. | |
1759 | (if (eq type `file) ; Change current file. | |
1760 | (and filename (setq compilation-current-file filename)) | |
1761 | ;; Enter or leave directory. | |
1762 | (setq stack compilation-directory-stack) | |
1763 | (and filename | |
1764 | (file-directory-p | |
1765 | (setq filename | |
1766 | ;; The directory name in the message | |
1767 | ;; is a truename. Try to convert it to a form | |
1768 | ;; like what the user typed in. | |
1769 | (compile-abbreviate-directory | |
1770 | (file-name-as-directory | |
1771 | (expand-file-name filename)) | |
1772 | orig orig-expanded parent-expanded))) | |
1773 | (if (eq type 'leave) | |
1774 | (while (and stack | |
1775 | (not (string-equal (car stack) | |
1776 | filename))) | |
1777 | (setq stack (cdr stack))) | |
1778 | (setq compilation-directory-stack | |
1779 | (cons filename compilation-directory-stack) | |
1780 | default-directory filename))) | |
58856335 RS |
1781 | (and (eq type 'leave) |
1782 | stack | |
1783 | (setq compilation-directory-stack (cdr stack)) | |
1784 | (setq stack (car compilation-directory-stack)) | |
bb40e751 RS |
1785 | (setq default-directory stack))) |
1786 | (goto-char end-of-match) ; Prepare to look at next message. | |
1787 | (and limit-search (>= end-of-match limit-search) | |
1788 | ;; The user wanted a specific error, and we're past it. | |
1789 | ;; We do this check here rather than at the end of the | |
1790 | ;; loop because if the last thing seen is an error | |
1791 | ;; message, we must carefully discard the last error | |
1792 | ;; when it is the first in a new file (see above in | |
1793 | ;; the error-message case) | |
1794 | (setq found-desired t))) | |
a24770bc RS |
1795 | |
1796 | ;; Go to before the last character in the message so that we will | |
1797 | ;; see the next line also when the message ended at end of line. | |
1798 | ;; When we ignore the last error message above, this will | |
1799 | ;; cancel the effect of forward-line below so that point | |
1800 | ;; doesn't move. | |
1801 | (forward-char -1) | |
1802 | ||
1803 | ;; Is this message necessary any more? Parsing is now so fast | |
1804 | ;; that you might not need to know how it proceeds. | |
1805 | (message | |
1806 | "Parsing error messages...%d found. %.0f%% of buffer seen." | |
6c43f2f9 | 1807 | compilation-num-errors-found |
51ba27e7 RM |
1808 | ;; Use floating-point because (* 100 (point)) frequently |
1809 | ;; exceeds the range of Emacs Lisp integers. | |
1810 | (/ (* 100.0 (point)) (point-max))) | |
a24770bc RS |
1811 | )) |
1812 | ||
1813 | (forward-line 1))) ; End of while loop. Look at next line. | |
1814 | ||
1815 | (setq compilation-parsing-end (point)) | |
1816 | (setq compilation-error-list (nreverse compilation-error-list)) | |
1817 | ;;; (message "Parsing error messages...done. %d found. %.0f%% of buffer seen." | |
1818 | ;;; compilation-num-errors-found | |
1819 | ;;; (/ (* 100.0 (point)) (point-max))) | |
1820 | (message "Parsing error messages...done."))) | |
1821 | ||
1822 | (defun compile-collect-regexps (type this) | |
1823 | ;; Add elements to variable compilation-regexps that is bound in | |
1824 | ;; compilation-parse-errors. | |
1825 | (and (not (eq this t)) | |
1826 | (while this | |
1827 | (setq compilation-regexps | |
1828 | (cons (cons (car (car this)) (cons type (cdr (car this)))) | |
1829 | compilation-regexps)) | |
1830 | (setq this (cdr this))))) | |
1831 | ||
1832 | (defun compile-buffer-substring (index) | |
1833 | ;; Get substring matched by INDEXth subexpression. | |
1834 | (if index | |
1835 | (let ((beg (match-beginning index))) | |
1836 | (if beg (buffer-substring beg (match-end index)))))) | |
55dfd2c4 | 1837 | |
51501e54 RS |
1838 | ;; If directory DIR is a subdir of ORIG or of ORIG's parent, |
1839 | ;; return a relative name for it starting from ORIG or its parent. | |
1840 | ;; ORIG-EXPANDED is an expanded version of ORIG. | |
1841 | ;; PARENT-EXPANDED is an expanded version of ORIG's parent. | |
1842 | ;; Those two args could be computed here, but we run faster by | |
1843 | ;; having the caller compute them just once. | |
1844 | (defun compile-abbreviate-directory (dir orig orig-expanded parent-expanded) | |
cd494de4 RM |
1845 | ;; Apply canonical abbreviations to DIR first thing. |
1846 | ;; Those abbreviations are already done in the other arguments passed. | |
1847 | (setq dir (abbreviate-file-name dir)) | |
1848 | ||
1e0e614d RM |
1849 | ;; Check for a comint-file-name-prefix and prepend it if appropriate. |
1850 | ;; (This is very useful for compilation-minor-mode in an rlogin-mode | |
1851 | ;; buffer.) | |
1852 | (if (boundp 'comint-file-name-prefix) | |
1853 | (setq dir (concat comint-file-name-prefix dir))) | |
1854 | ||
51501e54 RS |
1855 | (if (and (> (length dir) (length orig-expanded)) |
1856 | (string= orig-expanded | |
1857 | (substring dir 0 (length orig-expanded)))) | |
1858 | (setq dir | |
1859 | (concat orig | |
1860 | (substring dir (length orig-expanded))))) | |
1861 | (if (and (> (length dir) (length parent-expanded)) | |
1862 | (string= parent-expanded | |
1863 | (substring dir 0 (length parent-expanded)))) | |
1864 | (setq dir | |
1865 | (concat (file-name-directory | |
1866 | (directory-file-name orig)) | |
1867 | (substring dir (length parent-expanded))))) | |
1868 | dir) | |
1869 | ||
4746118a | 1870 | (provide 'compile) |
fad160d5 ER |
1871 | |
1872 | ;;; compile.el ends here |