Annotation of GNUtools/emacs/lisp/compile.el, revision 1.1.1.1

1.1       root        1: ;; Run compiler as inferior of Emacs, and parse its error messages.
                      2: ;; Copyright (C) 1985, 1986 Free Software Foundation, Inc.
                      3: 
                      4: ;; This file is part of GNU Emacs.
                      5: 
                      6: ;; GNU Emacs is free software; you can redistribute it and/or modify
                      7: ;; it under the terms of the GNU General Public License as published by
                      8: ;; the Free Software Foundation; either version 1, or (at your option)
                      9: ;; any later version.
                     10: 
                     11: ;; GNU Emacs is distributed in the hope that it will be useful,
                     12: ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
                     13: ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     14: ;; GNU General Public License for more details.
                     15: 
                     16: ;; You should have received a copy of the GNU General Public License
                     17: ;; along with GNU Emacs; see the file COPYING.  If not, write to
                     18: ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
                     19: 
                     20: (provide 'compile)
                     21: 
                     22: (defvar compilation-process nil
                     23:   "Process created by compile command, or nil if none exists now.
                     24: Note that the process may have been \"deleted\" and still
                     25: be the value of this variable.")
                     26: 
                     27: (defvar compilation-error-list nil
                     28:   "List of error message descriptors for visiting erring functions.
                     29: Each error descriptor is a list of length two.
                     30: Its car is a marker pointing to an error message.
                     31: Its cadr is a marker pointing to the text of the line the message is about,
                     32:   or nil if that is not interesting.
                     33: The value may be t instead of a list;
                     34: this means that the buffer of error messages should be reparsed
                     35: the next time the list of errors is wanted.")
                     36: 
                     37: (defvar compilation-parsing-end nil
                     38:   "Position of end of buffer when last error messages parsed.")
                     39: 
                     40: (defvar compilation-error-message nil
                     41:   "Message to print when no more matches for compilation-error-regexp are found")
                     42: 
                     43: ;; The filename excludes colons to avoid confusion when error message
                     44: ;; starts with digits.
                     45: (defvar compilation-error-regexp
                     46:   "\\([^ :\n]+\\(: *\\|, line \\|(\\)[0-9]+\\)\\|\\([0-9]+ *of *[^ \n]+\\)"
                     47:   "Regular expression for filename/linenumber in error in compilation log.")
                     48: 
                     49: (defun compile (command)
                     50:   "Compile the program including the current buffer.  Default: run `make'.
                     51: Runs COMMAND, a shell command, in a separate process asynchronously
                     52: with output going to the buffer *compilation*.
                     53: You can then use the command \\[next-error] to find the next error message
                     54: and move to the source code that caused it."
                     55:   (interactive (list (read-string "Compile command: " compile-command)))
                     56:   (setq compile-command command)
                     57:   (compile1 compile-command "No more errors"))
                     58: 
                     59: (defun grep (command)
                     60:   "Run grep, with user-specified args, and collect output in a buffer.
                     61: While grep runs asynchronously, you can use the \\[next-error] command
                     62: to find the text that grep hits refer to."
                     63:   (interactive "sRun grep (with args): ")
                     64:   (compile1 (concat "grep -n " command " /dev/null")
                     65:            "No more grep hits" "grep"))
                     66: 
                     67: (defun compile1 (command error-message &optional name-of-mode)
                     68:   (save-some-buffers)
                     69:   (if compilation-process
                     70:       (if (or (not (eq (process-status compilation-process) 'run))
                     71:              (yes-or-no-p "A compilation process is running; kill it? "))
                     72:          (condition-case ()
                     73:              (if compilation-process
                     74:                  (let ((comp-proc compilation-process))
                     75:                    (interrupt-process comp-proc)
                     76:                    (sit-for 1)
                     77:                    (delete-process comp-proc)))
                     78:            (error nil))
                     79:        (error "Cannot have two compilation processes")))
                     80:   (setq compilation-process nil)
                     81:   (compilation-forget-errors)
                     82:   (setq compilation-error-list t)
                     83:   (setq compilation-error-message error-message)
                     84:   (setq compilation-process
                     85:        (start-process "compilation" "*compilation*"
                     86:                       shell-file-name
                     87:                       "-c" (concat "exec " command)))
                     88:   (with-output-to-temp-buffer "*compilation*"
                     89:     (princ "cd ")
                     90:     (princ default-directory)
                     91:     (terpri)
                     92:     (princ command)
                     93:     (terpri))
                     94:   (set-process-sentinel compilation-process 'compilation-sentinel)
                     95:   (let* ((thisdir default-directory)
                     96:         (outbuf (process-buffer compilation-process))
                     97:         (outwin (get-buffer-window outbuf))
                     98:         (regexp compilation-error-regexp))
                     99:     (if (eq outbuf (current-buffer))
                    100:        (goto-char (point-max)))
                    101:     (save-excursion
                    102:       (set-buffer outbuf)
                    103:       (buffer-flush-undo outbuf)
                    104:       (let ((start (save-excursion (set-buffer outbuf) (point-min))))
                    105:        (set-window-start outwin start)
                    106:        (or (eq outwin (selected-window))
                    107:            (set-window-point outwin start)))
                    108:       (setq default-directory thisdir)
                    109:       (fundamental-mode)
                    110:       (make-local-variable 'compilation-error-regexp)
                    111:       (setq compilation-error-regexp regexp)
                    112:       (setq mode-name (or name-of-mode "Compilation"))
                    113:       ;; Make log buffer's mode line show process state
                    114:       (setq mode-line-process '(": %s")))))
                    115: 
                    116: ;; Called when compilation process changes state.
                    117: 
                    118: (defun compilation-sentinel (proc msg)
                    119:   (cond ((null (buffer-name (process-buffer proc)))
                    120:         ;; buffer killed
                    121:         (set-process-buffer proc nil))
                    122:        ((memq (process-status proc) '(signal exit))
                    123:         (let* ((obuf (current-buffer))
                    124:                omax opoint)
                    125:           ;; save-excursion isn't the right thing if
                    126:           ;;  process-buffer is current-buffer
                    127:           (unwind-protect
                    128:               (progn
                    129:                 ;; Write something in *compilation* and hack its mode line,
                    130:                 (set-buffer (process-buffer proc))
                    131:                 (setq omax (point-max) opoint (point))
                    132:                 (goto-char (point-max))
                    133:                 (insert ?\n mode-name " " msg)
                    134:                 (forward-char -1)
                    135:                 (insert " at "
                    136:                         (substring (current-time-string) 0 -5))
                    137:                 (forward-char 1)
                    138:                 (setq mode-line-process
                    139:                       (concat ": "
                    140:                               (symbol-name (process-status proc))))
                    141:                 ;; If buffer and mode line will show that the process
                    142:                 ;; is dead, we can delete it now.  Otherwise it
                    143:                 ;; will stay around until M-x list-processes.
                    144:                 (delete-process proc))
                    145:             (setq compilation-process nil)
                    146:             ;; Force mode line redisplay soon
                    147:             (set-buffer-modified-p (buffer-modified-p)))
                    148:           (if (and opoint (< opoint omax))
                    149:               (goto-char opoint))
                    150:           (set-buffer obuf)))))
                    151: 
                    152: (defun kill-compilation ()
                    153:   "Kill the process made by the \\[compile] command."
                    154:   (interactive)
                    155:   (if compilation-process
                    156:       (interrupt-process compilation-process)))
                    157: 
                    158: (defun kill-grep ()
                    159:   "Kill the process made by the \\[grep] command."
                    160:   (interactive)
                    161:   (if compilation-process
                    162:       (interrupt-process compilation-process)))
                    163: 
                    164: (defun next-error (&optional argp)
                    165:   "Visit next compilation error message and corresponding source code.
                    166: This operates on the output from the \\[compile] command.
                    167: If all preparsed error messages have been processed,
                    168: the error message buffer is checked for new ones.
                    169: A non-nil argument (prefix arg, if interactive)
                    170: means reparse the error message buffer and start at the first error."
                    171:   (interactive "P")
                    172:   (if (or (eq compilation-error-list t)
                    173:          argp)
                    174:       (progn (compilation-forget-errors)
                    175:             (setq compilation-parsing-end 1)))
                    176:   (if compilation-error-list
                    177:       nil
                    178:     (save-excursion
                    179:       (set-buffer "*compilation*")
                    180:       (set-buffer-modified-p nil)
                    181:       (compilation-parse-errors)))
                    182:   (let ((next-error (car compilation-error-list)))
                    183:     (if (null next-error)
                    184:        (error (concat compilation-error-message
                    185:                       (if (and compilation-process
                    186:                                (eq (process-status compilation-process)
                    187:                                    'run))
                    188:                           " yet" ""))))
                    189:     (setq compilation-error-list (cdr compilation-error-list))
                    190:     (if (null (car (cdr next-error)))
                    191:        nil
                    192:       (switch-to-buffer (marker-buffer (car (cdr next-error))))
                    193:       (goto-char (car (cdr next-error)))
                    194:       (set-marker (car (cdr next-error)) nil))
                    195:     (let* ((pop-up-windows t)
                    196:           (w (display-buffer (marker-buffer (car next-error)))))
                    197:       (set-window-point w (car next-error))
                    198:       (set-window-start w (car next-error)))
                    199:     (set-marker (car next-error) nil)))
                    200: 
                    201: ;; Set compilation-error-list to nil, and
                    202: ;; unchain the markers that point to the error messages and their text,
                    203: ;; so that they no longer slow down gap motion.
                    204: ;; This would happen anyway at the next garbage collection,
                    205: ;; but it is better to do it right away.
                    206: (defun compilation-forget-errors ()
                    207:   (if (eq compilation-error-list t)
                    208:       (setq compilation-error-list nil))
                    209:   (while compilation-error-list
                    210:     (let ((next-error (car compilation-error-list)))
                    211:       (set-marker (car next-error) nil)
                    212:       (if (car (cdr next-error))
                    213:          (set-marker (car (cdr next-error)) nil)))
                    214:     (setq compilation-error-list (cdr compilation-error-list))))
                    215: 
                    216: (defun compilation-parse-errors ()
                    217:   "Parse the current buffer as error messages.
                    218: This makes a list of error descriptors, compilation-error-list.
                    219: For each source-file, line-number pair in the buffer,
                    220: the source file is read in, and the text location is saved in compilation-error-list.
                    221: The function next-error, assigned to \\[next-error], takes the next error off the list
                    222: and visits its location."
                    223:   (setq compilation-error-list nil)
                    224:   (message "Parsing error messages...")
                    225:   (let (text-buffer
                    226:        last-filename last-linenum)
                    227:     ;; Don't reparse messages already seen at last parse.
                    228:     (goto-char compilation-parsing-end)
                    229:     ;; Don't parse the first two lines as error messages.
                    230:     ;; This matters for grep.
                    231:     (if (bobp)
                    232:        (forward-line 2))
                    233:     (while (re-search-forward compilation-error-regexp nil t)
                    234:       (let (linenum filename
                    235:            error-marker text-marker)
                    236:        ;; Extract file name and line number from error message.
                    237:        (save-restriction
                    238:          (narrow-to-region (match-beginning 0) (match-end 0))
                    239:          (goto-char (point-max))
                    240:          (skip-chars-backward "[0-9]")
                    241:          ;; If it's a lint message, use the last file(linenum) on the line.
                    242:          ;; Normally we use the first on the line.
                    243:          (if (= (preceding-char) ?\()
                    244:              (progn
                    245:                (narrow-to-region (point-min) (1+ (buffer-size)))
                    246:                (end-of-line)
                    247:                (re-search-backward compilation-error-regexp)
                    248:                (skip-chars-backward "^ \t\n")
                    249:                (narrow-to-region (point) (match-end 0))
                    250:                (goto-char (point-max))
                    251:                (skip-chars-backward "[0-9]")))
                    252:          ;; Are we looking at a "filename-first" or "line-number-first" form?
                    253:          (if (looking-at "[0-9]")
                    254:              (progn
                    255:                (setq linenum (read (current-buffer)))
                    256:                (goto-char (point-min)))
                    257:            ;; Line number at start, file name at end.
                    258:            (progn
                    259:              (goto-char (point-min))
                    260:              (setq linenum (read (current-buffer)))
                    261:              (goto-char (point-max))
                    262:              (skip-chars-backward "^ \t\n")))
                    263:          (setq filename (compilation-grab-filename)))
                    264:        ;; Locate the erring file and line.
                    265:        (if (and (equal filename last-filename)
                    266:                 (= linenum last-linenum))
                    267:            nil
                    268:          (beginning-of-line 1)
                    269:          (setq error-marker (point-marker))
                    270:          ;; text-buffer gets the buffer containing this error's file.
                    271:          (if (not (equal filename last-filename))
                    272:              (setq text-buffer
                    273:                    (and (file-exists-p (setq last-filename filename))
                    274:                         (find-file-noselect filename))
                    275:                    last-linenum 0))
                    276:          (if text-buffer
                    277:              ;; Go to that buffer and find the erring line.
                    278:              (save-excursion
                    279:                (set-buffer text-buffer)
                    280:                (if (zerop last-linenum)
                    281:                    (progn
                    282:                      (goto-char 1)
                    283:                      (setq last-linenum 1)))
                    284:                ;; Move the right number of lines from the old position.
                    285:                ;; If we can't move that many, put 0 in last-linenum
                    286:                ;; so the next error message will be handled starting from
                    287:                ;; scratch.
                    288:                (if (eq selective-display t)
                    289:                    (or (re-search-forward "[\n\C-m]" nil 'end
                    290:                                           (- linenum last-linenum))
                    291:                        (setq last-linenum 0))
                    292:                  (or (= 0 (forward-line (- linenum last-linenum)))
                    293:                      (setq last-linenum 0)))
                    294:                (setq last-linenum linenum)
                    295:                (setq text-marker (point-marker))
                    296:                (setq compilation-error-list
                    297:                      (cons (list error-marker text-marker)
                    298:                            compilation-error-list)))))
                    299:        (forward-line 1)))
                    300:     (setq compilation-parsing-end (point-max)))
                    301:   (message "Parsing error messages...done")
                    302:   (setq compilation-error-list (nreverse compilation-error-list)))
                    303: 
                    304: (defun compilation-grab-filename ()
                    305:   "Return a string which is a filename, starting at point.
                    306: Ignore quotes and parentheses around it, as well as trailing colons."
                    307:   (if (eq (following-char) ?\")
                    308:       (save-restriction
                    309:        (narrow-to-region (point)
                    310:                          (progn (forward-sexp 1) (point)))
                    311:        (goto-char (point-min))
                    312:        (read (current-buffer)))
                    313:     (buffer-substring (point)
                    314:                      (progn
                    315:                        (skip-chars-forward "^ :,\n\t(")
                    316:                        (point)))))
                    317: 
                    318: (define-key ctl-x-map "`" 'next-error)

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.