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