Mercurial > hg > xemacs-beta
diff lisp/ilisp/ilisp-src.el @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children | b82b59fe008d |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lisp/ilisp/ilisp-src.el Mon Aug 13 08:45:50 2007 +0200 @@ -0,0 +1,639 @@ +;;; -*- Mode: Emacs-Lisp -*- + +;;; ilisp-src.el -- + +;;; This file is part of ILISP. +;;; Version: 5.7 +;;; +;;; Copyright (C) 1990, 1991, 1992, 1993 Chris McConnell +;;; 1993, 1994 Ivan Vasquez +;;; 1994, 1995 Marco Antoniotti and Rick Busdiecker +;;; +;;; Other authors' names for which this Copyright notice also holds +;;; may appear later in this file. +;;; +;;; Send mail to 'ilisp-request@lehman.com' to be included in the +;;; ILISP mailing list. 'ilisp@lehman.com' is the general ILISP +;;; mailing list were bugs and improvements are discussed. +;;; +;;; ILISP is freely redistributable under the terms found in the file +;;; COPYING. + + + +;;; See ilisp.el for more information. + +;;;%Source file operations +(if (not (boundp 'tags-file-name)) (defvar tags-file-name nil)) +(defvar lisp-last-definition nil "Last definition (name type) looked for.") +(defvar lisp-last-file nil "Last used source file.") +(defvar lisp-first-point nil "First point found in last source file.") +(defvar lisp-last-point nil "Last point in last source file.") +(defvar lisp-last-locator nil "Last source locator used.") +(defvar lisp-search nil "Set to T when searching for definitions.") +(defvar lisp-using-tags nil "Set to T when using tags.") + +;;;%%lisp-directory +(defvar lisp-edit-files t + "If T, then buffers in one of lisp-source-modes will be searched by +edit-definitions-lisp if the source cannot be found through the +inferior LISP. It can also be a list of files to edit definitions +from set up by \(\\[lisp-directory]). If it is set to nil, then no +additional files will be searched.") + +;;; +(defun lisp-extensions () + "Return a regexp for matching the extensions of files that enter one +of lisp-source-modes according to auto-mode-alist." + (let ((entries auto-mode-alist) + (extensions nil)) + (while entries + (let ((entry (car entries))) + (if (memq (cdr entry) lisp-source-modes) + (setq extensions + (concat "\\|" (car entry) extensions)))) + (setq entries (cdr entries))) + (substring extensions 2))) + +;;; +(defun lisp-directory (directory add) + "Edit the files in DIRECTORY that have an auto-mode alist entry in +lisp-source-modes. With a positive prefix, add the files on to the +already existing files. With a negative prefix, clear the list. In +either case set tags-file-name to nil so that tags are not used." + (interactive + (list (if (not (eq current-prefix-arg '-)) + (read-file-name "Lisp Directory: " + nil + default-directory + nil)) + current-prefix-arg)) + (setq tags-file-name nil) + (if (eq add '-) + (progn (setq lisp-edit-files t) + (message "No current lisp directory")) + (if add + (message "Added %s as a lisp directory" directory) + (message "%s is the lisp directory" directory)) + (setq directory (expand-file-name directory)) + (if (file-directory-p directory) + (setq lisp-edit-files + (append + (directory-files directory t (lisp-extensions)) + (if add (if (eq lisp-edit-files t) nil lisp-edit-files)))) + (error "%s is not a directory" directory)))) + +;;;%%Utilities + +(defun fix-source-filenames () + "Apply the ilisp-source-directory-fixup-alist to the current buffer + (which will be *Edit-Definitions*) to change any pre-compiled + source-file locations to point to local source file locations. + See ilisp-source-directory-fixup-alist." + (let ((alist (ilisp-value 'ilisp-source-directory-fixup-alist t)) + cons) + (if alist + (save-excursion + (while alist + (setq cons (car alist)) + (goto-char (point-min)) + (if (re-search-forward (car cons) (point-max) t) + (replace-match (cdr cons))) + (setq alist (cdr alist))))))) + +(defun lisp-setup-edit-definitions (message edit-files) + "Set up *Edit-Definitions* with MESSAGE. If EDIT-FILES is T, insert +all buffer filenames that are in one of lisp-source-modes into the +current buffer. If it is a list of files set up by lisp-directory, +insert those in the buffer. If it is a string put that in the buffer." + (setq lisp-using-tags nil + lisp-search (not (stringp edit-files))) + (set-buffer (get-buffer-create "*Edit-Definitions*")) + (erase-buffer) + (insert message) + (insert "\n\n") + (if edit-files + (progn + (if (eq edit-files t) + (let ((buffers (buffer-list))) + (while buffers + (let ((buffer (car buffers))) + (if (save-excursion + (set-buffer buffer) + (and (memq major-mode lisp-source-modes) + (buffer-file-name buffer))) + (progn (insert ?\") (insert (buffer-file-name buffer)) + (insert "\"\n")))) + (setq buffers (cdr buffers)))) + (if (stringp edit-files) + (progn (insert edit-files) + ;; Remove garbage collection messages + (replace-regexp "^;[^\n]*\n" "") + (fix-source-filenames)) + (let ((files edit-files)) + (while files + (insert ?\") + (insert (car files)) + (insert "\"\n") + (setq files (cdr files)))))) + (goto-char (point-min)) + (forward-line 2) + (set-buffer-modified-p nil)) + (error + (substitute-command-keys + "Use \\[lisp-directory] to define source files.")))) + +;;; +(defun lisp-locate-definition (locator definition file point + &optional + back pop) + "Use LOCATOR to find the next DEFINITION (symbol . type) in FILE +starting at POINT, optionally BACKWARDS and POP to buffer. Return T +if successful." + (if file + (if (not (file-exists-p file)) + (progn + (message "File %s doesn't exist!" file) + (sit-for 1) + nil) + (let* ((symbol (car definition)) + (type (cdr definition)) + (first (not (eq lisp-last-file file))) + (buffer (current-buffer)) + name) + (lisp-find-file file pop) + (if first (setq lisp-first-point (point))) + (if back + (if first + (goto-char (point-max)) + (goto-char point) + (forward-line -1) + (end-of-line)) + (goto-char point) + (if (not first) + (progn (forward-line 1) (beginning-of-line)))) + (if (eq type 't) + (message "Search %s for %s" file symbol) + (message "Searching %s for %s %s" file type + (setq name (lisp-buffer-symbol symbol)))) + (if (funcall locator symbol type first back) + (progn + (setq lisp-last-file file + lisp-last-point (point)) + (if (bolp) + (forward-line -1) + (beginning-of-line)) + (recenter 0) + (if name + (message "Found %s %s definition" type name) + (message "Found %s")) + t) + (if first + (goto-char lisp-first-point) + (set-buffer buffer) + (goto-char point)) + nil))))) + +;;; +(defun lisp-next-file (back) + "Return the next filename in *Edit-Definitions*, or nil if none." + (let ((file t) + result) + (set-buffer (get-buffer-create "*Edit-Definitions*")) + (if back + (progn (forward-line -1) + (if (looking-at "\n") + (progn + (forward-line 1) + (end-of-line) + (setq file nil))))) + (if file + (progn + (skip-chars-forward "^\"") + (if (eobp) + (progn (bury-buffer (current-buffer)) + (setq result nil)) + (let* ((start (progn (forward-char 1) (point)))) + (skip-chars-forward "^\"") + (setq file + (prog1 (buffer-substring start (point)) + (end-of-line))) + (bury-buffer (current-buffer)))))) + (if (not (eq file 't)) file))) + +;;; +(defun lisp-next-definition (back pop) + "Go to the next definition from *Edit-Definitions* going BACK with +prefix and POPPING. Return 'first if found first time, 'none if no +definition ever, T if another definition is found, and nil if no more +definitions are found." + (let ((done nil) + (result nil)) + (while + (not + (or + (setq result + (lisp-locate-definition ;Same file + lisp-last-locator + lisp-last-definition lisp-last-file lisp-last-point back)) + (let ((file (lisp-next-file back))) + (if file + (if (lisp-locate-definition + lisp-last-locator lisp-last-definition + file 1 back + (prog1 pop (setq pop nil))) + (setq result 'first) + (setq result (if (not lisp-search) 'none))) + t))))) + (set-buffer (window-buffer (selected-window))) + result)) + +;;;%%Next-definition +(defun next-definition-lisp (back &optional pop) + "Edit the next definition from *Edit-Definitions* going BACK with +prefix and optionally POPPING or call tags-loop-continue if using tags." + (interactive "P") + (if lisp-using-tags + (tags-loop-continue) + (let* ((result (lisp-next-definition back pop)) + (symbol (car lisp-last-definition)) + (type (cdr lisp-last-definition)) + (name (if (not (eq type 't)) (lisp-buffer-symbol symbol)))) + (cond ((or (eq result 'first) (eq result 't)) + (if name + (message "Found %s %s definition" type name) + (message "Found %s" symbol))) + ((eq result 'none) + (error "Can't find %s %s definition" type name)) + (t + (if name + (error "No more %s %s definitions" type name) + (message "Done"))))))) + + +;;;%%Edit-definitions +(defun edit-definitions-lisp (symbol type &optional stay search locator) + "Find the source files for the TYPE definitions of SYMBOL. If STAY, +use the same window. If SEARCH, do not look for symbol in inferior +LISP. The definition will be searched for through the inferior LISP +and if not found it will be searched for in the current tags file and +if not found in the files in lisp-edit-files set up by +\(\\[lisp-directory]) or the buffers in one of lisp-source-modes if +lisp-edit-files is T. If lisp-edit-files is nil, no search will be +done if not found through the inferior LISP. TYPES are from +ilisp-source-types which is an alist of symbol strings or list +strings. With a negative prefix, look for the current symbol as the +first type in ilisp-source-types." + (interactive + (let* ((types (ilisp-value 'ilisp-source-types t)) + (default (if types (car (car types)))) + (function (lisp-function-name)) + (symbol (lisp-buffer-symbol function))) + (if (lisp-minus-prefix) + (list function default) + (list (ilisp-read-symbol + (format "Edit Definition [%s]: " symbol) + function + nil + t) + (if types + (ilisp-completing-read + (format "Type [%s]: " default) + types default)))))) + (let* ((name (lisp-buffer-symbol symbol)) + (symbol-name (lisp-symbol-name symbol)) + (command (ilisp-value 'ilisp-find-source-command t)) + (source + (if (and command (not search) (comint-check-proc ilisp-buffer)) + (ilisp-send + (format command symbol-name + (lisp-symbol-package symbol) + type) + (concat "Finding " type " " name " definitions") + 'source ) + "nil")) + (result (and source (lisp-last-line source))) + (source-ok (not (or (ilisp-value 'comint-errorp t) + (null result) + (string-match "nil" (car result))))) + (case-fold-search t) + (tagged nil)) + (unwind-protect + (if (and tags-file-name (not source-ok)) + (progn (setq lisp-using-tags t) + (if (string-match "Lucid" emacs-version) + (find-tag symbol-name stay) + (find-tag symbol-name nil stay)) + (setq tagged t))) + (if (not tagged) + (progn + (setq lisp-last-definition (cons symbol type) + lisp-last-file nil + lisp-last-locator (or locator (ilisp-value 'ilisp-locator))) + (lisp-setup-edit-definitions + (format "%s %s definitions:" type name) + (if source-ok (cdr result) lisp-edit-files)) + (next-definition-lisp nil t)))))) + +;;;%%Searching +(defun lisp-locate-search (pattern type first back) + "Find PATTERN in the current buffer." + (if back + (search-backward pattern nil t) + (search-forward pattern nil t))) + +;;; +(defun lisp-locate-regexp (regexp type first back) + "Find REGEXP in the current buffer." + (if back + (re-search-backward regexp nil t) + (re-search-forward regexp nil t))) + +;;; +(defvar lisp-last-pattern nil "Last search regexp.") +(defun search-lisp (pattern regexp) + "Search for PATTERN through the files in lisp-edit-files if it is a +list and the current buffers in one of lisp-source-modes otherwise. +If lisp-edit-files is nil, no search will be done. If called with a +prefix, search for regexp. If there is a tags file, call tags-search instead." + (interactive + (list (read-string (if current-prefix-arg + "Search for regexp: " + "Search for: ") lisp-last-pattern) + current-prefix-arg)) + (if tags-file-name + (progn (setq lisp-using-tags t) + (tags-search (if regexp pattern (regexp-quote pattern)))) + (setq lisp-last-pattern pattern + lisp-last-definition (cons pattern t) + lisp-last-file nil + lisp-last-locator (if regexp + 'lisp-locate-regexp + 'lisp-locate-search)) + (lisp-setup-edit-definitions (format "Searching for %s:" pattern) + lisp-edit-files) + (next-definition-lisp nil nil))) + +;;;%%Replacing +(defvar lisp-last-replace nil "Last replace regexp.") +(defun replace-lisp (old new regexp) + "Query replace OLD by NEW through the files in lisp-edit-files if it +is a list and the current buffers in one of lisp-source-modes +otherwise. If lisp-edit-files is nil, no search will be done. If +called with a prefix, replace regexps. If there is a tags file, then +call tags-query-replace instead." + (interactive + (let ((old (read-string (if current-prefix-arg + "Replace regexp: " + "Replace: ") lisp-last-pattern))) + (list old + (read-string (if current-prefix-arg + (format "Replace regexp %s by: " old) + (format "Replace %s by: " old)) + lisp-last-replace) + current-prefix-arg))) + (if tags-file-name + (progn (setq lisp-using-tags t) + (tags-query-replace (if regexp old (regexp-quote old)) + new)) + (setq lisp-last-pattern old + lisp-last-replace new) + (lisp-setup-edit-definitions + (format "Replacing %s by %s:\n\n" old new) + lisp-edit-files) + (let (file) + (while (setq file (lisp-next-file nil)) + (lisp-find-file file) + (let ((point (point))) + (goto-char (point-min)) + (if (if regexp + (re-search-forward old nil t) + (search-forward old nil t)) + (progn (beginning-of-line) + (if regexp + (query-replace-regexp old new) + (query-replace old new))) + (goto-char point))))))) + +;;;%%Edit-callers +(defvar lisp-callers nil + "T if we found callers through inferior LISP.") + +;;; +(defun who-calls-lisp (function &optional no-show) + "Put the functions that call FUNCTION into the buffer *All-Callers* +and show it unless NO-SHOW is T. Return T if successful." + (interactive + (let* ((function (lisp-defun-name)) + (symbol (lisp-buffer-symbol function))) + (if (lisp-minus-prefix) + (list function) + (list (ilisp-read-symbol + (format "Who Calls [%s]: " symbol) + function + t t))))) + (let* ((name (lisp-buffer-symbol function)) + (command (ilisp-value 'ilisp-callers-command t)) + (callers + (if command + (ilisp-send + (format command + (lisp-symbol-name function) + (lisp-symbol-package function)) + (concat "Finding callers of " name) + 'callers))) + (last-line (lisp-last-line callers)) + (case-fold-search t)) + (set-buffer (get-buffer-create "*All-Callers*")) + (erase-buffer) + (insert (format "All callers of function %s:\n\n" name)) + (if (and command (not (ilisp-value 'comint-errorp t))) + (if (string-match "nil" (car last-line)) + (error "%s has no callers" name) + (message "") + (insert (cdr last-line)) + (goto-char (point-min)) + ;; Remove garbage collection messages + (replace-regexp "^;[^\n]*\n" "") + (goto-char (point-min)) + (forward-line 2) + (if (not no-show) + (if (ilisp-temp-buffer-show-function) + (funcall (ilisp-temp-buffer-show-function) + (get-buffer "*All-Callers*")) + (view-buffer "*All-Callers*"))) + t) + (insert "Using the current source files to find callers.") + nil))) + +;;; +(defun next-caller-lisp (back &optional pop) + "Edit the next caller from *All-Callers*. With prefix, edit +the previous caller. If it can't get caller information from the +inferior LISP, this will search using the current source files. See +lisp-directory." + (interactive "P") + (if (not lisp-callers) + (next-definition-lisp back pop) + (set-buffer (get-buffer-create "*All-Callers*")) + (if back (forward-line -1)) + (skip-chars-forward " \t\n") + (if (eobp) + (progn + (bury-buffer (current-buffer)) + (error "No more callers")) + (let* ((start (point)) + (caller-function + (progn + (skip-chars-forward "^ \t\n") + (buffer-substring start (point))))) + (bury-buffer (current-buffer)) + (edit-definitions-lisp (lisp-string-to-symbol caller-function) + (car (car (ilisp-value 'ilisp-source-types))) + (not pop)))))) + +;;; +(defun edit-callers-lisp (function) + "Edit the callers of FUNCTION. With a minus prefix use the symbol +at the start of the current defun." + (interactive + (let* ((function (lisp-defun-name))) + (if (lisp-minus-prefix) + (list function) + (list (ilisp-read-symbol + (format "Edit callers of [%s]: " + (lisp-buffer-symbol function)) + function + t))))) + (if (save-excursion (setq lisp-callers (who-calls-lisp function t))) + (progn + (setq lisp-last-locator (ilisp-value 'ilisp-calls-locator)) + (next-caller-lisp nil t)) + (edit-definitions-lisp function "calls" nil t + (ilisp-value 'ilisp-calls-locator)))) + +;;;%Locators +(defun lisp-re (back format &rest args) + "Search BACK if T using FORMAT applied to ARGS." + (let ((regexp (apply 'format format args))) + (if back + (re-search-backward regexp nil t) + (re-search-forward regexp nil t)))) + +;;; +(defun lisp-locate-ilisp (symbol type first back) + "Find SYMBOL's TYPE definition in the current file and return T if +successful. A definition is of the form +\(def<whitespace>(?name<whitespace>." + (lisp-re back + "^[ \t\n]*(def[^ \t\n]*[ \t\n]+(?%s[ \t\n(]+" + (regexp-quote (lisp-symbol-name symbol)))) + +;;; +(defun lisp-locate-calls (symbol type first back) + "Locate calls to SYMBOL." + (lisp-re back "\\(#'\\|(\\|'\\)%s\\([ \t\n]+\\|)\\)" + (regexp-quote (lisp-buffer-symbol symbol)))) + + +;;;%%Common LISP + +(defvar ilisp-cl-source-locater-patterns + '((setf + "^\\(.\\)?[ \t\n]*(def[^ \t\n]*\\([ \t\n]+\\(.\\)?[ \t\n]*\\|[ \t\n]*.[ \t\n]+\\)(setf\\([ \t\n]+\\(.\\)?[ \t\n]*\\|[ \t\n]*.[ \t\n]+\\)%s[ \t\n]*\\(.\\)?[ \t\n]*)") + + (function + "^\\(.\\)?[ \t\n]*(defun\\([ \t\n]+\\(.\\)?[ \t\n]*\\|[ \t\n]*.[ \t\n]+\\)%s[ \t\n(]") + + (macro + "^\\(.\\)?[ \t\n]*(defmacro\\([ \t\n]+\\(.\\)?[ \t\n]*\\|[ \t\n]*.[ \t\n]+\\)%s[ \t\n(]") + + (variable + "^\\(.\\)?[ \t\n]*(def\\(\\(var\\)\\|\\(parameter\\)\\|constant\\)\\([ \t\n]+\\(.\\)?[ \t\n]*\\|[ \t\n]*.[ \t\n]+\\)%s[ \t\n(]") + + (structure + "^\\(.\\)?[ \t\n]*(defstruct\\([ \t\n]+\\(.\\)?[ \t\n]*\\|[ \t\n]*.[ \t\n]+\\)(?[ \t\n]*\\(.\\)?[ \t\n]*%s[ \t\n(]") + + (type + "^\\(.\\)?[ \t\n]*(deftype\\([ \t\n]+\\(.\\)?[ \t\n]*\\|[ \t\n]*.[ \t\n]+\\)%s[ \t\n(]") + + (class + "^\\(.\\)?[ \t\n]*(defclass\\([ \t\n]+\\(.\\)?[ \t\n]*\\|[ \t\n]*.[ \t\n]+\\)%s[ \t\n(]") + )) + + +(defun ilisp-locate-clisp-defn (name type back) + (let ((pattern (car (cdr (assoc (intern type) ilisp-cl-source-locater-patterns))))) + (if pattern + (lisp-re back pattern name)))) + + + +(defun ilisp-locate-clos-method (name type back) + (if (string-match "(\\([^(]*\\)\\(([^)]*)\\)" type) + (let* ((quals (substring type (match-beginning 1) (match-end 1))) + (class + (read (substring type (match-beginning 2) (match-end 2)))) + (class-re nil) + (position 0)) + (while (setq position (string-match + "\\([ \t\n]+.[ \t\n]*\\|[ \t\n]*.[ \t\n]+\\|[ \t\n]+\\)" + quals position)) + (setq quals + (concat (substring quals 0 position) + "\\([ \t\n]+.[ \t\n]*\\|[ \t\n]*.[ \t\n]+\\|[ \t\n]+\\)" + (substring quals (match-end 0))))) + (while class + (setq class-re + (concat + class-re + (format + "[ \t\n]*\\(.\\)?[ \t\n]*([ \t\n]*\\(.\\)?[ \t\n]*[^ \t\n]*\\([ \t\n]+\\(.\\)?[ \t\n]*\\|[ \t\n]*.[ \t\n]+\\)%s[ \t\n]*\\(.\\)?[ \t\n]*" + (car class))) + class (cdr class))) + (lisp-re back + "^\\(.\\)?[ \t\n]*(def[^ \t\n]*\\([ \t\n]+\\(.\\)?[ \t\n]*\\|[ \t\n]*.[ \t\n]+\\)%s\\([ \t\n]+\\(.\\)?[ \t\n]*\\|[ \t\n]*.[ \t\n]+\\)%s[^ \t\n]*([^ \t\n]*%s" + name quals class-re)))) + + + + +(defun lisp-locate-clisp (symbol type first back) + "Try to find SYMBOL's TYPE definition in the current buffer and return +T if sucessful. FIRST is T if this is the first time in a file. BACK +is T to go backwards." + (let* ((name (regexp-quote (lisp-symbol-name symbol))) + (prefix + ;; Automatically generated defstruct accessors + (if (string-match "-" name) + (let ((struct (substring name 0 (1- (match-end 0))))) + (format + "^\\(.\\)?[ \t\n]*(def[^ \t\n]*\\([ \t\n]+\\(.\\)?\\|\\|[ \t\n]*.[ \t\n]+\\)(?%s[ \t\n)]\\|:conc-name\\([ \t\n]+\\(.\\)?[ \t\n]*\\|[ \t\n]*.[ \t\n]+\\)%s-" + struct struct)))) + ;; Defclass accessors + (class + "\\(:accessor\\|:writer\\|:reader\\)\\([ \t\n]+\\(.\\)?+[ \t\n]*\\|[ \t\n]*.[ \t\n]+\\)%s[ \t\n)]")) + (or + (if (equal type "any") + (lisp-re + back + (concat + "^\\(.\\)?[ \t\n]*(def[^ \t\n]*\\([ \t\n]+\\(.\\)?[ \t\n]*\\|[ \t\n]*.[ \t\n]+\\)\\((setf\\([ \t\n]+\\(.\\)?[ \t\n]*\\|[ \t\n]*.[ \t\n]+\\)\\|(?[ \t\n]*\\(.\\)?[ \t\n]*\\)%s[ \t\n)]" + (if prefix (concat "\\|" prefix)) + "\\|" + class) + name name)) + + ;; (qualifiers* (type1 type2 ...)) + (ilisp-locate-clos-method name type back) + + (ilisp-locate-clisp-defn name type back) + + ;; Standard def form + (if first (lisp-locate-ilisp symbol type first back)) + ;; Automatically generated defstruct accessors + (if (and first prefix) (lisp-re back prefix)) + ;; Defclass accessors + (lisp-re back class name) + ;; Give up! + )))