compile.el 123 KB
Newer Older
1
;;; compile.el --- run compiler as inferior of Emacs, parse error messages  -*- lexical-binding:t -*-
Eric S. Raymond's avatar
Eric S. Raymond committed
2

Paul Eggert's avatar
Paul Eggert committed
3
;; Copyright (C) 1985-1987, 1993-1999, 2001-2019 Free Software
4
;; Foundation, Inc.
Eric S. Raymond's avatar
Eric S. Raymond committed
5

Stefan Monnier's avatar
Stefan Monnier committed
6 7
;; Authors: Roland McGrath <roland@gnu.org>,
;;	    Daniel Pfeiffer <occitan@esperanto.org>
8
;; Maintainer: emacs-devel@gnu.org
Eric S. Raymond's avatar
Eric S. Raymond committed
9
;; Keywords: tools, processes
Eric S. Raymond's avatar
Eric S. Raymond committed
10

Richard M. Stallman's avatar
Richard M. Stallman committed
11 12
;; This file is part of GNU Emacs.

13
;; GNU Emacs is free software: you can redistribute it and/or modify
Roland McGrath's avatar
Roland McGrath committed
14
;; it under the terms of the GNU General Public License as published by
15 16
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
Roland McGrath's avatar
Roland McGrath committed
17

Richard M. Stallman's avatar
Richard M. Stallman committed
18
;; GNU Emacs is distributed in the hope that it will be useful,
Roland McGrath's avatar
Roland McGrath committed
19 20 21 22 23
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
24
;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
Richard M. Stallman's avatar
Richard M. Stallman committed
25

Eric S. Raymond's avatar
Eric S. Raymond committed
26 27
;;; Commentary:

Stefan Monnier's avatar
Stefan Monnier committed
28 29
;; This package provides the compile facilities documented in the Emacs user's
;; manual.
Eric S. Raymond's avatar
Eric S. Raymond committed
30

31 32
;;; Code:

