Mercurial > hg > xemacs-beta
view lisp/oobr/eif-ise-er.el @ 120:cca96a509cfe r20-1b12
Import from CVS: tag r20-1b12
author | cvs |
---|---|
date | Mon, 13 Aug 2007 09:25:29 +0200 |
parents | 4be1180a9e89 |
children |
line wrap: on
line source
;;!emacs ;; ;; FILE: eif-ise-er.el ;; SUMMARY: Parses ISE's Eiffel error messages; compiles Eiffel classes. ;; USAGE: GNU Emacs Lisp Library ;; KEYWORDS: oop, tools ;; ;; AUTHOR: Bob Weiner ;; ORG: InfoDock Associates ;; ;; ORIG-DATE: 7-Dec-89 at 00:17:18 ;; LAST-MOD: 31-Oct-96 at 22:39:09 by Bob Weiner ;; ;; Copyright (C) 1989-1996 Free Software Foundation, Inc. ;; See the file BR-COPY for license information. ;; ;; This file is part of the OO-Browser. ;; ;; DESCRIPTION: ;; ;; 'eif-ec' compiles an Eiffel class. ;; 'eif-es' compiles an Eiffel system. ;; ;; Load this library and then invoke error parsing via {C-x `}. ;; See the GNU Emacs Manual for an explanation of error parsing. ;; ;; 'eif-ise-next-error' bound to {C-x `} parses ISE Eiffel compiler ;; error messages. As in: ;; ;; "my_class", 16: syntax error : Keyword 'expanded' may not be used as identifier ;; ;; Only handles compilation lines of the following form: ;; ;; <compiler> [<option> ... <option>] <pathname> ;; ;; Requires the 'br-class-path', 'br-build-sys-paths-htable', and ;; 'br-build-paths-htable' functions from the OO-Browser 'br-lib' package. ;; This is used to determine the full pathname for the source code of each ;; class since ISE does not include any pathname information in its error ;; messages. ;; ;; ;; To reset the {C-x `} key to parse non-Eiffel error messages, use: ;; ;; {M-x load-lib RET compile RET} ;; ;; DESCRIP-END. (require 'br-lib) (require 'br-eif) (require 'compile) (global-set-key "\C-x`" 'eif-ise-next-error) (and (boundp 'eiffel-mode-map) (define-key eiffel-mode-map "\C-c!" 'eif-ec)) (setq compilation-error-regexp "\"\\([^ \t]+\\)\", \\([0-9]+\\):.*") (defconst eif-compile-dir nil "Default directory in which to invoke an Eiffel compile command.") (defconst eif-compile-cmd "ec" "Default command name with which to invoke the Eiffel compiler.") (defun eif-ise-next-error (&optional argp) "Visit next compilation error message and corresponding source code. This operates on the output from the \\[compile] command. If all preparsed error messages have been processed, the error message buffer is checked for new ones. A non-nil argument (prefix arg, if interactive) means reparse the error message buffer and start at the first error." (interactive "P") (if (or (eq compilation-error-list t) argp) (progn (compilation-forget-errors) (setq compilation-parsing-end 1))) (if compilation-error-list nil (save-excursion (switch-to-buffer "*compilation*") (set-buffer-modified-p nil) (eif-ise-compilation-parse-errors))) (let ((next-error (car compilation-error-list))) (if (null next-error) (error (concat compilation-error-message (if (and compilation-process (eq (process-status compilation-process) 'run)) " yet" "")))) (setq compilation-error-list (cdr compilation-error-list)) (if (null (car (cdr next-error))) nil (switch-to-buffer (marker-buffer (car (cdr next-error)))) (goto-char (car (cdr next-error))) (set-marker (car (cdr next-error)) nil)) (let* ((pop-up-windows t) (w (display-buffer (marker-buffer (car next-error))))) (set-window-point w (car next-error)) (set-window-start w (car next-error))) (set-marker (car next-error) nil))) (defun eif-ise-compilation-filename () "Return a string which is the last filename from the compilation command. Ignore quotes around it. Return nil if no filename was given." ;; First arg of compile cmd should be filename (if (string-match "^.*[ \t]+\\([^ \t\"]+\\)" compile-command) (substring compile-command (match-beginning 1) (match-end 1)))) (defun eif-ise-compilation-parse-errors () "Parse the current buffer as error messages. This makes a list of error descriptors, compilation-error-list. For each error line-number in the buffer, the source file is read in, and the text location is saved in compilation-error-list. The function next-error, assigned to \\[next-error], takes the next error off the list and visits its location." (setq compilation-error-list nil) (message "Parsing error messages...") (let (text-buffer last-filename last-linenum) ;; Don't reparse messages already seen at last parse. (goto-char compilation-parsing-end) ;; Don't parse the first two lines as error messages. ;; This matters for grep. (if (bobp) (forward-line 2)) (let (class-name case-fold-search linenum filename error-marker text-marker) (while (re-search-forward compilation-error-regexp nil t) ;; Extract line number from error message. (setq linenum (string-to-int (buffer-substring (match-beginning 2) (match-end 2)))) ;; Extract class name from error message and convert to the full ;; pathname of the class' source file. (setq class-name (downcase (buffer-substring (match-beginning 1) (match-end 1))) filename (br-class-path class-name)) (if (null filename) ; No matching class name in lookup table. (progn (message "Rebuilding Eiffel system class locations table...") (sit-for 2) (call-interactively 'br-build-sys-classes-htable) ; Typically pretty fast (message "Rebuilding Eiffel system class locations table...Done") (setq filename (br-class-path class-name)) (if (null filename) (error (format "'%s' not in lookup table, use {M-x br-build-paths-htable RET} to update." class-name))))) ;; Locate the erring file and line. (if (and (equal filename last-filename) (= linenum last-linenum)) nil (beginning-of-line 1) (setq error-marker (point-marker)) ;; text-buffer gets the buffer containing this error's file. (if (not (equal filename last-filename)) (setq text-buffer (and (file-exists-p (setq last-filename filename)) (if (boundp 'br-find-file-noselect-function) (set-buffer (funcall br-find-file-noselect-function filename)) (find-file-noselect filename))) last-linenum 0)) (if text-buffer ;; Go to that buffer and find the erring line. (save-excursion (set-buffer text-buffer) (if (zerop last-linenum) (progn (goto-char 1) (setq last-linenum 1))) (forward-line (- linenum last-linenum)) (setq last-linenum linenum) (setq text-marker (point-marker)) (setq compilation-error-list (cons (list error-marker text-marker) compilation-error-list))))) (forward-line 1))) (setq compilation-parsing-end (point-max))) (message "Parsing error messages...done") (setq compilation-error-list (nreverse compilation-error-list))) ;;; The following version of 'eif-ec' courtesy of: ;;; Heinz W. Schmidt hws@icsi.berkeley.edu ;;; International Computer Science Institute (415) 643-9153 x175 ;;; 1947 Center Street, Ste. 600 /\/\|;; CLOS saves time and ;;; Berkeley, CA 94704 \/\/|-- Eiffel is faster ;;; 2/11/90 ;;; With a number of Bob Weiner's modifications (defun str2argv (STR) (if (string-match "[^ ]" STR) (let ((arg1 (read-from-string STR))) (cons (prin1-to-string (car arg1)) (str2argv (substring STR (cdr arg1))))))) (defvar eif-ec-args "" "Default arguments to send to the Eiffel ec class compiler.") (defun eif-ec (ARG &optional CMD DIR CLASS-NAME) "Calls Eiffel compiler. Compile with optional CMD, 'eif-compile-cmd' or \"ec\". By default, the compiler is called on the file associated with the current buffer. With numeric argument 0 prompts for explicit command line arguments. Other numeric arguments allow you to insert options or further class names." (interactive "P") (setq CLASS-NAME (or CLASS-NAME (let ((fn (file-name-nondirectory buffer-file-name))) (substring fn 0 (- (length fn) 2)))) ec-dir (or DIR eif-compile-dir (file-name-directory buffer-file-name))) (let* ((ec-output (get-buffer-create "*compilation*")) (ec-process (get-buffer-process ec-output)) (curr-buffer (current-buffer))) (if ec-process (if (y-or-n-p "Kill current Eiffel compilation process? ") (delete-process ec-process) (error "Can't ec concurrently."))) (if (and (buffer-modified-p) (y-or-n-p (format "Save file %s? " buffer-file-name))) (progn (save-buffer) (message ""))) ;; Maybe prompt for args and dispatch according to numeric ARG. (setq eif-ec-args (if ARG (read-string "ec args: " eif-ec-args) "")) ;; Switch to shell buffer and run ec. (set-buffer ec-output) (erase-buffer) ;; Move to directory and trim classname so ec works in situations ;; like: ec -t class1 <CLASS-NAME> (cd ec-dir) (insert (or CMD eif-compile-cmd "ec") (if ARG (format " %s" eif-ec-args) "") (format " %s" (if (not (and ARG (zerop ARG))) CLASS-NAME "")) "\n") (set-buffer curr-buffer) (display-buffer ec-output) (eval (append '(start-process "ec" ec-output (or CMD eif-compile-cmd "ec")) (str2argv eif-ec-args) (if (not (and ARG (zerop ARG))) (list CLASS-NAME)))))) (defun eif-es (&optional dir) "Compile Eiffel system with es." (interactive) (eif-ec nil "es" dir "")) (provide 'eif-ise-er)