| 1 | ;;; compile.el --- run compiler as inferior of Emacs, parse error messages.
 | 
|---|
| 2 | 
 | 
|---|
| 3 | ;; Copyright (C) 1985, 86, 87, 93, 94 Free Software Foundation, Inc.
 | 
|---|
| 4 | 
 | 
|---|
| 5 | ;; Author: Roland McGrath <roland@prep.ai.mit.edu>
 | 
|---|
| 6 | ;; Maintainer: FSF
 | 
|---|
| 7 | ;; Keywords: tools, processes
 | 
|---|
| 8 | 
 | 
|---|
| 9 | ;; This file is part of GNU Emacs.
 | 
|---|
| 10 | 
 | 
|---|
| 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 | 
 | 
|---|
| 16 | ;; GNU Emacs is distributed in the hope that it will be useful,
 | 
|---|
| 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
 | 
|---|
| 22 | ;; along with GNU Emacs; see the file COPYING.  If not, write to
 | 
|---|
| 23 | ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
|---|
| 24 | 
 | 
|---|
| 25 | ;;; Commentary:
 | 
|---|
| 26 | 
 | 
|---|
| 27 | ;; This package provides the compile and grep facilities documented in
 | 
|---|
| 28 | ;; the Emacs user's manual.
 | 
|---|
| 29 | 
 | 
|---|
| 30 | ;;; Code:
 | 
|---|
| 31 | 
 | 
|---|
| 32 | ;;;###autoload
 | 
|---|
| 33 | (defvar compilation-mode-hook nil
 | 
|---|
| 34 |   "*List of hook functions run by `compilation-mode' (see `run-hooks').")
 | 
|---|
| 35 | 
 | 
|---|
| 36 | ;;;###autoload
 | 
|---|
| 37 | (defconst compilation-window-height nil
 | 
|---|
| 38 |   "*Number of lines in a compilation window.  If nil, use Emacs default.")
 | 
|---|
| 39 | 
 | 