33
(eval-when-compile (require 'cl-lib))
Jan Djärv's avatar
Jan Djärv committed
34
(require 'tool-bar)
35
(require 'comint)
Stefan Monnier's avatar
Stefan Monnier committed
36

37 38 39 40 41 42
(defgroup compilation nil
  "Run compiler as inferior of Emacs, parse error messages."
  :group 'tools
  :group 'processes)


Roland McGrath's avatar
Roland McGrath committed
43
;;;###autoload
44
(defcustom compilation-mode-hook nil
45
  "List of hook functions run by `compilation-mode'."
46
  :type 'hook)
Roland McGrath's avatar
Roland McGrath committed
47

48 49
;;;###autoload
(defcustom compilation-start-hook nil
50 51
  "Hook run after starting a new compilation process.
The hook is run with one argument, the new process."
52
  :type 'hook)
53

Roland McGrath's avatar
Roland McGrath committed
54
;;;###autoload
55
(defcustom compilation-window-height nil
56 57
  "Number of lines in a compilation window.
If nil, use Emacs default."
58
  :type '(choice (const :tag "Default" nil)
59
		 integer))
Roland McGrath's avatar
Roland McGrath committed
60

61 62 63 64
(defvar compilation-filter-hook nil
  "Hook run after `compilation-filter' has inserted a string into the buffer.
It is called with the variable `compilation-filter-start' bound
to the position of the start of the inserted text, and point at
65 66 67 68
its end.

If Emacs lacks asynchronous process support, this hook is run
after `call-process' inserts the grep output into the buffer.")
69 70

(defvar compilation-filter-start nil
71 72
  "Position of the start of the text inserted by `compilation-filter'.
This is bound before running `compilation-filter-hook'.")
73

Stefan Monnier's avatar
Stefan Monnier committed
74
(defvar compilation-first-column 1
75
  "This is how compilers number the first column, usually 1 or 0.
Glenn Morris's avatar
Glenn Morris committed
76 77 78
If this is buffer-local in the destination buffer, Emacs obeys
that value, otherwise it uses the value in the *compilation*
buffer.  This enables a major-mode to specify its own value.")
Richard M. Stallman's avatar
Richard M. Stallman committed
79

80 81 82
(defvar compilation-parse-errors-filename-function nil
  "Function to call to post-process filenames while parsing error messages.
It takes one arg FILENAME which is the name of a file as found
83 84 85 86
in the compilation output, and should return a transformed file name
or a buffer, the one which was compiled.")
;; Note: the compilation-parse-errors-filename-function need not save the
;; match data.
87

88 89
;;;###autoload
(defvar compilation-process-setup-function nil
90
  "Function to call to customize the compilation process.
Stefan Monnier's avatar
Stefan Monnier committed
91
This function is called immediately before the compilation process is
92
started.  It can be used to set any variables or functions that are used
93
while processing the output of the compilation process.")
94

Jim Blandy's avatar
Jim Blandy committed
95
;;;###autoload
Roland McGrath's avatar
Roland McGrath committed
96
(defvar compilation-buffer-name-function nil
Richard M. Stallman's avatar
Richard M. Stallman committed
97 98 99
  "Function to compute the name of a compilation buffer.
The function receives one argument, the name of the major mode of the
compilation buffer.  It should return a string.
100
If nil, compute the name with `(concat \"*\" (downcase major-mode) \"*\")'.")
Richard M. Stallman's avatar
Richard M. Stallman committed
101

102 103
;;;###autoload
(defvar compilation-finish-functions nil
104
  "Functions to call when a compilation process finishes.
105 106 107
Each function is called with two arguments: the compilation buffer,
and a string describing how the process finished.")

Roland McGrath's avatar
Roland McGrath committed
108 109 110 111 112 113
(defvar compilation-in-progress nil
  "List of compilation processes now running.")
(or (assq 'compilation-in-progress minor-mode-alist)
    (setq minor-mode-alist (cons '(compilation-in-progress " Compiling")
				 minor-mode-alist)))

Stefan Monnier's avatar
Stefan Monnier committed
114 115
(defvar compilation-error "error"
  "Stem of message to print when no matches are found.")
Richard M. Stallman's avatar
Richard M. Stallman committed
116

117
(defvar compilation-arguments nil
Stefan Monnier's avatar
Stefan Monnier committed
118
  "Arguments that were given to `compilation-start'.")
119

120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
(defvar compilation-num-errors-found 0)
(defvar compilation-num-warnings-found 0)
(defvar compilation-num-infos-found 0)

(defconst compilation-mode-line-errors
  '(" [" (:propertize (:eval (int-to-string compilation-num-errors-found))
                      face compilation-error
                      help-echo "Number of errors so far")
    " " (:propertize (:eval (int-to-string compilation-num-warnings-found))
                     face compilation-warning
                     help-echo "Number of warnings so far")
    " " (:propertize (:eval (int-to-string compilation-num-infos-found))
                     face compilation-info
                     help-echo "Number of informational messages so far")
    "]"))
Roland McGrath's avatar
Roland McGrath committed
135

136
;; If you make any changes to `compilation-error-regexp-alist-alist',
137
;; be sure to run the ERT test in test/lisp/progmodes/compile-tests.el.
138
;; emacs -batch -l compile-tests.el -f ert-run-tests-batch-and-exit
139

140
(defvar compilation-error-regexp-alist-alist
141
  `((absoft
Stefan Monnier's avatar
Stefan Monnier committed
142 143
     "^\\(?:[Ee]rror on \\|[Ww]arning on\\( \\)\\)?[Ll]ine[ \t]+\\([0-9]+\\)[ \t]+\
of[ \t]+\"?\\([a-zA-Z]?:?[^\":\n]+\\)\"?:" 3 2 nil (1))
144

Stefan Monnier's avatar
Stefan Monnier committed
145 146
    (ada
     "\\(warning: .*\\)? at \\([^ \n]+\\):\\([0-9]+\\)$" 2 3 nil (1))
Karl Heuer's avatar
Karl Heuer committed
147

Stefan Monnier's avatar
Stefan Monnier committed
148 149
    (aix
     " in line \\([0-9]+\\) of file \\([^ \n]+[^. \n]\\)\\.? " 2 1)
150

Stefan Monnier's avatar
Stefan Monnier committed
151
    (ant
152
     "^[ \t]*\\[[^] \n]+\\][ \t]*\\(\\(?:[A-Za-z]:\\\\\\)?[^: \n]+\\):\\([0-9]+\\):\\(?:\\([0-9]+\\):\\([0-9]+\\):\\([0-9]+\\):\\)?\
Chong Yidong's avatar
Chong Yidong committed
153
\\( warning\\)?" 1 (2 . 4) (3 . 5) (6))
154

Stefan Monnier's avatar
Stefan Monnier committed
155 156
    (bash
     "^\\([^: \n\t]+\\): line \\([0-9]+\\):" 1 2)
157

Stefan Monnier's avatar
Stefan Monnier committed
158 159 160 161 162
    (borland
     "^\\(?:Error\\|Warnin\\(g\\)\\) \\(?:[FEW][0-9]+ \\)?\
\\([a-zA-Z]?:?[^:( \t\n]+\\)\
 \\([0-9]+\\)\\(?:[) \t]\\|:[^0-9\n]\\)" 2 3 nil (1))

163 164
    (python-tracebacks-and-caml
     "^[ \t]*File \\(\"?\\)\\([^,\" \n\t<>]+\\)\\1, lines? \\([0-9]+\\)-?\\([0-9]+\\)?\\(?:$\\|,\
165
\\(?: characters? \\([0-9]+\\)-?\\([0-9]+\\)?:\\)?\\([ \n]Warning\\(?: [0-9]+\\)?:\\)?\\)"
166
     2 (3 . 4) (5 . 6) (7))
Stefan Monnier's avatar
Stefan Monnier committed
167

Jö Fahlke's avatar
Jö Fahlke committed
168 169 170 171 172 173 174
    (cmake
     "^CMake \\(?:Error\\|\\(Warning\\)\\) at \\(.*\\):\\([1-9][0-9]*\\) ([^)]+):$"
     2 3 nil (1))
    (cmake-info
     "^  \\(?: \\*\\)?\\(.*\\):\\([1-9][0-9]*\\) ([^)]+)$"
     1 2 nil 0)

Stefan Monnier's avatar
Stefan Monnier committed
175 176 177 178
    (comma
     "^\"\\([^,\" \n\t]+\\)\", line \\([0-9]+\\)\
\\(?:[(. pos]+\\([0-9]+\\))?\\)?[:.,; (-]\\( warning:\\|[-0-9 ]*(W)\\)?" 1 2 3 (4))

179 180
    (cucumber
     "\\(?:^cucumber\\(?: -p [^[:space:]]+\\)?\\|#\\)\
181
\\(?: \\)\\([^(].*\\):\\([1-9][0-9]*\\)" 1 2)
182

183 184 185 186 187 188 189 190 191
    (msft
     ;; Must be before edg-1, so that MSVC's longer messages are
     ;; considered before EDG.
     ;; The message may be a "warning", "error", or "fatal error" with
     ;; an error code, or "see declaration of" without an error code.
     "^ *\\([0-9]+>\\)?\\(\\(?:[a-zA-Z]:\\)?[^:(\t\n]+\\)(\\([0-9]+\\)) ?\
: \\(?:see declaration\\|\\(?:warnin\\(g\\)\\|[a-z ]+\\) C[0-9]+:\\)"
     2 3 nil (4))

192 193 194 195 196 197 198
    (edg-1
     "^\\([^ \n]+\\)(\\([0-9]+\\)): \\(?:error\\|warnin\\(g\\)\\|remar\\(k\\)\\)"
     1 2 nil (3 . 4))
    (edg-2
     "at line \\([0-9]+\\) of \"\\([^ \n]+\\)\"$"
     2 1 nil 0)

Stefan Monnier's avatar
Stefan Monnier committed
199
    (epc
200
     "^Error [0-9]+ at (\\([0-9]+\\):\\([^)\n]+\\))" 2 1)
Stefan Monnier's avatar
Stefan Monnier committed
201

202 203 204
    (ftnchek
     "\\(^Warning .*\\)? line[ \n]\\([0-9]+\\)[ \n]\\(?:col \\([0-9]+\\)[ \n]\\)?file \\([^ :;\n]+\\)"
     4 2 3 (1))
205

Stefan Monnier's avatar
Stefan Monnier committed
206 207 208 209 210 211 212 213
    (iar
     "^\"\\(.*\\)\",\\([0-9]+\\)\\s-+\\(?:Error\\|Warnin\\(g\\)\\)\\[[0-9]+\\]:"
     1 2 nil (3))

    (ibm
     "^\\([^( \n\t]+\\)(\\([0-9]+\\):\\([0-9]+\\)) :\
 \\(?:warnin\\(g\\)\\|informationa\\(l\\)\\)?" 1 2 3 (4 . 5))

Stefan Monnier's avatar
Stefan Monnier committed
214
    ;; fixme: should be `mips'
Stefan Monnier's avatar
Stefan Monnier committed
215
    (irix
216 217
     "^[-[:alnum:]_/ ]+: \\(?:\\(?:[sS]evere\\|[eE]rror\\|[wW]arnin\\(g\\)\\|[iI]nf\\(o\\)\\)[0-9 ]*: \\)?\
\\([^,\" \n\t]+\\)\\(?:, line\\|:\\) \\([0-9]+\\):" 3 4 nil (1 . 2))
Stefan Monnier's avatar
Stefan Monnier committed
218 219 220 221 222 223

    (java
     "^\\(?:[ \t]+at \\|==[0-9]+== +\\(?:at\\|b\\(y\\)\\)\\).+(\\([^()\n]+\\):\\([0-9]+\\))$" 2 3 nil (1))

    (jikes-file
     "^\\(?:Found\\|Issued\\) .* compiling \"\\(.+\\)\":$" 1 nil nil 0)
224 225 226 227 228 229


    ;; This used to be pathologically slow on long lines (Bug#3441),
    ;; due to matching filenames via \\(.*?\\).  This might be faster.
    (maven
     ;; Maven is a popular free software build tool for Java.
230
     "\\(\\[WARNING\\] *\\)?\\([^ \n]\\(?:[^\n :]\\| [^-/\n]\\|:[^ \n]\\)*?\\):\\[\\([0-9]+\\),\\([0-9]+\\)\\] " 2 3 4 (1))
231

Stefan Monnier's avatar
Stefan Monnier committed
232 233 234 235 236
    (jikes-line
     "^ *\\([0-9]+\\)\\.[ \t]+.*\n +\\(<-*>\n\\*\\*\\* \\(?:Error\\|Warnin\\(g\\)\\)\\)"
     nil 1 nil 2 0
     (2 (compilation-face '(3))))

237 238 239 240 241 242 243
    (clang-include
     ,(rx bol "In file included from "
          (group (+ (not (any ?\n ?:)))) ?:
          (group (+ (any (?0 . ?9)))) ?:
          eol)
     1 2 nil 0)

244 245
    (gcc-include
     "^\\(?:In file included \\|                 \\|\t\\)from \
Andreas Schwab's avatar
Andreas Schwab committed
246 247 248
\\([0-9]*[^0-9\n]\\(?:[^\n :]\\| [^-/\n]\\|:[^ \n]\\)*?\\):\
\\([0-9]+\\)\\(?::\\([0-9]+\\)\\)?\\(?:\\(:\\)\\|\\(,\\|$\\)\\)?"
     1 2 3 (4 . 5))
249

250
    (ruby-Test::Unit
251
     "^[\t ]*\\[\\([^(].*\\):\\([1-9][0-9]*\\)\\(\\]\\)?:in " 1 2)
252

Stefan Monnier's avatar
Stefan Monnier committed
253
    (gnu
254 255 256 257 258 259 260 261 262 263 264 265 266
     ;; The first line matches the program name for

     ;;     PROGRAM:SOURCE-FILE-NAME:LINENO: MESSAGE

     ;; format, which is used for non-interactive programs other than
     ;; compilers (e.g. the "jade:" entry in compilation.txt).

     ;; This first line makes things ambiguous with output such as
     ;; "foo:344:50:blabla" since the "foo" part can match this first
     ;; line (in which case the file name as "344").  To avoid this,
     ;; the second line disallows filenames exclusively composed of
     ;; digits.

267 268 269 270
     ;; Similarly, we get lots of false positives with messages including
     ;; times of the form "HH:MM:SS" where MM is taken as a line number, so
     ;; the last line tries to rule out message where the info after the
     ;; line number starts with "SS".  --Stef
271 272 273 274

     ;; The core of the regexp is the one with *?.  It says that a file name
     ;; can be composed of any non-newline char, but it also rules out some
     ;; valid but unlikely cases, such as a trailing space or a space
275
     ;; followed by a -, or a colon followed by a space.
276
     ;;
277
     ;; The "in \\|from " exception was added to handle messages from Ruby.
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315
     ,(rx
       bol
       (? (| (regexp "[[:alpha:]][-[:alnum:].]+: ?")
             (regexp "[ \t]+\\(?:in \\|from\\)")))
       (group-n 1 (: (regexp "[0-9]*[^0-9\n]")
                     (*? (| (regexp "[^\n :]")
                            (regexp " [^-/\n]")
                            (regexp ":[^ \n]")))))
       (regexp ": ?")
       (group-n 2 (regexp "[0-9]+"))
       (? (| (: "-"
                (group-n 4 (regexp "[0-9]+"))
                (? "." (group-n 5 (regexp "[0-9]+"))))
             (: (in ".:")
                (group-n 3 (regexp "[0-9]+"))
                (? "-"
                   (? (group-n 4 (regexp "[0-9]+")) ".")
                   (group-n 5 (regexp "[0-9]+"))))))
       ":"
       (| (: (* " ")
             (group-n 6 (| "FutureWarning"
                           "RuntimeWarning"
                           "Warning"
                           "warning"
                           "W:")))
          (: (* " ")
             (group-n 7 (| (regexp "[Ii]nfo\\(?:\\>\\|rmationa?l?\\)")
                           "I:"
                           (: "[ skipping " (+ ".") " ]")
                           "instantiated from"
                           "required from"
                           (regexp "[Nn]ote"))))
          (: (* " ")
             (regexp "[Ee]rror"))
          (: (regexp "[0-9]?")
             (| (regexp "[^0-9\n]")
                eol))
          (regexp "[0-9][0-9][0-9]")))
316
     1 (2 . 4) (3 . 5) (6 . 7))
Stefan Monnier's avatar
Stefan Monnier committed
317 318 319 320 321 322

    (lcc
     "^\\(?:E\\|\\(W\\)\\), \\([^(\n]+\\)(\\([0-9]+\\),[ \t]*\\([0-9]+\\)"
     2 3 4 (1))

    (makepp
Daniel Pfeiffer's avatar
Daniel Pfeiffer committed
323
     "^makepp\\(?:\\(?:: warning\\(:\\).*?\\|\\(: Scanning\\|: [LR]e?l?oading makefile\\|: Imported\\|log:.*?\\) \\|: .*?\\)\
324
`\\(\\(\\S +?\\)\\(?::\\([0-9]+\\)\\)?\\)['(]\\)"
Stefan Monnier's avatar
Stefan Monnier committed
325
     4 5 nil (1 . 2) 3
326 327 328 329 330 331 332 333 334
     (0 (progn (save-match-data
                 (compilation-parse-errors
                  (match-end 0) (line-end-position)
                  `("`\\(\\(\\S +?\\)\\(?::\\([0-9]+\\)\\)?\\)['(]"
                    2 3 nil
                    ,(cond ((match-end 1) 1) ((match-end 2) 0) (t 2))
                    1)))
               (end-of-line)
               nil)))
Stefan Monnier's avatar
Stefan Monnier committed
335

Stefan Monnier's avatar
Stefan Monnier committed
336
    ;; Should be lint-1, lint-2 (SysV lint)
Stefan Monnier's avatar
Stefan Monnier committed
337 338 339 340 341 342
    (mips-1
     " (\\([0-9]+\\)) in \\([^ \n]+\\)" 2 1)
    (mips-2
     " in \\([^()\n ]+\\)(\\([0-9]+\\))$" 1 2)

    (msft
343 344 345 346 347
     ;; The message may be a "warning", "error", or "fatal error" with
     ;; an error code, or "see declaration of" without an error code.
     "^ *\\([0-9]+>\\)?\\(\\(?:[a-zA-Z]:\\)?[^:(\t\n]+\\)(\\([0-9]+\\)) \
: \\(?:see declaration\\|\\(?:warnin\\(g\\)\\|[a-z ]+\\) C[0-9]+:\\)"
     2 3 nil (4))
Stefan Monnier's avatar
Stefan Monnier committed
348

349 350 351
    (omake
     ;; "omake -P" reports "file foo changed"
     ;; (useful if you do "cvs up" and want to see what has changed)
352 353 354 355 356 357
     "omake: file \\(.*\\) changed" 1 nil nil nil nil
     ;; FIXME-omake: This tries to prevent reusing pre-existing markers
     ;; for subsequent messages, since those messages's line numbers
     ;; are about another version of the file.
     (0 (progn (compilation--flush-file-structure (match-string 1))
               nil)))
358

Stefan Monnier's avatar
Stefan Monnier committed
359
    (oracle
360 361 362
     "^\\(?:Semantic error\\|Error\\|PCC-[0-9]+:\\).* line \\([0-9]+\\)\
\\(?:\\(?:,\\| at\\)? column \\([0-9]+\\)\\)?\
\\(?:,\\| in\\| of\\)? file \\(.*?\\):?$"
Stefan Monnier's avatar
Stefan Monnier committed
363
     3 1 2)
364

365 366 367
    ;; "during global destruction": This comes out under "use
    ;; warnings" in recent perl when breaking circular references
    ;; during program or thread exit.
Stefan Monnier's avatar
Stefan Monnier committed
368
    (perl
369 370
     " at \\([^ \n]+\\) line \\([0-9]+\\)\\(?:[,.]\\|$\\| \
during global destruction\\.$\\)" 1 2)
Stefan Monnier's avatar
Stefan Monnier committed
371

372 373 374 375
    (php
     "\\(?:Parse\\|Fatal\\) error: \\(.*\\) in \\(.*\\) on line \\([0-9]+\\)"
     2 3 nil nil)

Stefan Monnier's avatar
Stefan Monnier committed
376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392
    (rxp
     "^\\(?:Error\\|Warnin\\(g\\)\\):.*\n.* line \\([0-9]+\\) char\
 \\([0-9]+\\) of file://\\(.+\\)"
     4 2 3 (1))

    (sparc-pascal-file
     "^\\w\\w\\w \\w\\w\\w +[0-3]?[0-9] +[0-2][0-9]:[0-5][0-9]:[0-5][0-9]\
 [12][09][0-9][0-9] +\\(.*\\):$"
     1 nil nil 0)
    (sparc-pascal-line
     "^\\(\\(?:E\\|\\(w\\)\\) +[0-9]+\\) line \\([0-9]+\\) -  "
     nil 3 nil (2) nil (1 (compilation-face '(2))))
    (sparc-pascal-example
     "^ +\\([0-9]+\\) +.*\n\\(\\(?:e\\|\\(w\\)\\) [0-9]+\\)-+"
     nil 1 nil (3) nil (2 (compilation-face '(3))))

    (sun
Stefan Monnier's avatar
Stefan Monnier committed
393
     ": \\(?:ERROR\\|WARNIN\\(G\\)\\|REMAR\\(K\\)\\) \\(?:[[:alnum:] ]+, \\)?\
Stefan Monnier's avatar
Stefan Monnier committed
394 395 396 397
File = \\(.+\\), Line = \\([0-9]+\\)\\(?:, Column = \\([0-9]+\\)\\)?"
     3 4 5 (1 . 2))

    (sun-ada
398
     "^\\([^, \n\t]+\\), line \\([0-9]+\\), char \\([0-9]+\\)[:., (-]" 1 2 3)
Stefan Monnier's avatar
Stefan Monnier committed
399

400
    (watcom
401
     "^[ \t]*\\(\\(?:[a-zA-Z]:\\)?[^:(\t\n]+\\)(\\([0-9]+\\)): ?\
Chong Yidong's avatar
Chong Yidong committed
402 403
\\(?:\\(Error! E[0-9]+\\)\\|\\(Warning! W[0-9]+\\)\\):"
     1 2 nil (4))
404

Stefan Monnier's avatar
Stefan Monnier committed
405 406
    (4bsd
     "\\(?:^\\|::  \\|\\S ( \\)\\(/[^ \n\t()]+\\)(\\([0-9]+\\))\
407 408 409
\\(?:: \\(warning:\\)?\\|$\\| ),\\)" 1 2 nil (3))

    (gcov-file
410
     "^ *-: *\\(0\\):Source:\\(.+\\)$"
411
     2 1 nil 0 nil)
412 413
    (gcov-header
     "^ *-: *\\(0\\):\\(?:Object\\|Graph\\|Data\\|Runs\\|Programs\\):.+$"
414
     nil 1 nil 0 nil)
415 416 417 418 419 420 421 422
    ;; Underlines over all lines of gcov output are too uncomfortable to read.
    ;; However, hyperlinks embedded in the lines are useful.
    ;; So I put default face on the lines; and then put
    ;; compilation-*-face by manually to eliminate the underlines.
    ;; The hyperlinks are still effective.
    (gcov-nomark
     "^ *-: *\\([1-9]\\|[0-9]\\{2,\\}\\):.*$"
     nil 1 nil 0 nil
423 424
     (0 'default)
     (1 compilation-line-face))
425
    (gcov-called-line
426
     "^ *\\([0-9]+\\): *\\([0-9]+\\):.*$"
427
     nil 2 nil 0 nil
428 429
     (0 'default)
     (1 compilation-info-face) (2 compilation-line-face))
430
    (gcov-never-called
431
     "^ *\\(#####\\): *\\([0-9]+\\):.*$"
432
     nil 2 nil 2 nil
433 434
     (0 'default)
     (1 compilation-error-face) (2 compilation-line-face))
435

436
    (perl--Pod::Checker
437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453
     ;; podchecker error messages, per Pod::Checker.
     ;; The style is from the Pod::Checker::poderror() function, eg.
     ;; *** ERROR: Spurious text after =cut at line 193 in file foo.pm
     ;;
     ;; Plus end_pod() can give "at line EOF" instead of a
     ;; number, so for that match "on line N" which is the
     ;; originating spot, eg.
     ;; *** ERROR: =over on line 37 without closing =back at line EOF in file bar.pm
     ;;
     ;; Plus command() can give both "on line N" and "at line N";
     ;; the latter is desired and is matched because the .* is
     ;; greedy.
     ;; *** ERROR: =over on line 1 without closing =back (at head1) at line 3 in file x.pod
     ;;
     "^\\*\\*\\* \\(?:ERROR\\|\\(WARNING\\)\\).* \\(?:at\\|on\\) line \
\\([0-9]+\\) \\(?:.* \\)?in file \\([^ \t\n]+\\)"
     3 2 nil (1))
454
    (perl--Test
455 456 457 458 459 460
     ;; perl Test module error messages.
     ;; Style per the ok() function "$context", eg.
     ;; # Failed test 1 in foo.t at line 6
     ;;
     "^# Failed test [0-9]+ in \\([^ \t\r\n]+\\) at line \\([0-9]+\\)"
     1 2)
461
    (perl--Test2
462
     ;; Or when comparing got/want values, with a "fail #n" if repeated
463
     ;; # Test 2 got: "xx" (t-compilation-perl-2.t at line 10)
464
     ;; # Test 3 got: "xx" (t-compilation-perl-2.t at line 10 fail #2)
465 466 467 468 469 470
     ;;
     ;; And under Test::Harness they're preceded by progress stuff with
     ;; \r and "NOK",
     ;; ... NOK 1# Test 1 got: "1234" (t/foo.t at line 46)
     ;;
     "^\\(.*NOK.*\\)?# Test [0-9]+ got:.* (\\([^ \t\r\n]+\\) at line \
471
\\([0-9]+\\)\\( fail #[0-9]+\\)?)"
472
     2 3)
473
    (perl--Test::Harness
474 475 476 477 478 479 480 481 482 483
     ;; perl Test::Harness output, eg.
     ;; NOK 1# Test 1 got: "1234" (t/foo.t at line 46)
     ;;
     ;; Test::Harness is slightly designed for tty output, since
     ;; it prints CRs to overwrite progress messages, but if you
     ;; run it in with M-x compile this pattern can at least step
     ;; through the failures.
     ;;
     "^.*NOK.* \\([^ \t\r\n]+\\) at line \\([0-9]+\\)"
     1 2)
484
    (weblint
485 486 487 488 489 490 491 492 493 494 495 496 497
     ;; The style comes from HTML::Lint::Error::as_string(), eg.
     ;; index.html (13:1) Unknown element <fdjsk>
     ;;
     ;; The pattern only matches filenames without spaces, since that
     ;; should be usual and should help reduce the chance of a false
     ;; match of a message from some unrelated program.
     ;;
     ;; This message style is quite close to the "ibm" entry which is
     ;; for IBM C, though that ibm bit doesn't put a space after the
     ;; filename.
     ;;
     "^\\([^ \t\r\n(]+\\) (\\([0-9]+\\):\\([0-9]+\\)) "
     1 2 3)
498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520

    ;; Guile compilation yields file-headers in the following format:
    ;;
    ;;   In sourcefile.scm:
    ;;
    ;; We need to catch those, but we also need to be aware that Emacs
    ;; byte-compilation yields compiler headers in similar form of
    ;; those:
    ;;
    ;;   In toplevel form:
    ;;   In end of data:
    ;;
    ;; We want to catch the Guile file-headers but not the Emacs
    ;; byte-compilation headers, because that will cause next-error
    ;; and prev-error to break, because the files "toplevel form" and
    ;; "end of data" does not exist.
    ;;
    ;; To differentiate between these two cases, we require that the
    ;; file-match must always contain an extension.
    ;;
    ;; We should also only treat this as "info", not "error", because
    ;; we do not know what lines will follow.
    (guile-file "^In \\(.+\\..+\\):\n" 1 nil nil 0)
521
    (guile-line "^ *\\([0-9]+\\): *\\([0-9]+\\)" nil 1 2)
522
    )
Stefan Monnier's avatar
Stefan Monnier committed
523 524 525
  "Alist of values for `compilation-error-regexp-alist'.")

(defcustom compilation-error-regexp-alist
526
  (mapcar #'car compilation-error-regexp-alist-alist)
Richard M. Stallman's avatar
Richard M. Stallman committed
527
  "Alist that specifies how to match errors in compiler output.
528
On GNU and Unix, any string is a valid filename, so these
Stefan Monnier's avatar
Stefan Monnier committed
529 530 531 532 533 534
matchers must make some common sense assumptions, which catch
normal cases.  A shorter list will be lighter on resource usage.

Instead of an alist element, you can use a symbol, which is
looked up in `compilation-error-regexp-alist-alist'.  You can see
the predefined symbols and their effects in the file
Stefan Monnier's avatar
Stefan Monnier committed
535
`etc/compilation.txt' (linked below if you are customizing this).
Stefan Monnier's avatar
Stefan Monnier committed
536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551

Each elt has the form (REGEXP FILE [LINE COLUMN TYPE HYPERLINK
HIGHLIGHT...]).  If REGEXP matches, the FILE'th subexpression
gives the file name, and the LINE'th subexpression gives the line
number.  The COLUMN'th subexpression gives the column number on
that line.

If FILE, LINE or COLUMN are nil or that index didn't match, that
information is not present on the matched line.  In that case the
file name is assumed to be the same as the previous one in the
buffer, line number defaults to 1 and column defaults to
beginning of line's indentation.

FILE can also have the form (FILE FORMAT...), where the FORMATs
\(e.g. \"%s.c\") will be applied in turn to the recognized file
name, until a file of that name is found.  Or FILE can also be a
552
function that returns (FILENAME) or (RELATIVE-FILENAME . DIRNAME).
553 554
In the former case, FILENAME may be relative or absolute, or it may
be a buffer.
Stefan Monnier's avatar
Stefan Monnier committed
555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571

LINE can also be of the form (LINE . END-LINE) meaning a range
of lines.  COLUMN can also be of the form (COLUMN . END-COLUMN)
meaning a range of columns starting on LINE and ending on
END-LINE, if that matched.

TYPE is 2 or nil for a real error or 1 for warning or 0 for info.
TYPE can also be of the form (WARNING . INFO).  In that case this
will be equivalent to 1 if the WARNING'th subexpression matched
or else equivalent to 0 if the INFO'th subexpression matched.
See `compilation-error-face', `compilation-warning-face',
`compilation-info-face' and `compilation-skip-threshold'.

What matched the HYPERLINK'th subexpression has `mouse-face' and
`compilation-message-face' applied.  If this is nil, the text
matched by the whole REGEXP becomes the hyperlink.

572 573
Additional HIGHLIGHTs take the shape (SUBMATCH FACE), where
SUBMATCH is the number of a submatch and FACE is an expression
574 575 576 577
which evaluates to a face name (a symbol or string).
Alternatively, FACE can evaluate to a property list of the
form (face FACE PROP1 VAL1 PROP2 VAL2 ...), in which case all the
listed text properties PROP# are given values VAL# as well."
Glenn Morris's avatar
Glenn Morris committed
578 579
  :type '(repeat (choice (symbol :tag "Predefined symbol")
			 (sexp :tag "Error specification")))
Stefan Monnier's avatar
Stefan Monnier committed
580
  :link `(file-link :tag "example file"
581
		    ,(expand-file-name "compilation.txt" data-directory)))
Richard M. Stallman's avatar
Richard M. Stallman committed
582

583
;;;###autoload(put 'compilation-directory 'safe-local-variable 'stringp)
584 585 586
(defvar compilation-directory nil
  "Directory to restore to when doing `recompile'.")

Stefan Monnier's avatar
Stefan Monnier committed
587
(defvar compilation-directory-matcher
588
  '("\\(?:Entering\\|Leavin\\(g\\)\\) directory [`']\\(.+\\)'$" (2 . 1))
Stefan Monnier's avatar
Stefan Monnier committed
589
  "A list for tracking when directories are entered or left.
590
If nil, do not track directories, e.g. if all file names are absolute.  The
Stefan Monnier's avatar
Stefan Monnier committed
591 592 593 594 595 596 597 598 599 600
first element is the REGEXP matching these messages.  It can match any number
of variants, e.g. different languages.  The remaining elements are all of the
form (DIR .  LEAVE).  If for any one of these the DIR'th subexpression
matches, that is a directory name.  If LEAVE is nil or the corresponding
LEAVE'th subexpression doesn't match, this message is about going into another
directory.  If it does match anything, this message is about going back to the
directory we were in before the last entering message.  If you change this,
you may also want to change `compilation-page-delimiter'.")

(defvar compilation-page-delimiter
601
  "^\\(?:\f\\|.*\\(?:Entering\\|Leaving\\) directory [`'].+'\n\\)+"
Stefan Monnier's avatar
Stefan Monnier committed
602 603 604
  "Value of `page-delimiter' in Compilation mode.")

(defvar compilation-mode-font-lock-keywords
605
   '(;; configure output lines.
Stefan Monnier's avatar
Stefan Monnier committed
606 607
     ("^[Cc]hecking \\(?:[Ff]or \\|[Ii]f \\|[Ww]hether \\(?:to \\)?\\)?\\(.+\\)\\.\\.\\. *\\(?:(cached) *\\)?\\(\\(yes\\(?: .+\\)?\\)\\|no\\|\\(.*\\)\\)$"
      (1 font-lock-variable-name-face)
608
      (2 (compilation-face '(4 . 3))))
Stefan Monnier's avatar
Stefan Monnier committed
609
     ;; Command output lines.  Recognize `make[n]:' lines too.
Stefan Monnier's avatar
Stefan Monnier committed
610
     ("^\\([[:alnum:]_/.+-]+\\)\\(\\[\\([0-9]+\\)\\]\\)?[ \t]*:"
Stefan Monnier's avatar
Stefan Monnier committed
611
      (1 font-lock-function-name-face) (3 compilation-line-face nil t))
612
     (" --?o\\(?:utfile\\|utput\\)?[= ]\\(\\S +\\)" . 1)
613
     ("^Compilation \\(finished\\).*"
614
      (0 '(face nil compilation-message nil help-echo nil mouse-face nil) t)
615
      (1 compilation-info-face))
616
     ("^Compilation \\(exited abnormally\\|interrupt\\|killed\\|terminated\\|segmentation fault\\)\\(?:.*with code \\([0-9]+\\)\\)?.*"
617
      (0 '(face nil compilation-message nil help-echo nil mouse-face nil) t)
618 619
      (1 compilation-error-face)
      (2 compilation-error-face nil t)))
Stefan Monnier's avatar
Stefan Monnier committed
620 621
   "Additional things to highlight in Compilation mode.
This gets tacked on the end of the generated expressions.")
622

623 624 625 626 627 628 629
(defvar compilation-highlight-regexp t
  "Regexp matching part of visited source lines to highlight temporarily.
Highlight entire line if t; don't highlight source lines if nil.")

(defvar compilation-highlight-overlay nil
  "Overlay used to temporarily highlight compilation matches.")

630
(defcustom compilation-error-screen-columns t
631
  "If non-nil, column numbers in error messages are screen columns.
632 633 634 635
Otherwise they are interpreted as character positions, with
each character occupying one column.
The default is to use screen columns, which requires that the compilation
program and Emacs agree about the display width of the characters,
Glenn Morris's avatar
Glenn Morris committed
636 637 638 639
especially the TAB character.
If this is buffer-local in the destination buffer, Emacs obeys
that value, otherwise it uses the value in the *compilation*
buffer.  This enables a major-mode to specify its own value."
640 641 642
  :type 'boolean
  :version "20.4")

643
(defcustom compilation-read-command t
644
  "Non-nil means \\[compile] reads the compilation command to use.
645 646 647 648 649 650
Otherwise, \\[compile] just uses the value of `compile-command'.

Note that changing this to nil may be a security risk, because a
file might define a malicious `compile-command' as a file local
variable, and you might not notice.  Therefore, `compile-command'
is considered unsafe if this variable is nil."
651
  :type 'boolean)
652

653
;;;###autoload
654
(defcustom compilation-ask-about-save t
655
  "Non-nil means \\[compile] asks which buffers to save before compiling.
656
Otherwise, it saves all modified buffers without asking."
657
  :type 'boolean)
658

659 660 661 662 663 664 665 666 667 668 669 670
(defcustom compilation-save-buffers-predicate nil
  "The second argument (PRED) passed to `save-some-buffers' before compiling.
E.g., one can set this to
  (lambda ()
    (string-prefix-p my-compilation-root (file-truename (buffer-file-name))))
to limit saving to files located under `my-compilation-root'.
Note, that, in general, `compilation-directory' cannot be used instead
of `my-compilation-root' here."
  :type '(choice
          (const :tag "Default (save all file-visiting buffers)" nil)
          (const :tag "Save all buffers" t)
          function)
671
  :version "24.1")
672

Roland McGrath's avatar
Roland McGrath committed
673
;;;###autoload
674
(defcustom compilation-search-path '(nil)
675
  "List of directories to search for source files named in error messages.
Roland McGrath's avatar
Roland McGrath committed
676
Elements should be directory names, not file names of directories.
677
The value nil as an element means to try the default directory."
678
  :type '(repeat (choice (const :tag "Default" nil)
679
			 (string :tag "Directory"))))
Richard M. Stallman's avatar
Richard M. Stallman committed
680

681
;;;###autoload
682
(defcustom compile-command (purecopy "make -k ")
683
  "Last shell command used to do a compilation; default for next compilation.
Richard M. Stallman's avatar
Richard M. Stallman committed
684 685 686 687

Sometimes it is useful for files to supply local values for this variable.
You might also use mode hooks to specify it in certain modes, like this:

688
    (add-hook \\='c-mode-hook
689 690 691
       (lambda ()
	 (unless (or (file-exists-p \"makefile\")
		     (file-exists-p \"Makefile\"))
692
	   (set (make-local-variable \\='compile-command)
693
		(concat \"make -k \"
694 695
			(if buffer-file-name
			  (shell-quote-argument
696 697 698
			    (file-name-sans-extension buffer-file-name))))))))

It's often useful to leave a space at the end of the value."
699
  :type 'string)
700
;;;###autoload(put 'compile-command 'safe-local-variable (lambda (a) (and (stringp a) (or (not (boundp 'compilation-read-command)) compilation-read-command))))
Richard M. Stallman's avatar
Richard M. Stallman committed
701

702
;;;###autoload
703
(defcustom compilation-disable-input nil
704
  "If non-nil, send end-of-file as compilation process input.
705
This only affects platforms that support asynchronous processes (see
706
`start-process'); synchronous compilation processes never accept input."
707 708 709
  :type 'boolean
  :version "22.1")

Stefan Monnier's avatar
Stefan Monnier committed
710 711
;; A weak per-compilation-buffer hash indexed by (FILENAME . DIRECTORY).  Each
;; value is a FILE-STRUCTURE as described above, with the car eq to the hash
Juanma Barranquero's avatar
Juanma Barranquero committed
712
;; key.  This holds the tree seen from root, for storing new nodes.
Stefan Monnier's avatar
Stefan Monnier committed
713 714 715
(defvar compilation-locs ())

(defvar compilation-debug nil
716
  "Set this to t before creating a *compilation* buffer.
Stefan Monnier's avatar
Stefan Monnier committed
717 718
Then every error line will have a debug text property with the matcher that
fit this line and the match data.  Use `describe-text-properties'.")
Roland McGrath's avatar
Roland McGrath committed
719

720 721
(defvar compilation-exit-message-function nil "\
If non-nil, called when a compilation process dies to return a status message.
722 723 724
This should be a function of three arguments: process status, exit status,
and exit message; it returns a cons (MESSAGE . MODELINE) of the strings to
write into the compilation buffer, and to put in its mode line.")
725

726 727
(defcustom compilation-environment nil
  "List of environment variables for compilation to inherit.
728 729
Each element should be a string of the form ENVVARNAME=VALUE.
This list is temporarily prepended to `process-environment' prior to
730 731 732 733
starting the compilation process."
  :type '(repeat (string :tag "ENVVARNAME=VALUE"))
  :options '(("LANG=C"))
  :version "24.1")
734

735 736 737
;; History of compile commands.
(defvar compile-history nil)

738
(defface compilation-error
739
  '((t :inherit error))
740 741 742
  "Face used to highlight compiler errors."
  :version "22.1")

743
(defface compilation-warning
744
  '((t :inherit warning))
Stefan Monnier's avatar
Stefan Monnier committed
745
  "Face used to highlight compiler warnings."
746
  :version "22.1")
Stefan Monnier's avatar
Stefan Monnier committed
747

748
(defface compilation-info
749
  '((t :inherit success))
750
  "Face used to highlight compiler information."
751
  :version "22.1")
Stefan Monnier's avatar
Stefan Monnier committed
752

753 754 755 756 757 758 759 760 761
;; The next three faces must be able to stand out against the
;; `mode-line' and `mode-line-inactive' faces.

(defface compilation-mode-line-fail
  '((default :inherit compilation-error)
    (((class color) (min-colors 16)) (:foreground "Red1" :weight bold))
    (((class color) (min-colors 8)) (:foreground "red"))
    (t (:inverse-video t :weight bold)))
  "Face for Compilation mode's \"error\" mode line indicator."
762
  :version "24.3")
763 764 765 766

(defface compilation-mode-line-run
  '((t :inherit compilation-warning))
  "Face for Compilation mode's \"running\" mode line indicator."
767
  :version "24.3")
768 769 770 771 772 773 774 775

(defface compilation-mode-line-exit
  '((default :inherit compilation-info)
    (((class color) (min-colors 16))
     (:foreground "ForestGreen" :weight bold))
    (((class color)) (:foreground "green" :weight bold))
    (t (:weight bold)))
  "Face for Compilation mode's \"exit\" mode line indicator."
776
  :version "24.3")
777

778
(defface compilation-line-number
779
  '((t :inherit font-lock-keyword-face))
780
  "Face for displaying line numbers in compiler messages."
781 782 783
  :version "22.1")

(defface compilation-column-number
784
  '((t :inherit font-lock-doc-face))
785
  "Face for displaying column numbers in compiler messages."
786 787
  :version "22.1")

788
(defcustom compilation-message-face 'underline
Stefan Monnier's avatar
Stefan Monnier committed
789 790 791
  "Face name to use for whole messages.
Faces `compilation-error-face', `compilation-warning-face',
`compilation-info-face', `compilation-line-face' and
792 793 794
`compilation-column-face' get prepended to this, when applicable."
  :type 'face
  :version "22.1")
Stefan Monnier's avatar
Stefan Monnier committed
795

796
(defvar compilation-error-face 'compilation-error
Stefan Monnier's avatar
Stefan Monnier committed
797 798
  "Face name to use for file name in error messages.")

799
(defvar compilation-warning-face 'compilation-warning
Stefan Monnier's avatar
Stefan Monnier committed
800 801
  "Face name to use for file name in warning messages.")

802
(defvar compilation-info-face 'compilation-info
Stefan Monnier's avatar
Stefan Monnier committed
803 804
  "Face name to use for file name in informational messages.")

805
(defvar compilation-line-face 'compilation-line-number
806
  "Face name to use for line numbers in compiler messages.")
Stefan Monnier's avatar
Stefan Monnier committed
807

808
(defvar compilation-column-face 'compilation-column-number
809
  "Face name to use for column numbers in compiler messages.")
Stefan Monnier's avatar
Stefan Monnier committed
810 811 812

;; same faces as dired uses
(defvar compilation-enter-directory-face 'font-lock-function-name-face
813
  "Face name to use for entering directory messages.")
Stefan Monnier's avatar
Stefan Monnier committed
814

815
(defvar compilation-leave-directory-face 'font-lock-builtin-face
816
  "Face name to use for leaving directory messages.")
Stefan Monnier's avatar
Stefan Monnier committed
817

818 819
;; Used for compatibility with the old compile.el.
(defvar compilation-parse-errors-function nil)
820 821
(make-obsolete-variable 'compilation-parse-errors-function
			'compilation-error-regexp-alist "24.1")
822

823
(defcustom compilation-auto-jump-to-first-error nil
824
  "If non-nil, automatically jump to the first error during compilation."
825 826
  :type 'boolean
  :version "23.1")
827 828 829 830 831

(defvar compilation-auto-jump-to-next nil
  "If non-nil, automatically jump to the next error encountered.")
(make-variable-buffer-local 'compilation-auto-jump-to-next)

832 833 834
;; (defvar compilation-buffer-modtime nil
;;   "The buffer modification time, for buffers not associated with files.")
;; (make-variable-buffer-local 'compilation-buffer-modtime)
835 836

(defvar compilation-skip-to-next-location t
837
  "If non-nil, skip multiple error messages for the same source location.")
838 839 840 841 842 843 844

(defcustom compilation-skip-threshold 1
  "Compilation motion commands skip less important messages.
The value can be either 2 -- skip anything less than error, 1 --
skip anything less than warning or 0 -- don't skip any messages.
Note that all messages not positively identified as warning or
info, are considered errors."
845 846 847
  :type '(choice (const :tag "Skip warnings and info" 2)
		 (const :tag "Skip info" 1)
		 (const :tag "No skip" 0))
848 849
  :version "22.1")

850 851 852 853 854 855 856 857 858 859
(defun compilation-set-skip-threshold (level)
  "Switch the `compilation-skip-threshold' level."
  (interactive
   (list
    (mod (if current-prefix-arg
             (prefix-numeric-value current-prefix-arg)
           (1+ compilation-skip-threshold))
         3)))
  (setq compilation-skip-threshold level)
  (message "Skipping %s"
860
           (pcase compilation-skip-threshold
861 862 863 864
             (0 "Nothing")
             (1 "Info messages")
             (2 "Warnings and info"))))

865 866 867 868 869 870 871 872
(defcustom compilation-skip-visited nil
  "Compilation motion commands skip visited messages if this is t.
Visited messages are ones for which the file, line and column have been jumped
to from the current content in the current compilation buffer, even if it was
from a different message."
  :type 'boolean
  :version "22.1")

873 874 875 876
(defun compilation-type (type)
  (or (and (car type) (match-end (car type)) 1)
      (and (cdr type) (match-end (cdr type)) 0)
      2))
Stefan Monnier's avatar
Stefan Monnier committed
877

878 879 880 881 882 883 884 885 886 887
(defun compilation-face (type)
  (let ((typ (compilation-type type)))
    (cond
     ((eq typ 1)
      compilation-warning-face)
     ((eq typ 0)
      compilation-info-face)
     ((eq typ 2)
      compilation-error-face))))

888 889 890 891
;;   LOC (or location) is a list of (COLUMN LINE FILE-STRUCTURE nil nil)

;; COLUMN and LINE are numbers parsed from an error message.  COLUMN and maybe
;; LINE will be nil for a message that doesn't contain them.  Then the
892
;; location refers to an indented beginning of line or beginning of file.
893 894 895 896 897 898 899 900 901 902 903
;; Once any location in some file has been jumped to, the list is extended to
;; (COLUMN LINE FILE-STRUCTURE MARKER TIMESTAMP . VISITED)
;; for all LOCs pertaining to that file.
;; MARKER initially points to LINE and COLUMN in a buffer visiting that file.
;; Being a marker it sticks to some text, when the buffer grows or shrinks
;; before that point.  VISITED is t if we have jumped there, else nil.
;; FIXME-omake: TIMESTAMP was used to try and handle "incremental compilation":
;; `omake -P' polls filesystem for changes and recompiles when a file is
;; modified using the same *compilation* buffer. this necessitates
;; re-parsing markers.

904
;; (cl-defstruct (compilation--loc
905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926
;;             (:constructor nil)
;;             (:copier nil)
;;             (:constructor compilation--make-loc
;;                           (file-struct line col marker))
;;             (:conc-name compilation--loc->))
;;   col line file-struct marker timestamp visited)

;; FIXME: We don't use a defstruct because of compilation-assq which looks up
;; and creates part of the LOC (only the first cons cell containing the COL).

(defmacro compilation--make-cdrloc (line file-struct marker)
  `(list ,line ,file-struct ,marker nil))
(defmacro compilation--loc->col (loc) `(car ,loc))
(defmacro compilation--loc->line (loc) `(cadr ,loc))
(defmacro compilation--loc->file-struct (loc) `(nth 2 ,loc))
(defmacro compilation--loc->marker (loc) `(nth 3 ,loc))
;; (defmacro compilation--loc->timestamp (loc) `(nth 4 ,loc))
(defmacro compilation--loc->visited (loc) `(nthcdr 5 ,loc))

;;   FILE-STRUCTURE is a list of
;;   ((FILENAME DIRECTORY) FORMATS (LINE LOC ...) ...)

927 928 929 930 931
;; FILENAME is a string parsed from an error message, or the buffer which was
;; compiled.  DIRECTORY is a string obtained by following directory change
;; messages.  DIRECTORY will be nil for an absolute filename or a buffer.
;; FORMATS is a list of formats to apply to FILENAME if a file of that name
;; can't be found.
932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953
;; The rest of the list is an alist of elements with LINE as key.  The keys
;; are either nil or line numbers.  If present, nil comes first, followed by
;; the numbers in decreasing order.  The LOCs for each line are again an alist
;; ordered the same way.  Note that the whole file structure is referenced in
;; every LOC.

(defmacro compilation--make-file-struct (file-spec formats &optional loc-tree)
  `(cons ,file-spec (cons ,formats ,loc-tree)))
(defmacro compilation--file-struct->file-spec (fs) `(car ,fs))
(defmacro compilation--file-struct->formats (fs) `(cadr ,fs))
;; The FORMATS field plays the role of ANCHOR in the loc-tree.
(defmacro compilation--file-struct->loc-tree (fs) `(cdr ,fs))

;;   MESSAGE is a list of (LOC TYPE END-LOC)

;; TYPE is 0 for info or 1 for warning if the message matcher identified it as
;; such, 2 otherwise (for a real error).  END-LOC is a LOC pointing to the
;; other end, if the parsed message contained a range.  If the end of the
;; range didn't specify a COLUMN, it defaults to -1, meaning end of line.
;; These are the value of the `compilation-message' text-properties in the
;; compilation buffer.

954
(cl-defstruct (compilation--message
955 956 957 958 959 960 961
            (:constructor nil)
            (:copier nil)
            ;; (:type list)                ;Old representation.
            (:constructor compilation--make-message (loc type end-loc))
            (:conc-name compilation--message->))
  loc type end-loc)

962 963 964
(defvar compilation--previous-directory-cache nil
  "A pair (POS . RES) caching the result of previous directory search.
Basically, this pair says that calling
965
   (previous-single-property-change POS \\='compilation-directory)
966 967
returned RES, i.e. there is no change of `compilation-directory' between
POS and RES.")
968
(make-variable-buffer-local 'compilation--previous-directory-cache)
969

970
(defun compilation--flush-directory-cache (start _end)
971 972 973 974
  (cond
   ((or (not compilation--previous-directory-cache)
        (<= (car compilation--previous-directory-cache) start)))
   ((or (not (cdr compilation--previous-directory-cache))
975
	(null (marker-buffer (cdr compilation--previous-directory-cache)))
976 977 978 979
        (<= (cdr compilation--previous-directory-cache) start))
    (set-marker (car compilation--previous-directory-cache) start))
   (t (setq compilation--previous-directory-cache nil))))

980
(defun compilation--previous-directory (pos)
981
  "Like (previous-single-property-change POS \\='compilation-directory), but faster."
982 983 984
  ;; This avoids an N² behavior when there's no/few compilation-directory
  ;; entries, in which case each call to previous-single-property-change
  ;; ends up having to walk very far back to find the last change.
985 986
  (if (and compilation--previous-directory-cache
           (< pos (car compilation--previous-directory-cache))
987 988
           (or (null (cdr compilation--previous-directory-cache))
               (< (cdr compilation--previous-directory-cache) pos)))
989 990
      ;; No need to call previous-single-property-change.
      (cdr compilation--previous-directory-cache)
991

992 993 994 995 996
    (let* ((cache (and compilation--previous-directory-cache
                       (<= (car compilation--previous-directory-cache) pos)
                       (car compilation--previous-directory-cache)))
           (prev
            (previous-single-property-change
997 998 999 1000 1001 1002 1003 1004
             pos 'compilation-directory nil cache))
           (res
            (cond
             ((null cache)
              (setq compilation--previous-directory-cache
                    (cons (copy-marker pos) (if prev (copy-marker prev))))
              prev)
             ((and prev (= prev cache))
1005
              (set-marker (car compilation--previous-directory-cache) pos)
1006 1007
              (cdr compilation--previous-directory-cache))
             (t
1008 1009 1010
              (set-marker cache pos)
              (setcdr compilation--previous-directory-cache
                      (copy-marker prev))
1011 1012
              prev))))
      (if (markerp res) (marker-position res) res))))
1013

1014
;; Internal function for calculating the text properties of a directory
1015 1016
;; change message.  The compilation-directory property is important, because it
;; is the stack of nested enter-messages.  Relative filenames on the following
1017
;; lines are relative to the top of the stack.
Stefan Monnier's avatar
Stefan Monnier committed
1018 1019 1020
(defun compilation-directory-properties (idx leave)
  (if leave (setq leave (match-end leave)))
  ;; find previous stack, and push onto it, or if `leave' pop it
1021
  (let ((dir (compilation--previous-directory (match-beginning 0))))
1022 1023
    (setq dir (if dir (or (get-text-property (1- dir) 'compilation-directory)
			  (get-text-property dir 'compilation-directory))))
1024 1025 1026
    `(font-lock-face ,(if leave
                          compilation-leave-directory-face
                        compilation-enter-directory-face)
1027 1028 1029 1030
      compilation-directory ,(if leave
                                 (or (cdr dir)
                                     '(nil)) ; nil only isn't a property-change
                               (cons (match-string-no-properties idx) dir))
1031 1032 1033
      ;; Place a `compilation-message' everywhere we change text-properties
      ;; so compilation--remove-properties can know what to remove.
      compilation-message ,(compilation--make-message nil 0 nil)
Stefan Monnier's avatar
Stefan Monnier committed
1034
      mouse-face highlight
Stefan Monnier's avatar
Stefan Monnier committed
1035
      keymap compilation-button-map
1036
      help-echo "mouse-2: visit destination directory")))
Stefan Monnier's avatar
Stefan Monnier committed
1037

Juanma Barranquero's avatar
Juanma Barranquero committed
1038
;; Data type `reverse-ordered-alist' retriever.  This function retrieves the
Stefan Monnier's avatar
Stefan Monnier committed
1039 1040 1041 1042
;; KEY element from the ALIST, creating it in the right position if not already
;; present. ALIST structure is
;; '(ANCHOR (KEY1 ...) (KEY2 ...)... (KEYn ALIST ...))
;; ANCHOR is ignored, but necessary so that elements can be inserted.  KEY1
Juanma Barranquero's avatar
Juanma Barranquero committed
1043
;; may be nil.  The other KEYs are ordered backwards so that growing line
Stefan Monnier's avatar
Stefan Monnier committed
1044 1045
;; numbers can be inserted in front and searching can abort after half the
;; list on average.
Stefan Monnier's avatar
Stefan Monnier committed
1046
(eval-when-compile		    ;Don't keep it at runtime if not needed.
Stefan Monnier's avatar
Stefan Monnier committed
1047 1048 1049 1050 1051 1052 1053 1054 1055 1056
(defmacro compilation-assq (key alist)
  `(let* ((l1 ,alist)
	  (l2 (cdr l1)))
     (car (if (if (null ,key)
		  (if l2 (null (caar l2)))
		(while (if l2 (if (caar l2) (< ,key (caar l2)) t))
		  (setq l1 l2
			l2 (cdr l1)))
		(if l2 (eq ,key (caar l2))))
	      l2
Stefan Monnier's avatar
Stefan Monnier committed
1057
	    (setcdr l1 (cons (list ,key) l2)))))))
Stefan Monnier's avatar
Stefan Monnier committed
1058

1059 1060 1061
(defun compilation-auto-jump (buffer pos)
  (with-current-buffer buffer
    (goto-char pos)
1062 1063
    (let ((win (get-buffer-window buffer 0)))
      (if win (set-window-point win pos)))
Juri Linkov's avatar
Juri Linkov committed
1064
    (if compilation-auto-jump-to-first-error
1065
	(compile-goto-error))))
Stefan Monnier's avatar
Stefan Monnier committed
1066 1067 1068 1069

;; This function is the central driver, called when font-locking to gather
;; all information needed to later jump to corresponding source code.
;; Return a property list with all meta information on this error location.
1070

Stefan Monnier's avatar
Stefan Monnier committed
1071
(defun compilation-error-properties (file line end-line col end-col type fmt)
1072 1073
  (unless (text-property-not-all (match-beginning 0) (point)
                                 'compilation-message nil)
Stefan Monnier's avatar
Stefan Monnier committed
1074
    (if file
1075 1076 1077 1078
        (when (stringp
               (setq file (if (functionp file) (funcall file)
                            (match-string-no-properties file))))
	  (let ((dir
Stefan Monnier's avatar
Stefan Monnier committed
1079
	    (unless (file-name-absolute-p file)
1080 1081
                   (let ((pos (compilation--previous-directory
                               (match-beginning 0))))
1082 1083 1084
                     (when pos
                       (or (get-text-property (1- pos) 'compilation-directory)
                           (get-text-property pos 'compilation-directory)))))))
1085
	    (setq file (cons file (car dir)))))
Stefan Monnier's avatar
Stefan Monnier committed
1086
      ;; This message didn't mention one, get it from previous
1087 1088
      (let ((prev-pos
	     ;; Find the previous message.
1089
	     (previous-single-property-change (point) 'compilation-message)))
1090 1091 1092
	(if prev-pos
	    ;; Get the file structure that belongs to it.
	    (let* ((prev
1093 1094
		    (or (get-text-property (1- prev-pos) 'compilation-message)
			(get-text-property prev-pos 'compilation-message)))
1095 1096 1097 1098 1099
		   (prev-file-struct
		    (and prev
			 (compilation--loc->file-struct
			  (compilation--message->loc prev)))))

1100
	      ;; Construct FILE . DIR from that.
1101 1102 1103
	      (if prev-file-struct
		  (setq file (cons (caar prev-file-struct)
				   (cadr (car prev-file-struct)))))))
1104 1105
	(unless file
	  (setq file '("*unknown*")))))
Stefan Monnier's avatar
Stefan Monnier committed
1106 1107 1108 1109 1110 1111 1112 1113
    ;; All of these fields are optional, get them only if we have an index, and
    ;; it matched some part of the message.
    (and line
	 (setq line (match-string-no-properties line))
	 (setq line (string-to-number line)))
    (and end-line
	 (setq end-line (match-string-no-properties end-line))
	 (setq end-line (string-to-number end-line)))
1114 1115 1116 1117 1118
    (if col
        (if (functionp col)
            (setq col (funcall col))
          (and
           (setq col (match-string-no-properties col))
1119
           (setq col (string-to-number col)))))
1120 1121 1122
    (if (and end-col (functionp end-col))
        (setq end-col (funcall end-col))
      (if (and end-col (setq end-col (match-string-no-properties end-col)))
1123
          (setq end-col (- (string-to-number end-col) -1))
1124
        (if end-line (setq end-col -1))))
1125
    (if (consp type)			; not a static type, check what it is.
Stefan Monnier's avatar
Stefan Monnier committed
1126 1127 1128
	(setq type (or (and (car type) (match-end (car type)) 1)
		       (and (cdr type) (match-end (cdr type)) 0)
		       2)))
1129 1130 1131 1132 1133 1134 1135

    (when (and compilation-auto-jump-to-next
               (>= type compilation-skip-threshold))
      (kill-local-variable 'compilation-auto-jump-to-next)
      (run-with-timer 0 nil 'compilation-auto-jump
                      (current-buffer) (match-beginning 0)))

1136 1137
    (compilation-internal-error-properties
     file line end-line col end-col type fmt)))
1138