|---|
| 40 | (defvar compilation-error-list nil
 | 
|---|
| 41 |   "List of error message descriptors for visiting erring functions.
 | 
|---|
| 42 | Each error descriptor is a cons (or nil).  Its car is a marker pointing to
 | 
|---|
| 43 | an error message.  If its cdr is a marker, it points to the text of the
 | 
|---|
| 44 | line the message is about.  If its cdr is a cons, it is a list
 | 
|---|
| 45 | \(\(DIRECTORY . FILE\) LINE [COLUMN]\).  Or its cdr may be nil if that
 | 
|---|
| 46 | error is not interesting.
 | 
|---|
| 47 | 
 | 
|---|
| 48 | The value may be t instead of a list; this means that the buffer of
 | 
|---|
| 49 | error messages should be reparsed the next time the list of errors is wanted.
 | 
|---|
| 50 | 
 | 
|---|
| 51 | Some other commands (like `diff') use this list to control the error
 | 
|---|
| 52 | message tracking facilites; if you change its structure, you should make
 | 
|---|
| 53 | sure you also change those packages.  Perhaps it is better not to change
 | 
|---|
| 54 | it at all.")
 | 
|---|
| 55 | 
 | 
|---|
| 56 | (defvar compilation-old-error-list nil
 | 
|---|
| 57 |   "Value of `compilation-error-list' after errors were parsed.")
 | 
|---|
| 58 | 
 | 
|---|
| 59 | (defvar compilation-parse-errors-function 'compilation-parse-errors 
 | 
|---|
| 60 |   "Function to call to parse error messages from a compilation.
 | 
|---|
| 61 | It takes args LIMIT-SEARCH and FIND-AT-LEAST.
 | 
|---|
| 62 | If LIMIT-SEARCH is non-nil, don't bother parsing past that location.
 | 
|---|
| 63 | If FIND-AT-LEAST is non-nil, don't bother parsing after finding that 
 | 
|---|
| 64 | many new errors.
 | 
|---|
| 65 | It should read in the source files which have errors and set
 | 
|---|
| 66 | `compilation-error-list' to a list with an element for each error message
 | 
|---|
| 67 | found.  See that variable for more info.")
 | 
|---|
| 68 | 
 | 
|---|
| 69 | ;;;###autoload
 | 
|---|
| 70 | (defvar compilation-buffer-name-function nil
 | 
|---|
| 71 |   "Function to compute the name of a compilation buffer.
 | 
|---|
| 72 | The function receives one argument, the name of the major mode of the
 | 
|---|
| 73 | compilation buffer.  It should return a string.
 | 
|---|
| 74 | nil means compute the name with `(concat \"*\" (downcase major-mode) \"*\")'.")
 | 
|---|
| 75 | 
 | 
|---|
| 76 | ;;;###autoload
 | 
|---|
| 77 | (defvar compilation-finish-function nil
 | 
|---|
| 78 |   "*Function to call when a compilation process finishes.
 | 
|---|
| 79 | It is called with two arguments: the compilation buffer, and a string
 | 
|---|
| 80 | describing how the process finished.")
 | 
|---|
| 81 | 
 | 
|---|
| 82 | (defvar compilation-last-buffer nil
 | 
|---|
| 83 |   "The most recent compilation buffer.
 | 
|---|
| 84 | A buffer becomes most recent when its compilation is started
 | 
|---|
| 85 | or when it is used with \\[next-error] or \\[compile-goto-error].")
 | 
|---|
| 86 | 
 | 
|---|
| 87 | (defvar compilation-in-progress nil
 | 
|---|
| 88 |   "List of compilation processes now running.")
 | 
|---|
| 89 | (or (assq 'compilation-in-progress minor-mode-alist)
 | 
|---|
| 90 |     (setq minor-mode-alist (cons '(compilation-in-progress " Compiling")
 | 
|---|
| 91 |                                  minor-mode-alist)))
 | 
|---|
| 92 | 
 | 
|---|
| 93 | (defvar compilation-parsing-end nil
 | 
|---|
| 94 |   "Position of end of buffer when last error messages were parsed.")
 | 
|---|
| 95 | 
 | 
|---|
| 96 | (defvar compilation-error-message "No more errors"
 | 
|---|
| 97 |   "Message to print when no more matches are found.")
 | 
|---|
| 98 | 
 | 
|---|
| 99 | (defvar compilation-num-errors-found)
 | 
|---|
| 100 | 
 | 
|---|
| 101 | (defvar compilation-error-regexp-alist
 | 
|---|
| 102 |   '(
 | 
|---|
| 103 |     ;; NOTE!  This first one is repeated in grep-regexp-alist, below.
 | 
|---|
| 104 | 
 | 
|---|
| 105 |     ;; 4.3BSD grep, cc, lint pass 1:
 | 
|---|
| 106 |     ;;  /usr/src/foo/foo.c(8): warning: w may be used before set
 | 
|---|
| 107 |     ;; or GNU utilities:
 | 
|---|
| 108 |     ;;  foo.c:8: error message
 | 
|---|
| 109 |     ;; or HP-UX 7.0 fc:
 | 
|---|
| 110 |     ;;  foo.f          :16    some horrible error message
 | 
|---|
| 111 |     ;;
 | 
|---|
| 112 |     ;; We'll insist that the number be followed by a colon or closing
 | 
|---|
| 113 |     ;; paren, because otherwise this matches just about anything
 | 
|---|
| 114 |     ;; containing a number with spaces around it.
 | 
|---|
| 115 |     ("\n\\([^:( \t\n]+\\)[:(][ \t]*\\([0-9]+\\)[:) \t]" 1 2)
 | 
|---|
| 116 | 
 | 
|---|
| 117 |     ;; 4.3BSD lint pass 2
 | 
|---|
| 118 |     ;;  strcmp: variable # of args. llib-lc(359)  ::  /usr/src/foo/foo.c(8)
 | 
|---|
| 119 |     ("[ \t:]\\([^:( \t\n]+\\)[:(](+[ \t]*\\([0-9]+\\))[:) \t]*$" 1 2)
 | 
|---|
| 120 | 
 | 
|---|
| 121 |     ;; 4.3BSD lint pass 3
 | 
|---|
| 122 |     ;;  bloofle defined( /users/wolfgang/foo.c(4) ), but never used
 | 
|---|
| 123 |     ;; This used to be
 | 
|---|
| 124 |     ;; ("[ \t(]+\\([^:( \t\n]+\\)[:( \t]+\\([0-9]+\\)[:) \t]+" 1 2)
 | 
|---|
| 125 |     ;; which is regexp Impressionism - it matches almost anything!
 | 
|---|
| 126 |     ("([ \t]*\\([^:( \t\n]+\\)[:(][ \t]*\\([0-9]+\\))" 1 2)
 | 
|---|
| 127 | 
 | 
|---|
| 128 |     ;; Ultrix 3.0 f77:
 | 
|---|
| 129 |     ;;  fort: Severe: addstf.f, line 82: Missing operator or delimiter symbol
 | 
|---|
| 130 |     ("\nfort: [^:\n]*: \\([^ \n]*\\), line \\([0-9]+\\):" 1 2)
 | 
|---|
| 131 |     ;;  Error on line 3 of t.f: Execution error unclassifiable statement    
 | 
|---|
| 132 |     ;; Unknown who does this:
 | 
|---|
| 133 |     ;;  Line 45 of "foo.c": bloofel undefined
 | 
|---|
| 134 |     ;; Absoft FORTRAN 77 Compiler 3.1.3
 | 
|---|
| 135 |     ;;  error on line 19 of fplot.f: spelling error?
 | 
|---|
| 136 |     ;;  warning on line 17 of fplot.f: data type is undefined for variable d
 | 
|---|
| 137 |     ("\\(\n\\|on \\)[Ll]ine[ \t]+\\([0-9]+\\)[ \t]+\
 | 
|---|
| 138 | of[ \t]+\"?\\([^\":\n]+\\)\"?:" 3 2)
 | 
|---|
| 139 | 
 | 
|---|
| 140 |     ;; Apollo cc, 4.3BSD fc:
 | 
|---|
| 141 |     ;;  "foo.f", line 3: Error: syntax error near end of statement
 | 
|---|
| 142 |     ;; IBM RS6000:
 | 
|---|
| 143 |     ;;  "vvouch.c", line 19.5: 1506-046 (S) Syntax error.
 | 
|---|
| 144 |     ;; Unknown compiler:
 | 
|---|
| 145 |     ;;  File "foobar.ml", lines 5-8, characters 20-155: blah blah
 | 
|---|
| 146 |     ;; Microtec mcc68k:
 | 
|---|
| 147 |     ;;  "foo.c", line 32 pos 1; (E) syntax error; unexpected symbol: "lossage"
 | 
|---|
| 148 |     ("\"\\([^,\" \n\t]+\\)\", lines? \\([0-9]+\\)[:., -]" 1 2)
 | 
|---|
| 149 | 
 | 
|---|
| 150 |     ;; MIPS RISC CC - the one distributed with Ultrix:
 | 
|---|
| 151 |     ;;  ccom: Error: foo.c, line 2: syntax error
 | 
|---|
| 152 |     ;; DEC AXP OSF/1 cc
 | 
|---|
| 153 |     ;;  /usr/lib/cmplrs/cc/cfe: Error: foo.c: 1: blah blah 
 | 
|---|
| 154 |     ("rror: \\([^,\" \n\t]+\\)[,:] \\(line \\)?\\([0-9]+\\):" 1 3)
 | 
|---|
| 155 | 
 | 
|---|
| 156 |     ;; IBM AIX PS/2 C version 1.1:
 | 
|---|
| 157 |     ;;  ****** Error number 140 in line 8 of file errors.c ******
 | 
|---|
| 158 |     ("in line \\([0-9]+\\) of file \\([^ \n]+[^. \n]\\)\\.? " 2 1)
 | 
|---|
| 159 |     ;; IBM AIX lint is too painful to do right this way.  File name
 | 
|---|
| 160 |     ;; prefixes entire sections rather than being on each line.
 | 
|---|
| 161 | 
 | 
|---|
| 162 |     ;; Lucid Compiler, lcc 3.x
 | 
|---|
| 163 |     ;; E, file.cc(35,52) Illegal operation on pointers
 | 
|---|
| 164 |     ("\n[EW], \\([^(\n]*\\)(\\([0-9]+\\),[ \t]*\\([0-9]+\\)" 1 2 3)
 | 
|---|
| 165 | 
 | 
|---|
| 166 |     )
 | 
|---|
| 167 |   "Alist that specifies how to match errors in compiler output.
 | 
|---|
| 168 | Each element has the form (REGEXP FILE-IDX LINE-IDX [COLUMN-IDX]).
 | 
|---|
| 169 | If REGEXP matches, the FILE-IDX'th subexpression gives the file name, and
 | 
|---|
| 170 | the LINE-IDX'th subexpression gives the line number.  If COLUMN-IDX is
 | 
|---|
| 171 | given, the COLUMN-IDX'th subexpression gives the column number on that line.")
 | 
|---|
| 172 | 
 | 
|---|
| 173 | (defvar compilation-read-command t
 | 
|---|
| 174 |   "If not nil, M-x compile reads the compilation command to use.
 | 
|---|
| 175 | Otherwise, M-x compile just uses the value of `compile-command'.")
 | 
|---|
| 176 | 
 | 
|---|
| 177 | (defvar compilation-ask-about-save t
 | 
|---|
| 178 |   "If not nil, M-x compile asks which buffers to save before compiling.
 | 
|---|
| 179 | Otherwise, it saves all modified buffers without asking.")
 | 
|---|
| 180 | 
 | 
|---|
| 181 | (defvar grep-regexp-alist
 | 
|---|
| 182 |   '(("^\\([^:( \t\n]+\\)[:( \t]+\\([0-9]+\\)[:) \t]" 1 2))
 | 
|---|
| 183 |   "Regexp used to match grep hits.  See `compilation-error-regexp-alist'.")
 | 
|---|
| 184 | 
 | 
|---|
| 185 | (defvar grep-command "grep -n "
 | 
|---|
| 186 |   "Last grep command used in \\{grep}; default for next grep.")
 | 
|---|
| 187 | 
 | 
|---|
| 188 | ;;;###autoload
 | 
|---|
| 189 | (defvar compilation-search-path '(nil)
 | 
|---|
| 190 |   "*List of directories to search for source files named in error messages.
 | 
|---|
| 191 | Elements should be directory names, not file names of directories.
 | 
|---|
| 192 | nil as an element means to try the default directory.")
 | 
|---|
| 193 | 
 | 
|---|
| 194 | (defvar compile-command "make -k "
 | 
|---|
| 195 |   "Last shell command used to do a compilation; default for next compilation.
 | 
|---|
| 196 | 
 | 
|---|
| 197 | Sometimes it is useful for files to supply local values for this variable.
 | 
|---|
| 198 | You might also use mode hooks to specify it in certain modes, like this:
 | 
|---|
| 199 | 
 | 
|---|
| 200 |     (setq c-mode-hook
 | 
|---|
| 201 |       '(lambda () (or (file-exists-p \"makefile\") (file-exists-p \"Makefile\")
 | 
|---|
| 202 |                       (progn (make-local-variable 'compile-command)
 | 
|---|
| 203 |                              (setq compile-command
 | 
|---|
| 204 |                                     (concat \"make -k \"
 | 
|---|
| 205 |                                             buffer-file-name))))))")
 | 
|---|
| 206 | 
 | 
|---|
| 207 | (defconst compilation-enter-directory-regexp
 | 
|---|
| 208 |   ": Entering directory `\\(.*\\)'$"
 | 
|---|
| 209 |   "Regular expression matching lines that indicate a new current directory.
 | 
|---|
| 210 | This must contain one \\(, \\) pair around the directory name.
 | 
|---|
| 211 | 
 | 
|---|
| 212 | The default value matches lines printed by the `-w' option of GNU Make.")
 | 
|---|
| 213 | 
 | 
|---|
| 214 | (defconst compilation-leave-directory-regexp
 | 
|---|
| 215 |   ": Leaving directory `\\(.*\\)'$"
 | 
|---|
| 216 |   "Regular expression matching lines that indicate restoring current directory.
 | 
|---|
| 217 | This may contain one \\(, \\) pair around the name of the directory
 | 
|---|
| 218 | being moved from.  If it does not, the last directory entered \(by a
 | 
|---|
| 219 | line matching `compilation-enter-directory-regexp'\) is assumed.
 | 
|---|
| 220 | 
 | 
|---|
| 221 | The default value matches lines printed by the `-w' option of GNU Make.")
 | 
|---|
| 222 | 
 | 
|---|
| 223 | (defvar compilation-directory-stack nil
 | 
|---|
| 224 |   "Stack of previous directories for `compilation-leave-directory-regexp'.
 | 
|---|
| 225 | The head element is the directory the compilation was started in.")
 | 
|---|
| 226 | 
 | 
|---|
| 227 | ;; History of compile commands.
 | 
|---|
| 228 | (defvar compile-history nil)
 | 
|---|
| 229 | ;; History of grep commands.
 | 
|---|
| 230 | (defvar grep-history nil)
 | 
|---|
| 231 | 
 | 
|---|
| 232 | ;;;###autoload
 | 
|---|
| 233 | (defun compile (command)
 | 
|---|
| 234 |   "Compile the program including the current buffer.  Default: run `make'.
 | 
|---|
| 235 | Runs COMMAND, a shell command, in a separate process asynchronously
 | 
|---|
| 236 | with output going to the buffer `*compilation*'.
 | 
|---|
| 237 | 
 | 
|---|
| 238 | You can then use the command \\[next-error] to find the next error message
 | 
|---|
| 239 | and move to the source code that caused it.
 | 
|---|
| 240 | 
 | 
|---|
| 241 | To run more than one compilation at once, start one and rename the
 | 
|---|
| 242 | \`*compilation*' buffer to some other name with \\[rename-buffer].
 | 
|---|
| 243 | Then start the next one.
 | 
|---|
| 244 | 
 | 
|---|
| 245 | The name used for the buffer is actually whatever is returned by
 | 
|---|
| 246 | the function in `compilation-buffer-name-function', so you can set that
 | 
|---|
| 247 | to a function that generates a unique name."
 | 
|---|
| 248 |   (interactive
 | 
|---|
| 249 |    (if compilation-read-command
 | 
|---|
| 250 |        (list (read-from-minibuffer "Compile command: "
 | 
|---|
| 251 |                                  compile-command nil nil
 | 
|---|
| 252 |                                  '(compile-history . 1)))
 | 
|---|
| 253 |      (list compile-command)))
 | 
|---|
| 254 |   (setq compile-command command)
 | 
|---|
| 255 |   (save-some-buffers (not compilation-ask-about-save) nil)
 | 
|---|
| 256 |   (compile-internal compile-command "No more errors"))
 | 
|---|
| 257 | 
 | 
|---|
| 258 | ;;;###autoload
 | 
|---|
| 259 | (defun grep (command-args)
 | 
|---|
| 260 |   "Run grep, with user-specified args, and collect output in a buffer.
 | 
|---|
| 261 | While grep runs asynchronously, you can use the \\[next-error] command
 | 
|---|
| 262 | to find the text that grep hits refer to.
 | 
|---|
| 263 | 
 | 
|---|
| 264 | This command uses a special history list for its arguments, so you can
 | 
|---|
| 265 | easily repeat a grep command."
 | 
|---|
| 266 |   (interactive
 | 
|---|
| 267 |    (list (read-from-minibuffer "Run grep (like this): "
 | 
|---|
| 268 |                                grep-command nil nil 'grep-history)))
 | 
|---|
| 269 |   (compile-internal (concat command-args " /dev/null")
 | 
|---|
| 270 |                     "No more grep hits" "grep"
 | 
|---|
| 271 |                     ;; Give it a simpler regexp to match.
 | 
|---|
| 272 |                     nil grep-regexp-alist))
 | 
|---|
| 273 | 
 | 
|---|
| 274 | (defun compile-internal (command error-message
 | 
|---|
| 275 |                                  &optional name-of-mode parser regexp-alist
 | 
|---|
| 276 |                                  name-function)
 | 
|---|
| 277 |   "Run compilation command COMMAND (low level interface).
 | 
|---|
| 278 | ERROR-MESSAGE is a string to print if the user asks to see another error
 | 
|---|
| 279 | and there are no more errors.  Third argument NAME-OF-MODE is the name
 | 
|---|
| 280 | to display as the major mode in the compilation buffer.
 | 
|---|
| 281 | 
 | 
|---|
| 282 | Fourth arg PARSER is the error parser function (nil means the default).  Fifth
 | 
|---|
| 283 | arg REGEXP-ALIST is the error message regexp alist to use (nil means the
 | 
|---|
| 284 | default).  Sixth arg NAME-FUNCTION is a function called to name the buffer (nil
 | 
|---|
| 285 | means the default).  The defaults for these variables are the global values of
 | 
|---|
| 286 | \`compilation-parse-errors-function', `compilation-error-regexp-alist', and
 | 
|---|
| 287 | \`compilation-buffer-name-function', respectively.
 | 
|---|
| 288 | 
 | 
|---|
| 289 | Returns the compilation buffer created."
 | 
|---|
| 290 |   (let (outbuf)
 | 
|---|
| 291 |     (save-excursion
 | 
|---|
| 292 |       (or name-of-mode
 | 
|---|
| 293 |           (setq name-of-mode "Compilation"))
 | 
|---|
| 294 |       (setq outbuf
 | 
|---|
| 295 |             (get-buffer-create
 | 
|---|
| 296 |              (funcall (or name-function compilation-buffer-name-function
 | 
|---|
| 297 |                           (function (lambda (mode)
 | 
|---|
| 298 |                                       (concat "*" (downcase mode) "*"))))
 | 
|---|
| 299 |                       name-of-mode)))
 | 
|---|
| 300 |       (set-buffer outbuf)
 | 
|---|
| 301 |       (let ((comp-proc (get-buffer-process (current-buffer))))
 | 
|---|
| 302 |         (if comp-proc
 | 
|---|
| 303 |             (if (or (not (eq (process-status comp-proc) 'run))
 | 
|---|
| 304 |                     (yes-or-no-p
 | 
|---|
| 305 |                      (format "A %s process is running; kill it? "
 | 
|---|
| 306 |                              name-of-mode)))
 | 
|---|
| 307 |                 (condition-case ()
 | 
|---|
| 308 |                     (progn
 | 
|---|
| 309 |                       (interrupt-process comp-proc)
 | 
|---|
| 310 |                       (sit-for 1)
 | 
|---|
| 311 |                       (delete-process comp-proc))
 | 
|---|
| 312 |                   (error nil))
 | 
|---|
| 313 |               (error "Cannot have two processes in `%s' at once"
 | 
|---|
| 314 |                      (buffer-name))
 | 
|---|
| 315 |               )))
 | 
|---|
| 316 |       ;; In case the compilation buffer is current, make sure we get the global
 | 
|---|
| 317 |       ;; values of compilation-error-regexp-alist, etc.
 | 
|---|
| 318 |       (kill-all-local-variables))
 | 
|---|
| 319 |     (let ((regexp-alist (or regexp-alist compilation-error-regexp-alist))
 | 
|---|
| 320 |           (parser (or parser compilation-parse-errors-function))
 | 
|---|
| 321 |           (thisdir default-directory)
 | 
|---|
| 322 |           outwin) 
 | 
|---|
| 323 |       (save-excursion
 | 
|---|
| 324 |         ;; Clear out the compilation buffer and make it writable.
 | 
|---|
| 325 |         ;; Change its default-directory to the directory where the compilation
 | 
|---|
| 326 |         ;; will happen, and insert a `cd' command to indicate this.
 | 
|---|
| 327 |         (set-buffer outbuf)
 | 
|---|
| 328 |         (setq buffer-read-only nil)
 | 
|---|
| 329 |         (erase-buffer)
 | 
|---|
| 330 |         ;; BEGIN C JANSSEN ADDITIONS
 | 
|---|
| 331 |         (if (and (not (string= name-of-mode "grep"))
 | 
|---|
| 332 |                  (fboundp 'compile-modify-path))
 | 
|---|
| 333 |             (setq thisdir (compile-modify-path thisdir))
 | 
|---|
| 334 |           )
 | 
|---|
| 335 |         ;; END C JANSSEN ADDITIONS
 | 
|---|
| 336 |         (setq default-directory thisdir)
 | 
|---|
| 337 |         (insert "cd " thisdir "\n" command "\n")
 | 
|---|
| 338 |         (set-buffer-modified-p nil))
 | 
|---|
| 339 |       ;; If we're already in the compilation buffer, go to the end
 | 
|---|
| 340 |       ;; of the buffer, so point will track the compilation output.
 | 
|---|
| 341 |       (if (eq outbuf (current-buffer))
 | 
|---|
| 342 |           (goto-char (point-max)))
 | 
|---|
| 343 |       ;; Pop up the compilation buffer.
 | 
|---|
| 344 |       (setq outwin (display-buffer outbuf))
 | 
|---|
| 345 |       (save-excursion
 | 
|---|
| 346 |         (set-buffer outbuf)
 | 
|---|
| 347 |         (compilation-mode)
 | 
|---|
| 348 |         (buffer-disable-undo (current-buffer))
 | 
|---|
| 349 |         ;; (setq buffer-read-only t)  ;;; Non-ergonomic.
 | 
|---|
| 350 |         (set (make-local-variable 'compilation-parse-errors-function) parser)
 | 
|---|
| 351 |         (set (make-local-variable 'compilation-error-message) error-message)
 | 
|---|
| 352 |         (set (make-local-variable 'compilation-error-regexp-alist) regexp-alist)
 | 
|---|
| 353 |         (setq default-directory thisdir
 | 
|---|
| 354 |               compilation-directory-stack (list default-directory))
 | 
|---|
| 355 |         (set-window-start outwin (point-min))
 | 
|---|
| 356 |         (setq mode-name name-of-mode)
 | 
|---|
| 357 |         (or (eq outwin (selected-window))
 | 
|---|
| 358 |         ;; BEGIN C JANSSEN MODS
 | 
|---|
| 359 |             ;; goto the end of the buffer instead of the beginning
 | 
|---|
| 360 |             ;;(set-window-point outwin (point-min)))
 | 
|---|
| 361 |             (set-window-point outwin (point-max)))
 | 
|---|
| 362 |         ;; END C JANSSEN MODS
 | 
|---|
| 363 |         (and compilation-window-height
 | 
|---|
| 364 |              (= (window-width outwin) (frame-width))
 | 
|---|
| 365 |              (let ((w (selected-window)))
 | 
|---|
| 366 |                (unwind-protect
 | 
|---|
| 367 |                    (progn
 | 
|---|
| 368 |                      (select-window outwin)
 | 
|---|
| 369 |                      (enlarge-window (- compilation-window-height
 | 
|---|
| 370 |                                         (window-height))))
 | 
|---|
| 371 |                  (select-window w))))
 | 
|---|
| 372 |         ;; Start the compilation.
 | 
|---|
| 373 |         (if (fboundp 'start-process)
 | 
|---|
| 374 |             (let ((proc (start-process-shell-command (downcase mode-name)
 | 
|---|
| 375 |                                                      outbuf
 | 
|---|
| 376 |                                                      command)))
 | 
|---|
| 377 |               (set-process-sentinel proc 'compilation-sentinel)
 | 
|---|
| 378 |               (set-process-filter proc 'compilation-filter)
 | 
|---|
| 379 |               (set-marker (process-mark proc) (point) outbuf)
 | 
|---|
| 380 |               (setq compilation-in-progress 
 | 
|---|
| 381 |                     (cons proc compilation-in-progress)))
 | 
|---|
| 382 |           ;; No asynchronous processes available
 | 
|---|
| 383 |           (message (format "Executing `%s'..." command))
 | 
|---|
| 384 |           (let ((status (call-process shell-file-name nil outbuf nil "-c"
 | 
|---|
| 385 |                                       command))))
 | 
|---|
| 386 |           (message (format "Executing `%s'...done" command)))))
 | 
|---|
| 387 |     ;; Make it so the next C-x ` will use this buffer.
 | 
|---|
| 388 |     (setq compilation-last-buffer outbuf)))
 | 
|---|
| 389 | 
 | 
|---|
| 390 | (defvar compilation-minor-mode-map
 | 
|---|
| 391 |   (let ((map (make-sparse-keymap)))
 | 
|---|
| 392 |     (define-key map [mouse-2] 'compile-mouse-goto-error)
 | 
|---|
| 393 |     (define-key map "\C-c\C-c" 'compile-goto-error)
 | 
|---|
| 394 |     (define-key map "\C-c\C-k" 'kill-compilation)
 | 
|---|
| 395 |     (define-key map "\M-n" 'compilation-next-error)
 | 
|---|
| 396 |     (define-key map "\M-p" 'compilation-previous-error)
 | 
|---|
| 397 |     (define-key map "\M-{" 'compilation-previous-file)
 | 
|---|
| 398 |     (define-key map "\M-}" 'compilation-next-file)
 | 
|---|
| 399 |     map)
 | 
|---|
| 400 |   "Keymap for `compilation-minor-mode'.")
 | 
|---|
| 401 | 
 | 
|---|
| 402 | (defvar compilation-mode-map
 | 
|---|
| 403 |   (let ((map (cons 'keymap compilation-minor-mode-map)))
 | 
|---|
| 404 |     (define-key map " " 'scroll-up)
 | 
|---|
| 405 |     (define-key map "\^?" 'scroll-down)
 | 
|---|
| 406 |     map)
 | 
|---|
| 407 |   "Keymap for compilation log buffers.
 | 
|---|
| 408 | `compilation-minor-mode-map' is a cdr of this.")
 | 
|---|
| 409 | 
 | 
|---|
| 410 | (defun compilation-mode ()
 | 
|---|
| 411 |   "Major mode for compilation log buffers.
 | 
|---|
| 412 | \\<compilation-mode-map>To visit the source for a line-numbered error,
 | 
|---|
| 413 | move point to the error message line and type \\[compile-goto-error].
 | 
|---|
| 414 | To kill the compilation, type \\[kill-compilation].
 | 
|---|
| 415 | 
 | 
|---|
| 416 | Runs `compilation-mode-hook' with `run-hooks' (which see)."
 | 
|---|
| 417 |   (interactive)
 | 
|---|
| 418 |   (fundamental-mode)
 | 
|---|
| 419 |   (use-local-map compilation-mode-map)
 | 
|---|
| 420 |   (setq major-mode 'compilation-mode
 | 
|---|
| 421 |         mode-name "Compilation")
 | 
|---|
| 422 |   (compilation-setup)
 | 
|---|
| 423 |   (run-hooks 'compilation-mode-hook))
 | 
|---|
| 424 | 
 | 
|---|
| 425 | ;; Prepare the buffer for the compilation parsing commands to work.
 | 
|---|
| 426 | (defun compilation-setup ()
 | 
|---|
| 427 |   ;; Make the buffer's mode line show process state.
 | 
|---|
| 428 |   (setq mode-line-process '(":%s"))
 | 
|---|
| 429 |   (set (make-local-variable 'compilation-error-list) nil)
 | 
|---|
| 430 |   (set (make-local-variable 'compilation-old-error-list) nil)
 | 
|---|
| 431 |   (set (make-local-variable 'compilation-parsing-end) 1)
 | 
|---|
| 432 |   (set (make-local-variable 'compilation-directory-stack) nil)
 | 
|---|
| 433 |   (setq compilation-last-buffer (current-buffer)))
 | 
|---|
| 434 | 
 | 
|---|
| 435 | (defvar compilation-minor-mode nil
 | 
|---|
| 436 |   "Non-nil when in compilation-minor-mode.
 | 
|---|
| 437 | In this minor mode, all the error-parsing commands of the
 | 
|---|
| 438 | Compilation major mode are available.")
 | 
|---|
| 439 | (make-variable-buffer-local 'compilation-minor-mode)
 | 
|---|
| 440 | 
 | 
|---|
| 441 | (or (assq 'compilation-minor-mode minor-mode-alist)
 | 
|---|
| 442 |     (setq minor-mode-alist (cons '(compilation-minor-mode " Compilation")
 | 
|---|
| 443 |                                  minor-mode-alist)))
 | 
|---|
| 444 | (or (assq 'compilation-minor-mode minor-mode-map-alist)
 | 
|---|
| 445 |     (setq minor-mode-map-alist (cons (cons 'compilation-minor-mode
 | 
|---|
| 446 |                                            compilation-minor-mode-map)
 | 
|---|
| 447 |                                      minor-mode-map-alist)))
 | 
|---|
| 448 | 
 | 
|---|
| 449 | ;;;###autoload
 | 
|---|
| 450 | (defun compilation-minor-mode (&optional arg)
 | 
|---|
| 451 |   "Toggle compilation minor mode.
 | 
|---|
| 452 | With arg, turn compilation mode on if and only if arg is positive.
 | 
|---|
| 453 | See `compilation-mode'."
 | 
|---|
| 454 |   (interactive "P")
 | 
|---|
| 455 |   (if (setq compilation-minor-mode (if (null arg)
 | 
|---|
| 456 |                                        (null compilation-minor-mode)
 | 
|---|
| 457 |                                      (> (prefix-numeric-value arg) 0)))
 | 
|---|
| 458 |       (compilation-setup)))
 | 
|---|
| 459 | 
 | 
|---|
| 460 | ;; Called when compilation process changes state.
 | 
|---|
| 461 | (defun compilation-sentinel (proc msg)
 | 
|---|
| 462 |   "Sentinel for compilation buffers."
 | 
|---|
| 463 |   (let ((buffer (process-buffer proc)))
 | 
|---|
| 464 |     (if (memq (process-status proc) '(signal exit))
 | 
|---|
| 465 |         (progn
 | 
|---|
| 466 |           (if (null (buffer-name buffer))
 | 
|---|
| 467 |               ;; buffer killed
 | 
|---|
| 468 |               (set-process-buffer proc nil)
 | 
|---|
| 469 |             (let ((obuf (current-buffer))
 | 
|---|
| 470 |                   omax opoint)
 | 
|---|
| 471 |               ;; save-excursion isn't the right thing if
 | 
|---|
| 472 |               ;; process-buffer is current-buffer
 | 
|---|
| 473 |               (unwind-protect
 | 
|---|
| 474 |                   (progn
 | 
|---|
| 475 |                     ;; Write something in the compilation buffer
 | 
|---|
| 476 |                     ;; and hack its mode line.
 | 
|---|
| 477 |                     (set-buffer buffer)
 | 
|---|
| 478 |                     (let ((buffer-read-only nil))
 | 
|---|
| 479 |                       (setq omax (point-max)
 | 
|---|
| 480 |                             opoint (point))
 | 
|---|
| 481 |                       (goto-char omax)
 | 
|---|
| 482 |                       ;; Record where we put the message, so we can ignore it
 | 
|---|
| 483 |                       ;; later on.
 | 
|---|
| 484 |                       (insert ?\n mode-name " " msg)
 | 
|---|
| 485 |                       (forward-char -1)
 | 
|---|
| 486 |                       (insert " at " (substring (current-time-string) 0 19))
 | 
|---|
| 487 |                       (forward-char 1)
 | 
|---|
| 488 |                       (setq mode-line-process
 | 
|---|
| 489 |                             (concat ":"
 | 
|---|
| 490 |                                     (symbol-name (process-status proc))))
 | 
|---|
| 491 |                       ;; Since the buffer and mode line will show that the
 | 
|---|
| 492 |                       ;; process is dead, we can delete it now.  Otherwise it
 | 
|---|
| 493 |                       ;; will stay around until M-x list-processes.
 | 
|---|
| 494 |                       (delete-process proc)
 | 
|---|
| 495 |                       ;; Force mode line redisplay soon.
 | 
|---|
| 496 |                       (set-buffer-modified-p (buffer-modified-p)))
 | 
|---|
| 497 |                     (if (and opoint (< opoint omax))
 | 
|---|
| 498 |                         (goto-char opoint))
 | 
|---|
| 499 |                     (if compilation-finish-function
 | 
|---|
| 500 |                         (funcall compilation-finish-function buffer msg)))
 | 
|---|
| 501 |                 (set-buffer obuf))))
 | 
|---|
| 502 |           (setq compilation-in-progress (delq proc compilation-in-progress))
 | 
|---|
| 503 |           ))))
 | 
|---|
| 504 | 
 | 
|---|
| 505 | (defun compilation-filter (proc string)
 | 
|---|
| 506 |   "Process filter for compilation buffers.
 | 
|---|
| 507 | Just inserts the text, but uses `insert-before-markers'."
 | 
|---|
| 508 |   (save-excursion
 | 
|---|
| 509 |     (set-buffer (process-buffer proc))
 | 
|---|
| 510 |     (let ((buffer-read-only nil))
 | 
|---|
| 511 |       (save-excursion
 | 
|---|
| 512 |         (goto-char (process-mark proc))
 | 
|---|
| 513 |         (insert-before-markers string)
 | 
|---|
| 514 |         (set-marker (process-mark proc) (point))))))
 | 
|---|
| 515 | 
 | 
|---|
| 516 | ;; Return the cdr of compilation-old-error-list for the error containing point.
 | 
|---|
| 517 | (defun compile-error-at-point ()
 | 
|---|
| 518 |   (compile-reinitialize-errors nil (point))
 | 
|---|
| 519 |   (let ((errors compilation-old-error-list))
 | 
|---|
| 520 |     (while (and errors
 | 
|---|
| 521 |                 (> (point) (car (car errors))))
 | 
|---|
| 522 |       (setq errors (cdr errors)))
 | 
|---|
| 523 |     errors))
 | 
|---|
| 524 | 
 | 
|---|
| 525 | (defsubst compilation-buffer-p (buffer)
 | 
|---|
| 526 |   (assq 'compilation-error-list (buffer-local-variables buffer)))
 | 
|---|
| 527 | 
 | 
|---|
| 528 | (defun compilation-next-error (n)
 | 
|---|
| 529 |   "Move point to the next error in the compilation buffer.
 | 
|---|
| 530 | Does NOT find the source line like \\[next-error]."
 | 
|---|
| 531 |   (interactive "p")
 | 
|---|
| 532 |   (or (compilation-buffer-p (current-buffer))
 | 
|---|
| 533 |       (error "Not in a compilation buffer."))
 | 
|---|
| 534 |   (setq compilation-last-buffer (current-buffer))
 | 
|---|
| 535 | 
 | 
|---|
| 536 |   (let ((errors (compile-error-at-point)))
 | 
|---|
| 537 | 
 | 
|---|
| 538 |     ;; Move to the error after the one containing point.
 | 
|---|
| 539 |     (goto-char (car (if (< n 0)
 | 
|---|
| 540 |                         (let ((i 0)
 | 
|---|
| 541 |                               (e compilation-old-error-list))
 | 
|---|
| 542 |                           ;; See how many cdrs away ERRORS is from the start.
 | 
|---|
| 543 |                           (while (not (eq e errors))
 | 
|---|
| 544 |                             (setq i (1+ i)
 | 
|---|
| 545 |                                   e (cdr e)))
 | 
|---|
| 546 |                           (if (> (- n) i)
 | 
|---|
| 547 |                               (error "Moved back past first error")
 | 
|---|
| 548 |                             (nth (+ i n) compilation-old-error-list)))
 | 
|---|
| 549 |                       (let ((compilation-error-list (cdr errors)))
 | 
|---|
| 550 |                         (compile-reinitialize-errors nil nil n)
 | 
|---|
| 551 |                         (if compilation-error-list
 | 
|---|
| 552 |                             (nth (1- n) compilation-error-list)
 | 
|---|
| 553 |                           (error "Moved past last error"))))))))
 | 
|---|
| 554 | 
 | 
|---|
| 555 | (defun compilation-previous-error (n)
 | 
|---|
| 556 |   "Move point to the previous error in the compilation buffer.
 | 
|---|
| 557 | Does NOT find the source line like \\[next-error]."
 | 
|---|
| 558 |   (interactive "p")
 | 
|---|
| 559 |   (compilation-next-error (- n)))
 | 
|---|
| 560 | 
 | 
|---|
| 561 | 
 | 
|---|
| 562 | ;; Given an elt of `compilation-error-list', return an object representing
 | 
|---|
| 563 | ;; the referenced file which is equal to (but not necessarily eq to) what
 | 
|---|
| 564 | ;; this function would return for another error in the same file.
 | 
|---|
| 565 | (defsubst compilation-error-filedata (data)
 | 
|---|
| 566 |   (setq data (cdr data))
 | 
|---|
| 567 |   (if (markerp data)
 | 
|---|
| 568 |       (marker-buffer data)
 | 
|---|
| 569 |     (car data)))
 | 
|---|
| 570 | 
 | 
|---|
| 571 | ;; Return a string describing a value from compilation-error-filedata.
 | 
|---|
| 572 | ;; This value is not necessarily useful as a file name, but should be
 | 
|---|
| 573 | ;; indicative to the user of what file's errors are being referred to.
 | 
|---|
| 574 | (defsubst compilation-error-filedata-file-name (filedata)
 | 
|---|
| 575 |   (if (bufferp filedata)
 | 
|---|
| 576 |       (buffer-file-name filedata)
 | 
|---|
| 577 |     (car filedata)))
 | 
|---|
| 578 | 
 | 
|---|
| 579 | (defun compilation-next-file (n)
 | 
|---|
| 580 |   "Move point to the next error for a different file than the current one."
 | 
|---|
| 581 |   (interactive "p")
 | 
|---|
| 582 |   (or (compilation-buffer-p (current-buffer))
 | 
|---|
| 583 |       (error "Not in a compilation buffer."))
 | 
|---|
| 584 |   (setq compilation-last-buffer (current-buffer))
 | 
|---|
| 585 | 
 | 
|---|
| 586 |   (let ((reversed (< n 0))
 | 
|---|
| 587 |         errors filedata)
 | 
|---|
| 588 | 
 | 
|---|
| 589 |     (if (not reversed)
 | 
|---|
| 590 |         (setq errors (or (compile-error-at-point)
 | 
|---|
| 591 |                          (error "Moved past last error")))
 | 
|---|
| 592 | 
 | 
|---|
| 593 |       ;; Get a reversed list of the errors up through the one containing point.
 | 
|---|
| 594 |       (compile-reinitialize-errors nil (point))
 | 
|---|
| 595 |       (setq errors (reverse compilation-old-error-list)
 | 
|---|
| 596 |             n (- n))
 | 
|---|
| 597 | 
 | 
|---|
| 598 |       ;; Ignore errors after point.  (car ERRORS) will be the error
 | 
|---|
| 599 |       ;; containing point, (cadr ERRORS) the one before it.
 | 
|---|
| 600 |       (while (and errors
 | 
|---|
| 601 |                   (< (point) (car (car errors))))
 | 
|---|
| 602 |         (setq errors (cdr errors))))
 | 
|---|
| 603 | 
 | 
|---|
| 604 |     (while (> n 0)
 | 
|---|
| 605 |       (setq filedata (compilation-error-filedata (car errors)))
 | 
|---|
| 606 | 
 | 
|---|
| 607 |       ;; Skip past the following errors for this file.
 | 
|---|
| 608 |       (while (equal filedata
 | 
|---|
| 609 |                     (compilation-error-filedata
 | 
|---|
| 610 |                      (car (or errors
 | 
|---|
| 611 |                               (if reversed
 | 
|---|
| 612 |                                   (error "%s the first erring file"
 | 
|---|
| 613 |                                          (compilation-error-filedata-file-name
 | 
|---|
| 614 |                                           filedata))
 | 
|---|
| 615 |                                 (let ((compilation-error-list nil))
 | 
|---|
| 616 |                                   ;; Parse some more.
 | 
|---|
| 617 |                                   (compile-reinitialize-errors nil nil 2)
 | 
|---|
| 618 |                                   (setq errors compilation-error-list)))
 | 
|---|
| 619 |                               (error "%s is the last erring file" 
 | 
|---|
| 620 |                                      (compilation-error-filedata-file-name
 | 
|---|
| 621 |                                       filedata))))))
 | 
|---|
| 622 |         (setq errors (cdr errors)))
 | 
|---|
| 623 | 
 | 
|---|
| 624 |       (setq n (1- n)))
 | 
|---|
| 625 | 
 | 
|---|
| 626 |     ;; Move to the following error.
 | 
|---|
| 627 |     (goto-char (car (car (or errors
 | 
|---|
| 628 |                              (if reversed
 | 
|---|
| 629 |                                  (error "This is the first erring file")
 | 
|---|
| 630 |                                (let ((compilation-error-list nil))
 | 
|---|
| 631 |                                  ;; Parse the last one.
 | 
|---|
| 632 |                                  (compile-reinitialize-errors nil nil 1)
 | 
|---|
| 633 |                                  compilation-error-list))))))))
 | 
|---|
| 634 | 
 | 
|---|
| 635 | (defun compilation-previous-file (n)
 | 
|---|
| 636 |   "Move point to the previous error for a different file than the current one."
 | 
|---|
| 637 |   (interactive "p")
 | 
|---|
| 638 |   (compilation-next-file (- n)))
 | 
|---|
| 639 | 
 | 
|---|
| 640 | 
 | 
|---|
| 641 | (defun kill-compilation ()
 | 
|---|
| 642 |   "Kill the process made by the \\[compile] command."
 | 
|---|
| 643 |   (interactive)
 | 
|---|
| 644 |   (let ((buffer (compilation-find-buffer)))
 | 
|---|
| 645 |     (if (get-buffer-process buffer)
 | 
|---|
| 646 |         (interrupt-process (get-buffer-process buffer))
 | 
|---|
| 647 |       (error "The compilation process is not running."))))
 | 
|---|
| 648 | 
 | 
|---|
| 649 | 
 | 
|---|
| 650 | ;; Parse any new errors in the compilation buffer,
 | 
|---|
| 651 | ;; or reparse from the beginning if the user has asked for that.
 | 
|---|
| 652 | (defun compile-reinitialize-errors (reparse
 | 
|---|
| 653 |                                     &optional limit-search find-at-least)
 | 
|---|
| 654 |   (save-excursion
 | 
|---|
| 655 |     (set-buffer compilation-last-buffer)
 | 
|---|
| 656 |     ;; If we are out of errors, or if user says "reparse",
 | 
|---|
| 657 |     ;; discard the info we have, to force reparsing.
 | 
|---|
| 658 |     (if (or (eq compilation-error-list t)
 | 
|---|
| 659 |             reparse)
 | 
|---|
| 660 |         (compilation-forget-errors))
 | 
|---|
| 661 |     (if (and compilation-error-list
 | 
|---|
| 662 |              (or (not limit-search)
 | 
|---|
| 663 |                  (> compilation-parsing-end limit-search))
 | 
|---|
| 664 |              (or (not find-at-least)
 | 
|---|
| 665 |                  (>= (length compilation-error-list) find-at-least)))
 | 
|---|
| 666 |         ;; Since compilation-error-list is non-nil, it points to a specific
 | 
|---|
| 667 |         ;; error the user wanted.  So don't move it around.
 | 
|---|
| 668 |         nil
 | 
|---|
| 669 |       ;; This was here for a long time (before my rewrite); why? --roland
 | 
|---|
| 670 |       ;;(switch-to-buffer compilation-last-buffer)
 | 
|---|
| 671 |       (set-buffer-modified-p nil)
 | 
|---|
| 672 |       (if (< compilation-parsing-end (point-max))
 | 
|---|
| 673 |           ;; compilation-error-list might be non-nil if we have a non-nil
 | 
|---|
| 674 |           ;; LIMIT-SEARCH or FIND-AT-LEAST arg.  In that case its value
 | 
|---|
| 675 |           ;; records the current position in the error list, and we must
 | 
|---|
| 676 |           ;; preserve that after reparsing.
 | 
|---|
| 677 |           (let ((error-list-pos compilation-error-list))
 | 
|---|
| 678 |             (funcall compilation-parse-errors-function
 | 
|---|
| 679 |                      limit-search
 | 
|---|
| 680 |                      (and find-at-least
 | 
|---|
| 681 |                           ;; We only need enough new parsed errors to reach
 | 
|---|
| 682 |                           ;; FIND-AT-LEAST errors past the current
 | 
|---|
| 683 |                           ;; position.
 | 
|---|
| 684 |                           (- find-at-least (length compilation-error-list))))
 | 
|---|
| 685 |             ;; Remember the entire list for compilation-forget-errors.  If
 | 
|---|
| 686 |             ;; this is an incremental parse, append to previous list.  If
 | 
|---|
| 687 |             ;; we are parsing anew, compilation-forget-errors cleared
 | 
|---|
| 688 |             ;; compilation-old-error-list above.
 | 
|---|
| 689 |             (setq compilation-old-error-list
 | 
|---|
| 690 |                   (nconc compilation-old-error-list compilation-error-list))
 | 
|---|
| 691 |             (if error-list-pos
 | 
|---|
| 692 |                 ;; We started in the middle of an existing list of parsed
 | 
|---|
| 693 |                 ;; errors before parsing more; restore that position.
 | 
|---|
| 694 |                 (setq compilation-error-list error-list-pos))
 | 
|---|
| 695 |             )))))
 | 
|---|
| 696 | 
 | 
|---|
| 697 | (defun compile-mouse-goto-error (event)
 | 
|---|
| 698 |   (interactive "e")
 | 
|---|
| 699 |   (save-excursion
 | 
|---|
| 700 |     (set-buffer (window-buffer (posn-window (event-end event))))
 | 
|---|
| 701 |     (goto-char (posn-point (event-end event)))
 | 
|---|
| 702 | 
 | 
|---|
| 703 |     (or (compilation-buffer-p (current-buffer))
 | 
|---|
| 704 |         (error "Not in a compilation buffer."))
 | 
|---|
| 705 |     (setq compilation-last-buffer (current-buffer))
 | 
|---|
| 706 |     (compile-reinitialize-errors nil (point))
 | 
|---|
| 707 | 
 | 
|---|
| 708 |     ;; Move to bol; the marker for the error on this line will point there.
 | 
|---|
| 709 |     (beginning-of-line)
 | 
|---|
| 710 | 
 | 
|---|
| 711 |     ;; Move compilation-error-list to the elt of compilation-old-error-list
 | 
|---|
| 712 |     ;; we want.
 | 
|---|
| 713 |     (setq compilation-error-list compilation-old-error-list)
 | 
|---|
| 714 |     (while (and compilation-error-list
 | 
|---|
| 715 |                 (> (point) (car (car compilation-error-list))))
 | 
|---|
| 716 |       (setq compilation-error-list (cdr compilation-error-list)))
 | 
|---|
| 717 |     (or compilation-error-list
 | 
|---|
| 718 |         (error "No error to go to")))
 | 
|---|
| 719 |   (select-window (posn-window (event-end event)))
 | 
|---|
| 720 |   ;; Move to another window, so that next-error's window changes
 | 
|---|
| 721 |   ;; result in the desired setup.
 | 
|---|
| 722 |   (or (one-window-p)
 | 
|---|
| 723 |       (progn
 | 
|---|
| 724 |         (other-window -1)
 | 
|---|
| 725 |         ;; other-window changed the selected buffer,
 | 
|---|
| 726 |         ;; but we didn't want to do that.
 | 
|---|
| 727 |         (set-buffer compilation-last-buffer)))
 | 
|---|
| 728 | 
 | 
|---|
| 729 |   (push-mark)
 | 
|---|
| 730 |   (next-error 1))
 | 
|---|
| 731 | 
 | 
|---|
| 732 | (defun compile-goto-error (&optional argp)
 | 
|---|
| 733 |   "Visit the source for the error message point is on.
 | 
|---|
| 734 | Use this command in a compilation log buffer.  Sets the mark at point there.
 | 
|---|
| 735 | \\[universal-argument] as a prefix arg means to reparse the buffer's error messages first;
 | 
|---|
| 736 | other kinds of prefix arguments are ignored."
 | 
|---|
| 737 |   (interactive "P")
 | 
|---|
| 738 |   (or (compilation-buffer-p (current-buffer))
 | 
|---|
| 739 |       (error "Not in a compilation buffer."))
 | 
|---|
| 740 |   (setq compilation-last-buffer (current-buffer))
 | 
|---|
| 741 |   (compile-reinitialize-errors (consp argp) (point))
 | 
|---|
| 742 | 
 | 
|---|
| 743 |   ;; Move to bol; the marker for the error on this line will point there.
 | 
|---|
| 744 |   (beginning-of-line)
 | 
|---|
| 745 | 
 | 
|---|
| 746 |   ;; Move compilation-error-list to the elt of compilation-old-error-list
 | 
|---|
| 747 |   ;; we want.
 | 
|---|
| 748 |   (setq compilation-error-list compilation-old-error-list)
 | 
|---|
| 749 |   (while (and compilation-error-list
 | 
|---|
| 750 |               (> (point) (car (car compilation-error-list))))
 | 
|---|
| 751 |     (setq compilation-error-list (cdr compilation-error-list)))
 | 
|---|
| 752 | 
 | 
|---|
| 753 |   ;; Move to another window, so that next-error's window changes
 | 
|---|
| 754 |   ;; result in the desired setup.
 | 
|---|
| 755 |   (or (one-window-p)
 | 
|---|
| 756 |       (progn
 | 
|---|
| 757 |         (other-window -1)
 | 
|---|
| 758 |         ;; other-window changed the selected buffer,
 | 
|---|
| 759 |         ;; but we didn't want to do that.
 | 
|---|
| 760 |         (set-buffer compilation-last-buffer)))
 | 
|---|
| 761 | 
 | 
|---|
| 762 |   (push-mark)
 | 
|---|
| 763 |   (next-error 1))
 | 
|---|
| 764 | 
 | 
|---|
| 765 | ;; Return a compilation buffer.
 | 
|---|
| 766 | ;; If the current buffer is a compilation buffer, return it.
 | 
|---|
| 767 | ;; If compilation-last-buffer is set to a live buffer, use that.
 | 
|---|
| 768 | ;; Otherwise, look for a compilation buffer and signal an error
 | 
|---|
| 769 | ;; if there are none.
 | 
|---|
| 770 | (defun compilation-find-buffer (&optional other-buffer)
 | 
|---|
| 771 |   (if (and (not other-buffer)
 | 
|---|
| 772 |            (compilation-buffer-p (current-buffer)))
 | 
|---|
| 773 |       ;; The current buffer is a compilation buffer.
 | 
|---|
| 774 |       (current-buffer)
 | 
|---|
| 775 |     (if (and compilation-last-buffer (buffer-name compilation-last-buffer)
 | 
|---|
| 776 |              (or (not other-buffer) (not (eq compilation-last-buffer
 | 
|---|
| 777 |                                              (current-buffer)))))
 | 
|---|
| 778 |         compilation-last-buffer
 | 
|---|
| 779 |       (let ((buffers (buffer-list)))
 | 
|---|
| 780 |         (while (and buffers (or (not (compilation-buffer-p (car buffers)))
 | 
|---|
| 781 |                                 (and other-buffer
 | 
|---|
| 782 |                                      (eq (car buffers) (current-buffer)))))
 | 
|---|
| 783 |           (setq buffers (cdr buffers)))
 | 
|---|
| 784 |         (if buffers
 | 
|---|
| 785 |             (car buffers)
 | 
|---|
| 786 |           (or (and other-buffer
 | 
|---|
| 787 |                    (compilation-buffer-p (current-buffer))
 | 
|---|
| 788 |                    ;; The current buffer is a compilation buffer.
 | 
|---|
| 789 |                    (progn
 | 
|---|
| 790 |                      (if other-buffer
 | 
|---|
| 791 |                          (message "This is the only compilation buffer."))
 | 
|---|
| 792 |                      (current-buffer)))
 | 
|---|
| 793 |               (error "No compilation started!")))))))
 | 
|---|
| 794 | 
 | 
|---|
| 795 | ;;;###autoload
 | 
|---|
| 796 | (defun next-error (&optional argp)
 | 
|---|
| 797 |   "Visit next compilation error message and corresponding source code.
 | 
|---|
| 798 | This operates on the output from the \\[compile] command.
 | 
|---|
| 799 | If all preparsed error messages have been processed,
 | 
|---|
| 800 | the error message buffer is checked for new ones.
 | 
|---|
| 801 | 
 | 
|---|
| 802 | A prefix arg specifies how many error messages to move;
 | 
|---|
| 803 | negative means move back to previous error messages.
 | 
|---|
| 804 | Just C-u as a prefix means reparse the error message buffer
 | 
|---|
| 805 | and start at the first error.
 | 
|---|
| 806 | 
 | 
|---|
| 807 | \\[next-error] normally applies to the most recent compilation started,
 | 
|---|
| 808 | but as long as you are in the middle of parsing errors from one compilation
 | 
|---|
| 809 | output buffer, you stay with that compilation output buffer.
 | 
|---|
| 810 | 
 | 
|---|
| 811 | Use \\[next-error] in a compilation output buffer to switch to
 | 
|---|
| 812 | processing errors from that compilation.
 | 
|---|
| 813 | 
 | 
|---|
| 814 | See variables `compilation-parse-errors-function' and
 | 
|---|
| 815 | \`compilation-error-regexp-alist' for customization ideas."
 | 
|---|
| 816 |   (interactive "P")
 | 
|---|
| 817 |   (setq compilation-last-buffer (compilation-find-buffer))
 | 
|---|
| 818 |   (compilation-goto-locus (compilation-next-error-locus
 | 
|---|
| 819 |                            ;; We want to pass a number here only if
 | 
|---|
| 820 |                            ;; we got a numeric prefix arg, not just C-u.
 | 
|---|
| 821 |                            (and (not (consp argp))
 | 
|---|
| 822 |                                 (prefix-numeric-value argp))
 | 
|---|
| 823 |                            (consp argp))))
 | 
|---|
| 824 | ;;;###autoload (define-key ctl-x-map "`" 'next-error)
 | 
|---|
| 825 | 
 | 
|---|
| 826 | (defun compilation-next-error-locus (&optional move reparse)
 | 
|---|
| 827 |   "Visit next compilation error and return locus in corresponding source code.
 | 
|---|
| 828 | This operates on the output from the \\[compile] command.
 | 
|---|
| 829 | If all preparsed error messages have been processed,
 | 
|---|
| 830 | the error message buffer is checked for new ones.
 | 
|---|
| 831 | 
 | 
|---|
| 832 | Returns a cons (ERROR . SOURCE) of two markers: ERROR is a marker at the
 | 
|---|
| 833 | location of the error message in the compilation buffer, and SOURCE is a
 | 
|---|
| 834 | marker at the location in the source code indicated by the error message.
 | 
|---|
| 835 | 
 | 
|---|
| 836 | Optional first arg MOVE says how many error messages to move forwards (or
 | 
|---|
| 837 | backwards, if negative); default is 1.  Optional second arg REPARSE, if
 | 
|---|
| 838 | non-nil, says to reparse the error message buffer and reset to the first
 | 
|---|
| 839 | error (plus MOVE - 1).
 | 
|---|
| 840 | 
 | 
|---|
| 841 | The current buffer should be the desired compilation output buffer."
 | 
|---|
| 842 |   (or move (setq move 1))
 | 
|---|
| 843 |   (compile-reinitialize-errors reparse nil (and (not reparse)
 | 
|---|
| 844 |                                                 (if (< move 1) 0 (1- move))))
 | 
|---|
| 845 |   (let (next-errors next-error)
 | 
|---|
| 846 |     (save-excursion
 | 
|---|
| 847 |       (set-buffer compilation-last-buffer)
 | 
|---|
| 848 |       ;; compilation-error-list points to the "current" error.
 | 
|---|
| 849 |       (setq next-errors 
 | 
|---|
| 850 |             (if (> move 0)
 | 
|---|
| 851 |                 (nthcdr (1- move)
 | 
|---|
| 852 |                         compilation-error-list)
 | 
|---|
| 853 |               ;; Zero or negative arg; we need to move back in the list.
 | 
|---|
| 854 |               (let ((n (1- move))
 | 
|---|
| 855 |                     (i 0)
 | 
|---|
| 856 |                     (e compilation-old-error-list))
 | 
|---|
| 857 |                 ;; See how many cdrs away the current error is from the start.
 | 
|---|
| 858 |                 (while (not (eq e compilation-error-list))
 | 
|---|
| 859 |                   (setq i (1+ i)
 | 
|---|
| 860 |                         e (cdr e)))
 | 
|---|
| 861 |                 (if (> (- n) i)
 | 
|---|
| 862 |                     (error "Moved back past first error")
 | 
|---|
| 863 |                   (nthcdr (+ i n) compilation-old-error-list))))
 | 
|---|
| 864 |             next-error (car next-errors))
 | 
|---|
| 865 |       (while
 | 
|---|
| 866 |           (if (null next-error)
 | 
|---|
| 867 |               (progn
 | 
|---|
| 868 |                 (and move (/= move 1)
 | 
|---|
| 869 |                      (error (if (> move 0)
 | 
|---|
| 870 |                                 "Moved past last error")
 | 
|---|
| 871 |                             "Moved back past first error"))
 | 
|---|
| 872 |                 (compilation-forget-errors)
 | 
|---|
| 873 |                 (error (concat compilation-error-message
 | 
|---|
| 874 |                                (and (get-buffer-process (current-buffer))
 | 
|---|
| 875 |                                     (eq (process-status
 | 
|---|
| 876 |                                          (get-buffer-process
 | 
|---|
| 877 |                                           (current-buffer)))
 | 
|---|
| 878 |                                         'run)
 | 
|---|
| 879 |                                     " yet"))))
 | 
|---|
| 880 |             (setq compilation-error-list (cdr next-errors))
 | 
|---|
| 881 |             (if (null (cdr next-error))
 | 
|---|
| 882 |                 ;; This error is boring.  Go to the next.
 | 
|---|
| 883 |                 t
 | 
|---|
| 884 |               (or (markerp (cdr next-error))
 | 
|---|
| 885 |                   ;; This error has a filename/lineno pair.
 | 
|---|
| 886 |                   ;; Find the file and turn it into a marker.
 | 
|---|
| 887 |                   (let* ((fileinfo (car (cdr next-error)))
 | 
|---|
| 888 |                          (buffer (compilation-find-file (cdr fileinfo)
 | 
|---|
| 889 |                                                         (car fileinfo)
 | 
|---|
| 890 |                                                         (car next-error))))
 | 
|---|
| 891 |                     (if (null buffer)
 | 
|---|
| 892 |                         ;; We can't find this error's file.
 | 
|---|
| 893 |                         ;; Remove all errors in the same file.
 | 
|---|
| 894 |                         (progn
 | 
|---|
| 895 |                           (setq next-errors compilation-old-error-list)
 | 
|---|
| 896 |                           (while next-errors
 | 
|---|
| 897 |                             (and (consp (cdr (car next-errors)))
 | 
|---|
| 898 |                                  (equal (car (cdr (car next-errors)))
 | 
|---|
| 899 |                                         fileinfo)
 | 
|---|
| 900 |                                  (progn
 | 
|---|
| 901 |                                    (set-marker (car (car next-errors)) nil)
 | 
|---|
| 902 |                                    (setcdr (car next-errors) nil)))
 | 
|---|
| 903 |                             (setq next-errors (cdr next-errors)))
 | 
|---|
| 904 |                           ;; Look for the next error.
 | 
|---|
| 905 |                           t)
 | 
|---|
| 906 |                       ;; We found the file.  Get a marker for this error.
 | 
|---|
| 907 |                       ;; compilation-old-error-list is a buffer-local
 | 
|---|
| 908 |                       ;; variable, so we must be careful to extract its value
 | 
|---|
| 909 |                       ;; before switching to the source file buffer.
 | 
|---|
| 910 |                       (let ((errors compilation-old-error-list)
 | 
|---|
| 911 |                             (last-line (nth 1 (cdr next-error)))
 | 
|---|
| 912 |                             (column (nth 2 (cdr next-error))))
 | 
|---|
| 913 |                         (set-buffer buffer)
 | 
|---|
| 914 |                         (save-excursion
 | 
|---|
| 915 |                           (save-restriction
 | 
|---|
| 916 |                             (widen)
 | 
|---|
| 917 |                             (goto-line last-line)
 | 
|---|
| 918 |                             (if column
 | 
|---|
| 919 |                                 (move-to-column column)
 | 
|---|
| 920 |                               (beginning-of-line))
 | 
|---|
| 921 |                             (setcdr next-error (point-marker))
 | 
|---|
| 922 |                             ;; Make all the other error messages referring
 | 
|---|
| 923 |                             ;; to the same file have markers into the buffer.
 | 
|---|
| 924 |                             (while errors
 | 
|---|
| 925 |                               (and (consp (cdr (car errors)))
 | 
|---|
| 926 |                                    (equal (car (cdr (car errors))) fileinfo)
 | 
|---|
| 927 |                                    (let* ((this (nth 1 (cdr (car errors))))
 | 
|---|
| 928 |                                           (column (nth 2 (cdr (car errors))))
 | 
|---|
| 929 |                                           (lines (- this last-line)))
 | 
|---|
| 930 |                                      (if (eq selective-display t)
 | 
|---|
| 931 |                                          ;; When selective-display is t,
 | 
|---|
| 932 |                                          ;; each C-m is a line boundary,
 | 
|---|
| 933 |                                          ;; as well as each newline.
 | 
|---|
| 934 |                                          (if (< lines 0)
 | 
|---|
| 935 |                                              (re-search-backward "[\n\C-m]"
 | 
|---|
| 936 |                                                                  nil 'end
 | 
|---|
| 937 |                                                                  (- lines))
 | 
|---|
| 938 |                                            (re-search-forward "[\n\C-m]"
 | 
|---|
| 939 |                                                               nil 'end
 | 
|---|
| 940 |                                                               lines))
 | 
|---|
| 941 |                                        (forward-line lines))
 | 
|---|
| 942 |                                      (if column
 | 
|---|
| 943 |                                          (move-to-column column))
 | 
|---|
| 944 |                                      (setq last-line this)
 | 
|---|
| 945 |                                      (setcdr (car errors) (point-marker))))
 | 
|---|
| 946 |                               (setq errors (cdr errors)))))))))
 | 
|---|
| 947 |               ;; If we didn't get a marker for this error, or this
 | 
|---|
| 948 |               ;; marker's buffer was killed, go on to the next one.
 | 
|---|
| 949 |               (or (not (markerp (cdr next-error)))
 | 
|---|
| 950 |                   (not (marker-buffer (cdr next-error))))))
 | 
|---|
| 951 |         (setq next-errors compilation-error-list
 | 
|---|
| 952 |               next-error (car next-errors))))
 | 
|---|
| 953 | 
 | 
|---|
| 954 |     ;; Skip over multiple error messages for the same source location,
 | 
|---|
| 955 |     ;; so the next C-x ` won't go to an error in the same place.
 | 
|---|
| 956 |     (while (and compilation-error-list
 | 
|---|
| 957 |                 (equal (cdr (car compilation-error-list)) (cdr next-error)))
 | 
|---|
| 958 |       (setq compilation-error-list (cdr compilation-error-list)))
 | 
|---|
| 959 | 
 | 
|---|
| 960 |     ;; We now have a marker for the position of the error source code.
 | 
|---|
| 961 |     ;; NEXT-ERROR is a cons (ERROR . SOURCE) of two markers.
 | 
|---|
| 962 |     next-error))
 | 
|---|
| 963 | 
 | 
|---|
| 964 | (defun compilation-goto-locus (next-error)
 | 
|---|
| 965 |   "Jump to an error locus returned by `compilation-next-error-locus'.
 | 
|---|
| 966 | Takes one argument, a cons (ERROR . SOURCE) of two markers.
 | 
|---|
| 967 | Selects a window with point at SOURCE, with another window displaying ERROR."
 | 
|---|
| 968 |   (if (and (window-dedicated-p (selected-window))
 | 
|---|
| 969 |            (eq (selected-window) (frame-root-window)))
 | 
|---|
| 970 |       (switch-to-buffer-other-frame (marker-buffer (cdr next-error)))
 | 
|---|
| 971 |     (switch-to-buffer (marker-buffer (cdr next-error))))
 | 
|---|
| 972 |   (goto-char (cdr next-error))
 | 
|---|
| 973 |   ;; If narrowing got in the way of
 | 
|---|
| 974 |   ;; going to the right place, widen.
 | 
|---|
| 975 |   (or (= (point) (marker-position (cdr next-error)))
 | 
|---|
| 976 |       (progn
 | 
|---|
| 977 |         (widen)
 | 
|---|
| 978 |         (goto-char (cdr next-error))))
 | 
|---|
| 979 | 
 | 
|---|
| 980 |   ;; Show compilation buffer in other window, scrolled to this error.
 | 
|---|
| 981 |   (let* ((pop-up-windows t)
 | 
|---|
| 982 |          (w (display-buffer (marker-buffer (car next-error)))))
 | 
|---|
| 983 |     (set-window-point w (car next-error))
 | 
|---|
| 984 |     (set-window-start w (car next-error))))
 | 
|---|
| 985 |  | 
|---|
| 986 | 
 | 
|---|
| 987 | ;; Find a buffer for file FILENAME.
 | 
|---|
| 988 | ;; Search the directories in compilation-search-path.
 | 
|---|
| 989 | ;; A nil in compilation-search-path means to try the
 | 
|---|
| 990 | ;; current directory, which is passed in DIR.
 | 
|---|
| 991 | ;; If FILENAME is not found at all, ask the user where to find it.
 | 
|---|
| 992 | ;; Pop up the buffer containing MARKER and scroll to MARKER if we ask the user.
 | 
|---|
| 993 | (defun compilation-find-file (filename dir marker)
 | 
|---|
| 994 |   (let ((dirs compilation-search-path)
 | 
|---|
| 995 |         result name)
 | 
|---|
| 996 |     (while (and dirs (null result))
 | 
|---|
| 997 |       (setq name (expand-file-name filename (or (car dirs) dir))
 | 
|---|
| 998 |             result (and (file-exists-p name)
 | 
|---|
| 999 |                         (find-file-noselect name))
 | 
|---|
| 1000 |             dirs (cdr dirs)))
 | 
|---|
| 1001 |     (or result
 | 
|---|
| 1002 |         ;; The file doesn't exist.
 | 
|---|
| 1003 |         ;; Ask the user where to find it.
 | 
|---|
| 1004 |         ;; If he hits C-g, then the next time he does
 | 
|---|
| 1005 |         ;; next-error, he'll skip past it.
 | 
|---|
| 1006 |         (progn
 | 
|---|
| 1007 |           (let* ((pop-up-windows t)
 | 
|---|
| 1008 |                  (w (display-buffer (marker-buffer marker))))
 | 
|---|
| 1009 |             (set-window-point w marker)
 | 
|---|
| 1010 |             (set-window-start w marker))
 | 
|---|
| 1011 |           (setq name
 | 
|---|
| 1012 |                 (expand-file-name
 | 
|---|
| 1013 |                  (read-file-name
 | 
|---|
| 1014 |                   (format "Find this error in: (default %s) "
 | 
|---|
| 1015 |                           filename) dir filename t)))
 | 
|---|
| 1016 |           (if (file-directory-p name)
 | 
|---|
| 1017 |               (setq name (concat (file-name-as-directory name) filename)))
 | 
|---|
| 1018 |           (if (file-exists-p name)
 | 
|---|
| 1019 |               (find-file-noselect name))))))
 | 
|---|
| 1020 | 
 | 
|---|
| 1021 | ;; Set compilation-error-list to nil, and unchain the markers that point to the
 | 
|---|
| 1022 | ;; error messages and their text, so that they no longer slow down gap motion.
 | 
|---|
| 1023 | ;; This would happen anyway at the next garbage collection, but it is better to
 | 
|---|
| 1024 | ;; do it right away.
 | 
|---|
| 1025 | (defun compilation-forget-errors ()
 | 
|---|
| 1026 |   (while compilation-old-error-list
 | 
|---|
| 1027 |     (let ((next-error (car compilation-old-error-list)))
 | 
|---|
| 1028 |       (set-marker (car next-error) nil)
 | 
|---|
| 1029 |       (if (markerp (cdr next-error))
 | 
|---|
| 1030 |           (set-marker (cdr next-error) nil)))
 | 
|---|
| 1031 |     (setq compilation-old-error-list (cdr compilation-old-error-list)))
 | 
|---|
| 1032 |   (setq compilation-error-list nil
 | 
|---|
| 1033 |         compilation-directory-stack nil
 | 
|---|
| 1034 |         compilation-parsing-end 1))
 | 
|---|
| 1035 | 
 | 
|---|
| 1036 | 
 | 
|---|
| 1037 | (defun count-regexp-groupings (regexp)
 | 
|---|
| 1038 |   "Return the number of \\( ... \\) groupings in REGEXP (a string)."
 | 
|---|
| 1039 |   (let ((groupings 0)
 | 
|---|
| 1040 |         (len (length regexp))
 | 
|---|
| 1041 |         (i 0)
 | 
|---|
| 1042 |         c)
 | 
|---|
| 1043 |     (while (< i len)
 | 
|---|
| 1044 |       (setq c (aref regexp i)
 | 
|---|
| 1045 |             i (1+ i))
 | 
|---|
| 1046 |       (cond ((= c ?\[)
 | 
|---|
| 1047 |              ;; Find the end of this [...].
 | 
|---|
| 1048 |              (while (and (< i len)
 | 
|---|
| 1049 |                          (not (= (aref regexp i) ?\])))
 | 
|---|
| 1050 |                (setq i (1+ i))))
 | 
|---|
| 1051 |             ((= c ?\\)
 | 
|---|
| 1052 |              (if (< i len)
 | 
|---|
| 1053 |                  (progn
 | 
|---|
| 1054 |                    (setq c (aref regexp i)
 | 
|---|
| 1055 |                          i (1+ i))
 | 
|---|
| 1056 |                    (if (= c ?\))
 | 
|---|
| 1057 |                        ;; We found the end of a grouping,
 | 
|---|
| 1058 |                        ;; so bump our counter.
 | 
|---|
| 1059 |                        (setq groupings (1+ groupings))))))))
 | 
|---|
| 1060 |     groupings))
 | 
|---|
| 1061 | 
 | 
|---|
| 1062 | (defun compilation-parse-errors (limit-search find-at-least)
 | 
|---|
| 1063 |   "Parse the current buffer as grep, cc or lint error messages.
 | 
|---|
| 1064 | See variable `compilation-parse-errors-function' for the interface it uses."
 | 
|---|
| 1065 |   (setq compilation-error-list nil)
 | 
|---|
| 1066 |   (message "Parsing error messages...")
 | 
|---|
| 1067 |   (let (text-buffer orig orig-expanded parent-expanded
 | 
|---|
| 1068 |         regexp enter-group leave-group error-group
 | 
|---|
| 1069 |         alist subexpr error-regexp-groups
 | 
|---|
| 1070 |         (found-desired nil)
 | 
|---|
| 1071 |         (compilation-num-errors-found 0))
 | 
|---|
| 1072 | 
 | 
|---|
| 1073 |     ;; Don't reparse messages already seen at last parse.
 | 
|---|
| 1074 |     (goto-char compilation-parsing-end)
 | 
|---|
| 1075 |     ;; Don't parse the first two lines as error messages.
 | 
|---|
| 1076 |     ;; This matters for grep.
 | 
|---|
| 1077 |     (if (bobp)
 | 
|---|
| 1078 |         (progn
 | 
|---|
| 1079 |           (forward-line 2)
 | 
|---|
| 1080 |           ;; Move back so point is before the newline.
 | 
|---|
| 1081 |           ;; This matters because some error regexps use \n instead of ^
 | 
|---|
| 1082 |           ;; to be faster.
 | 
|---|
| 1083 |           (forward-char -1)))
 | 
|---|
| 1084 | 
 | 
|---|
| 1085 |     ;; Compile all the regexps we want to search for into one.
 | 
|---|
| 1086 |     (setq regexp (concat "\\(" compilation-enter-directory-regexp "\\)\\|"
 | 
|---|
| 1087 |                          "\\(" compilation-leave-directory-regexp "\\)\\|"
 | 
|---|
| 1088 |                          "\\(" (mapconcat (function
 | 
|---|
| 1089 |                                            (lambda (elt)
 | 
|---|
| 1090 |                                              (concat "\\(" (car elt) "\\)")))
 | 
|---|
| 1091 |                                           compilation-error-regexp-alist
 | 
|---|
| 1092 |                                           "\\|") "\\)"))
 | 
|---|
| 1093 | 
 | 
|---|
| 1094 |     ;; Find out how many \(...\) groupings are in each of the regexps, and set
 | 
|---|
| 1095 |     ;; *-GROUP to the grouping containing each constituent regexp (whose
 | 
|---|
| 1096 |     ;; subgroups will come immediately thereafter) of the big regexp we have
 | 
|---|
| 1097 |     ;; just constructed.
 | 
|---|
| 1098 |     (setq enter-group 1
 | 
|---|
| 1099 |           leave-group (+ enter-group
 | 
|---|
| 1100 |                          (count-regexp-groupings
 | 
|---|
| 1101 |                           compilation-enter-directory-regexp)
 | 
|---|
| 1102 |                          1)
 | 
|---|
| 1103 |           error-group (+ leave-group
 | 
|---|
| 1104 |                          (count-regexp-groupings
 | 
|---|
| 1105 |                           compilation-leave-directory-regexp)
 | 
|---|
| 1106 |                          1))
 | 
|---|
| 1107 | 
 | 
|---|
| 1108 |     ;; Compile an alist (IDX FILE LINE [COL]), where IDX is the number of
 | 
|---|
| 1109 |     ;; the subexpression for an entire error-regexp, and FILE and LINE (and
 | 
|---|
| 1110 |     ;; possibly COL) are the numbers for the subexpressions giving the file
 | 
|---|
| 1111 |     ;; name and line number (and possibly column number).
 | 
|---|
| 1112 |     (setq alist (or compilation-error-regexp-alist
 | 
|---|
| 1113 |                     (error "compilation-error-regexp-alist is empty!"))
 | 
|---|
| 1114 |           subexpr (1+ error-group))
 | 
|---|
| 1115 |     (while alist
 | 
|---|
| 1116 |       (setq error-regexp-groups
 | 
|---|
| 1117 |             (cons (list subexpr
 | 
|---|
| 1118 |                         (+ subexpr (nth 1 (car alist)))
 | 
|---|
| 1119 |                         (+ subexpr (nth 2 (car alist)))
 | 
|---|
| 1120 |                         (and (nth 3 (car alist))
 | 
|---|
| 1121 |                              (+ subexpr (nth 3 (car alist)))))
 | 
|---|
| 1122 |                   error-regexp-groups))
 | 
|---|
| 1123 |       (setq subexpr (+ subexpr 1 (count-regexp-groupings (car (car alist)))))
 | 
|---|
| 1124 |       (setq alist (cdr alist)))
 | 
|---|
| 1125 | 
 | 
|---|
| 1126 |     (setq orig default-directory)
 | 
|---|
| 1127 |     (setq orig-expanded (file-truename orig))
 | 
|---|
| 1128 |     (setq parent-expanded (expand-file-name "../" orig-expanded))
 | 
|---|
| 1129 | 
 | 
|---|
| 1130 |     (while (and (not found-desired)
 | 
|---|
| 1131 |                 ;; We don't just pass LIMIT-SEARCH to re-search-forward
 | 
|---|
| 1132 |                 ;; because we want to find matches containing LIMIT-SEARCH
 | 
|---|
| 1133 |                 ;; but which extend past it.
 | 
|---|
| 1134 |                 (re-search-forward regexp nil t))
 | 
|---|
| 1135 | 
 | 
|---|
| 1136 |       ;; Figure out which constituent regexp matched.
 | 
|---|
| 1137 |       (cond ((match-beginning enter-group)
 | 
|---|
| 1138 |              ;; The match was the enter-directory regexp.
 | 
|---|
| 1139 |              (let ((dir
 | 
|---|
| 1140 |                     (file-name-as-directory
 | 
|---|
| 1141 |                      (expand-file-name
 | 
|---|
| 1142 |                       (buffer-substring (match-beginning (+ enter-group 1))
 | 
|---|
| 1143 |                                         (match-end (+ enter-group 1)))))))
 | 
|---|
| 1144 |                ;; The directory name in the "entering" message
 | 
|---|
| 1145 |                ;; is a truename.  Try to convert it to a form
 | 
|---|
| 1146 |                ;; like what the user typed in.
 | 
|---|
| 1147 |                (setq dir
 | 
|---|
| 1148 |                      (compile-abbreviate-directory dir orig orig-expanded
 | 
|---|
| 1149 |                                                    parent-expanded))
 | 
|---|
| 1150 |                (setq compilation-directory-stack
 | 
|---|
| 1151 |                      (cons dir compilation-directory-stack))
 | 
|---|
| 1152 |                (and (file-directory-p dir)
 | 
|---|
| 1153 |                     (setq default-directory dir)))
 | 
|---|
| 1154 | 
 | 
|---|
| 1155 |              (and limit-search (>= (point) limit-search)
 | 
|---|
| 1156 |                   ;; The user wanted a specific error, and we're past it.
 | 
|---|
| 1157 |                   ;; We do this check here (and in the leave-group case)
 | 
|---|
| 1158 |                   ;; rather than at the end of the loop because if the last
 | 
|---|
| 1159 |                   ;; thing seen is an error message, we must carefully
 | 
|---|
| 1160 |                   ;; discard the last error when it is the first in a new
 | 
|---|
| 1161 |                   ;; file (see below in the error-group case).
 | 
|---|
| 1162 |                   (setq found-desired t)))
 | 
|---|
| 1163 | 
 | 
|---|
| 1164 |             ((match-beginning leave-group)
 | 
|---|
| 1165 |              ;; The match was the leave-directory regexp.
 | 
|---|
| 1166 |              (let ((beg (match-beginning (+ leave-group 1)))
 | 
|---|
| 1167 |                    (stack compilation-directory-stack))
 | 
|---|
| 1168 |                (if beg
 | 
|---|
| 1169 |                    (let ((dir
 | 
|---|
| 1170 |                           (file-name-as-directory
 | 
|---|
| 1171 |                            (expand-file-name
 | 
|---|
| 1172 |                             (buffer-substring beg
 | 
|---|
| 1173 |                                               (match-end (+ leave-group
 | 
|---|
| 1174 |                                                             1)))))))
 | 
|---|
| 1175 |                      ;; The directory name in the "entering" message
 | 
|---|
| 1176 |                      ;; is a truename.  Try to convert it to a form
 | 
|---|
| 1177 |                      ;; like what the user typed in.
 | 
|---|
| 1178 |                      (setq dir
 | 
|---|
| 1179 |                            (compile-abbreviate-directory dir orig orig-expanded
 | 
|---|
| 1180 |                                                          parent-expanded))
 | 
|---|
| 1181 |                      (while (and stack
 | 
|---|
| 1182 |                                  (not (string-equal (car stack) dir)))
 | 
|---|
| 1183 |                        (setq stack (cdr stack)))))
 | 
|---|
| 1184 |                (setq compilation-directory-stack (cdr stack))
 | 
|---|
| 1185 |                (setq stack (car compilation-directory-stack))
 | 
|---|
| 1186 |                (if stack
 | 
|---|
| 1187 |                    (setq default-directory stack))
 | 
|---|
| 1188 |                )
 | 
|---|
| 1189 | 
 | 
|---|
| 1190 |              (and limit-search (>= (point) limit-search)
 | 
|---|
| 1191 |                   ;; The user wanted a specific error, and we're past it.
 | 
|---|
| 1192 |                   ;; We do this check here (and in the enter-group case)
 | 
|---|
| 1193 |                   ;; rather than at the end of the loop because if the last
 | 
|---|
| 1194 |                   ;; thing seen is an error message, we must carefully
 | 
|---|
| 1195 |                   ;; discard the last error when it is the first in a new
 | 
|---|
| 1196 |                   ;; file (see below in the error-group case).
 | 
|---|
| 1197 |                   (setq found-desired t)))
 | 
|---|
| 1198 | 
 | 
|---|
| 1199 |             ((match-beginning error-group)
 | 
|---|
| 1200 |              ;; The match was the composite error regexp.
 | 
|---|
| 1201 |              ;; Find out which individual regexp matched.
 | 
|---|
| 1202 |              (setq alist error-regexp-groups)
 | 
|---|
| 1203 |              (while (and alist
 | 
|---|
| 1204 |                          (null (match-beginning (car (car alist)))))
 | 
|---|
| 1205 |                (setq alist (cdr alist)))
 | 
|---|
| 1206 |              (if alist
 | 
|---|
| 1207 |                  (setq alist (car alist))
 | 
|---|
| 1208 |                (error "compilation-parse-errors: impossible regexp match!"))
 | 
|---|
| 1209 |              
 | 
|---|
| 1210 |              ;; Extract the file name and line number from the error message.
 | 
|---|
| 1211 |              (let ((beginning-of-match (match-beginning 0)) ;looking-at nukes
 | 
|---|
| 1212 |                    (filename (buffer-substring (match-beginning (nth 1 alist))
 | 
|---|
| 1213 |                                                (match-end (nth 1 alist))))
 | 
|---|
| 1214 |                    (linenum (string-to-int
 | 
|---|
| 1215 |                              (buffer-substring
 | 
|---|
| 1216 |                               (match-beginning (nth 2 alist))
 | 
|---|
| 1217 |                               (match-end (nth 2 alist)))))
 | 
|---|
| 1218 |                    (column (and (nth 3 alist)
 | 
|---|
| 1219 |                                 (string-to-int
 | 
|---|
| 1220 |                                  (buffer-substring
 | 
|---|
| 1221 |                                   (match-beginning (nth 3 alist))
 | 
|---|
| 1222 |                                   (match-end (nth 3 alist)))))))
 | 
|---|
| 1223 | 
 | 
|---|
| 1224 |                ;; Check for a comint-file-name-prefix and prepend it if
 | 
|---|
| 1225 |                ;; appropriate.  (This is very useful for
 | 
|---|
| 1226 |                ;; compilation-minor-mode in an rlogin-mode buffer.)
 | 
|---|
| 1227 |                (and (boundp 'comint-file-name-prefix)
 | 
|---|
| 1228 |                     ;; If the file name is relative, default-directory will
 | 
|---|
| 1229 |                     ;; already contain the comint-file-name-prefix (done by
 | 
|---|
| 1230 |                     ;; compile-abbreviate-directory).
 | 
|---|
| 1231 |                     (file-name-absolute-p filename)
 | 
|---|
| 1232 |                     (setq filename (concat comint-file-name-prefix filename)))
 | 
|---|
| 1233 |                (setq filename (cons default-directory filename))
 | 
|---|
| 1234 | 
 | 
|---|
| 1235 |                ;; Locate the erring file and line.
 | 
|---|
| 1236 |                ;; Cons a new elt onto compilation-error-list,
 | 
|---|
| 1237 |                ;; giving a marker for the current compilation buffer
 | 
|---|
| 1238 |                ;; location, and the file and line number of the error.
 | 
|---|
| 1239 |                (save-excursion
 | 
|---|
| 1240 |                  (beginning-of-line 1)
 | 
|---|
| 1241 |                  (let ((this (cons (point-marker)
 | 
|---|
| 1242 |                                    (list filename linenum column))))
 | 
|---|
| 1243 |                    ;; Don't add the same source line more than once.
 | 
|---|
| 1244 |                    (if (equal (cdr this) (cdr (car compilation-error-list)))
 | 
|---|
| 1245 |                        nil
 | 
|---|
| 1246 |                      (setq compilation-error-list
 | 
|---|
| 1247 |                            (cons this
 | 
|---|
| 1248 |                                  compilation-error-list))
 | 
|---|
| 1249 |                      (setq compilation-num-errors-found
 | 
|---|
| 1250 |                            (1+ compilation-num-errors-found)))))
 | 
|---|
| 1251 |                (and (or (and find-at-least (> compilation-num-errors-found
 | 
|---|
| 1252 |                                               find-at-least))
 | 
|---|
| 1253 |                         (and limit-search (>= (point) limit-search)))
 | 
|---|
| 1254 |                     ;; We have found as many new errors as the user wants,
 | 
|---|
| 1255 |                     ;; or past the buffer position he indicated.  We
 | 
|---|
| 1256 |                     ;; continue to parse until we have seen all the
 | 
|---|
| 1257 |                     ;; consecutive errors in the same file, so the error
 | 
|---|
| 1258 |                     ;; positions will be recorded as markers in this buffer
 | 
|---|
| 1259 |                     ;; that might change.
 | 
|---|
| 1260 |                     (cdr compilation-error-list) ; Must check at least two.
 | 
|---|
| 1261 |                     (not (equal (car (cdr (nth 0 compilation-error-list)))
 | 
|---|
| 1262 |                                 (car (cdr (nth 1 compilation-error-list)))))
 | 
|---|
| 1263 |                     (progn
 | 
|---|
| 1264 |                       ;; Discard the error just parsed, so that the next
 | 
|---|
| 1265 |                       ;; parsing run can get it and the following errors in
 | 
|---|
| 1266 |                       ;; the same file all at once.  If we didn't do this, we
 | 
|---|
| 1267 |                       ;; would have the same problem we are trying to avoid
 | 
|---|
| 1268 |                       ;; with the test above, just delayed until the next run!
 | 
|---|
| 1269 |                       (setq compilation-error-list
 | 
|---|
| 1270 |                             (cdr compilation-error-list))
 | 
|---|
| 1271 |                       (goto-char beginning-of-match)
 | 
|---|
| 1272 |                       (setq found-desired t)))
 | 
|---|
| 1273 |                )
 | 
|---|
| 1274 |              )
 | 
|---|
| 1275 |             (t
 | 
|---|
| 1276 |              (error "compilation-parse-errors: known groups didn't match!")))
 | 
|---|
| 1277 | 
 | 
|---|
| 1278 |       (message "Parsing error messages...%d (%.0f%% of buffer)"
 | 
|---|
| 1279 |                compilation-num-errors-found
 | 
|---|
| 1280 |                ;; Use floating-point because (* 100 (point)) frequently
 | 
|---|
| 1281 |                ;; exceeds the range of Emacs Lisp integers.
 | 
|---|
| 1282 |                (/ (* 100.0 (point)) (point-max)))
 | 
|---|
| 1283 | 
 | 
|---|
| 1284 |       (and limit-search (>= (point) limit-search)
 | 
|---|
| 1285 |            ;; The user wanted a specific error, and we're past it.
 | 
|---|
| 1286 |            (setq found-desired t)))
 | 
|---|
| 1287 |     (setq compilation-parsing-end (if found-desired
 | 
|---|
| 1288 |                                       (point)
 | 
|---|
| 1289 |                                     ;; We have searched the whole buffer.
 | 
|---|
| 1290 |                                     (point-max))))
 | 
|---|
| 1291 |   (setq compilation-error-list (nreverse compilation-error-list))
 | 
|---|
| 1292 |   (message "Parsing error messages...done"))
 | 
|---|
| 1293 | 
 | 
|---|
| 1294 | ;; If directory DIR is a subdir of ORIG or of ORIG's parent,
 | 
|---|
| 1295 | ;; return a relative name for it starting from ORIG or its parent.
 | 
|---|
| 1296 | ;; ORIG-EXPANDED is an expanded version of ORIG.
 | 
|---|
| 1297 | ;; PARENT-EXPANDED is an expanded version of ORIG's parent.
 | 
|---|
| 1298 | ;; Those two args could be computed here, but we run faster by
 | 
|---|
| 1299 | ;; having the caller compute them just once.
 | 
|---|
| 1300 | (defun compile-abbreviate-directory (dir orig orig-expanded parent-expanded)
 | 
|---|
| 1301 |   ;; Check for a comint-file-name-prefix and prepend it if appropriate.
 | 
|---|
| 1302 |   ;; (This is very useful for compilation-minor-mode in an rlogin-mode
 | 
|---|
| 1303 |   ;; buffer.)
 | 
|---|
| 1304 |   (if (boundp 'comint-file-name-prefix)
 | 
|---|
| 1305 |       (setq dir (concat comint-file-name-prefix dir)))
 | 
|---|
| 1306 | 
 | 
|---|
| 1307 |   (if (and (> (length dir) (length orig-expanded))
 | 
|---|
| 1308 |            (string= orig-expanded
 | 
|---|
| 1309 |                     (substring dir 0 (length orig-expanded))))
 | 
|---|
| 1310 |       (setq dir
 | 
|---|
| 1311 |             (concat orig
 | 
|---|
| 1312 |                     (substring dir (length orig-expanded)))))
 | 
|---|
| 1313 |   (if (and (> (length dir) (length parent-expanded))
 | 
|---|
| 1314 |            (string= parent-expanded
 | 
|---|
| 1315 |                     (substring dir 0 (length parent-expanded))))
 | 
|---|
| 1316 |     (setq dir
 | 
|---|
| 1317 |           (concat (file-name-directory
 | 
|---|
| 1318 |                    (directory-file-name orig))
 | 
|---|
| 1319 |                   (substring dir (length parent-expanded)))))
 | 
|---|
| 1320 |   dir)
 | 
|---|
| 1321 | 
 | 
|---|
| 1322 | (provide 'compile)
 | 
|---|
| 1323 | 
 | 
|---|
| 1324 | ;;; compile.el ends here
 | 
|---|