Mercurial > hg > xemacs-beta
diff lisp/hyperbole/hmouse-tag.el @ 70:131b0175ea99 r20-0b30
Import from CVS: tag r20-0b30
author | cvs |
---|---|
date | Mon, 13 Aug 2007 09:02:59 +0200 |
parents | 4103f0995bd7 |
children | 4be1180a9e89 |
line wrap: on
line diff
--- a/lisp/hyperbole/hmouse-tag.el Mon Aug 13 09:00:04 2007 +0200 +++ b/lisp/hyperbole/hmouse-tag.el Mon Aug 13 09:02:59 2007 +0200 @@ -6,17 +6,32 @@ ;; KEYWORDS: c, hypermedia, mouse, oop, tools ;; ;; AUTHOR: Bob Weiner -;; ORG: InfoDock Associates +;; ORG: Brown U. ;; ;; ORIG-DATE: 24-Aug-91 -;; LAST-MOD: 17-Feb-97 at 15:31:50 by Bob Weiner +;; LAST-MOD: 11-Sep-95 at 18:19:48 by Bob Weiner +;; +;; This file is part of Hyperbole. +;; Available for use and distribution under the same terms as GNU Emacs. +;; +;; Copyright (C) 1991-1995, Free Software Foundation, Inc. +;; Developed with support from Motorola Inc. +;; +;; DESCRIPTION: +;; +;; Supports C, C++, Objective-C, Lisp, Fortran, and Assembly. +;; See the GNU Emacs manual for information on how to create a TAGS file +;; from the `etags' program. +;; Does not support the `ctags' tags file format. +;; +;; YOU MUST APPROPRIATELY SET THE PUBLIC VARIABLES BELOW BEFORE USE. +;; +;; DESCRIP-END. + ;;; ************************************************************************ ;;; Other required Elisp libraries ;;; ************************************************************************ -(require 'hpath) -(require 'hbut) - (if (cond ((or (featurep 'etags) (featurep 'tags)) nil) ((or hyperb:lemacs-p hyperb:emacs19-p) @@ -56,11 +71,11 @@ "*Ordered list of directories to search for C/C++ include files. Each directory must end with a directory separator. Directories normally searched by the C/C++ pre-processor should be set instead in -`smart-c-cpp-include-dirs'.") +'smart-c-cpp-include-dirs'.") (defvar smart-c-use-lib-man nil - "When non-nil makes `smart-c' and `smart-c++' display man pages for recognized lib symbols. -When nil, `smart-c' and `smart-c++' look up only symbols defined in an etags + "When non-nil makes 'smart-c' and 'smart-c++' display man pages for recognized lib symbols. +When nil, 'smart-c' and 'smart-c++' look up only symbols defined in an etags TAGS file. Create the file ~/.CLIBS-LIST and populate it with the full pathnames (one per @@ -76,20 +91,9 @@ "[ \t/*]*#[ \t]*\\(include\\|import\\)[ \t]+\\([\"<]\\)\\([^\">]+\\)[\">]" "Regexp to match to C, C++, or Objective-C include file lines. Include keyword matched is grouping 1. Type of include, user-specified via -double quote, or system-related starting with `<' is given by grouping 2. +double quote, or system-related starting with '<' is given by grouping 2. File name is grouping 3.") -(defvar smart-java-package-dirs - (and (fboundp 'getenv) (getenv "JAVA_HOME") - (list (expand-file-name "src/" (file-name-as-directory (getenv "JAVA_HOME"))))) - "*Ordered list of directories to search for imported Java packages. -Each directory must end with a directory separator.") - -(defconst smart-java-package-regexp - "[ \t/*]*\\(package\\|import\\)[ \t]+\\([^; \t\n\r\f]+\\)" - "Regexp to match to Java `package' and `import' lines. -Keyword matched is grouping 1. Referent is grouping 2.") - (defvar smart-emacs-tags-file nil "*Full path name of etags file for GNU Emacs source.") @@ -106,24 +110,26 @@ If: (1) on an include statement, the include file is displayed; - Look for include file in directory list `smart-asm-include-dirs'. + Look for include file in directory list 'smart-asm-include-dirs'. (2) on an identifier, the identifier definition is displayed, - assuming the identifier is found within an `etags' generated tag file + assuming the identifier is found within an 'etags' generated tag file in the current directory or any of its ancestor directories." (interactive) (or (if identifier nil (smart-asm-include-file)) (let ((tag (or identifier (smart-asm-at-tag-p)))) - ;; Set free variable tags-file-name so that next `find-tag' command uses + ;; Set free variable tags-file-name so that next 'find-tag' command uses ;; whatever tags file is set here. (setq tags-file-name (smart-tags-file buffer-file-name)) - (message "Looking for `%s' in `%s'..." tag tags-file-name) + (message "Looking for '%s' in '%s'..." tag tags-file-name) (condition-case () (progn - (smart-tags-display tag next) - (message "Found definition for `%s'." tag)) - (error (message "`%s' not found in `%s'." tag tags-file-name) + (funcall (if (br-in-browser) + 'find-tag 'find-tag-other-window) + tag next) + (message "Found definition for '%s'." tag)) + (error (message "'%s' not found in '%s'." tag tags-file-name) (beep)))))) ;;;###autoload @@ -134,422 +140,12 @@ (save-excursion (skip-chars-backward identifier-chars) (if (looking-at identifier) - (smart-flash-tag - (buffer-substring (point) (match-end 0)) - (point) (match-end 0)))))) - -(defun smart-c (&optional identifier next) - "Jumps to the definition of optional C IDENTIFIER or the one at point. -Optional second arg NEXT means jump to next matching C tag. - -It assumes that its caller has already checked that the key was pressed in an -appropriate buffer and has moved the cursor to the selected buffer. - -If: - (1) on a `#include' statement, the include file is displayed; - Look for include file in directory lists `smart-c-cpp-include-dirs' - and `smart-c-include-dirs'. - (2) on a C identifier, the identifier definition is displayed, - assuming the identifier is found within an `etags' generated tag file - in the current directory or any of its ancestor directories. - (3) if `smart-c-use-lib-man' is non-nil, the C identifier is - recognized as a library symbol, and a man page is found for the - identifier, then the man page is displayed." - - (interactive) - (or - (if identifier nil (smart-c-include-file)) - (let ((tag (or identifier (smart-c-at-tag-p)))) - ;; Set free variable tags-file-name so that next `find-tag' command uses - ;; whatever tags file is set here. - (setq tags-file-name (smart-tags-file buffer-file-name)) - (message "Looking for `%s' in `%s'..." tag tags-file-name) - (condition-case () - (progn - (smart-tags-display tag next) - (message "Found definition for `%s'." tag)) - (error - (if (not smart-c-use-lib-man) - (progn (message "`%s' not found in `%s'." tag tags-file-name) - (beep)) - (message "Checking if `%s' is a C library function..." tag) - (if (smart-library-symbol tag) - (progn (message "Displaying C library man page for `%s'." tag) - (manual-entry tag)) - (message "`%s' not found in `%s' or C libraries." - tag tags-file-name) - (beep)))))))) - -;;;###autoload -(defun smart-c-at-tag-p () - "Return C tag name that point is within, else nil." - (let* ((identifier-chars "_a-zA-Z0-9") - (identifier (concat "[_a-zA-Z][" identifier-chars "]*"))) - (save-excursion - (skip-chars-backward identifier-chars) - (if (looking-at identifier) - (smart-flash-tag - (buffer-substring (point) (match-end 0)) - (point) (match-end 0)))))) - -;;;###autoload -(defun smart-c++ (&optional identifier next) - "Jumps to the definition of optional C++ IDENTIFIER or the one at point. -Optional second arg NEXT means jump to next matching C++ tag. - -It assumes that its caller has already checked that the key was pressed in an -appropriate buffer and has moved the cursor to the selected buffer. - -If: - (1) on a `#include' statement, the include file is displayed; - Look for include file in directory lists `smart-c-cpp-include-dirs' - and `smart-c-include-dirs'. - (2) on a C++ identifier, the identifier definition is displayed, - assuming the identifier is found within an `etags' generated tag file - in the current directory or any of its ancestor directories. - (3) if `smart-c-use-lib-man' is non-nil, the C++ identifier is - recognized as a library symbol, and a man page is found for the - identifier, then the man page is displayed." - - (interactive) - (if (fboundp 'c++-to-definition) - ;; Only fboundp if OO-Browser has been loaded. - (smart-c++-oo-browser) - (or - (if identifier nil (smart-c-include-file)) - (let ((tag (or identifier (smart-c++-at-tag-p)))) - ;; Set free variable tags-file-name so that next `find-tag' command uses - ;; whatever tags file is set here. - (setq tags-file-name (smart-tags-file buffer-file-name)) - (message "Looking for `%s' in `%s'..." tag tags-file-name) - (condition-case () - (progn - (smart-tags-display tag next) - (message "Found definition for `%s'." tag)) - (error - (if (not smart-c-use-lib-man) - (progn (message "`%s' not found in `%s'." tag tags-file-name) - (beep)) - (message "Checking if `%s' is a C++ library function..." tag) - (if (smart-library-symbol tag) - (progn (message "Displaying C++ library man page for `%s'." tag) - (manual-entry tag)) - (message "`%s' not found in `%s' or C++ libraries." - tag tags-file-name) - (beep))))))))) - -;;; The following should be called only if the OO-Browser is available. -(defun smart-c++-oo-browser (&optional junk) - "Jumps to the definition of selected C++ construct via OO-Browser support. -Optional JUNK is ignored. Does nothing if the OO-Browser is not available. - -It assumes that its caller has already checked that the key was pressed in an -appropriate buffer and has moved the cursor to the selected buffer. - -If key is pressed: - (1) on a `#include' statement, the include file is displayed; - Look for include file in directory lists `smart-c-cpp-include-dirs' - and `smart-c-include-dirs'. - (2) within a method declaration, its definition is displayed; - (3) on a class name, the class definition is shown. - - (2) and (3) require that an OO-Browser Environment has been loaded with - the {M-x br-env-load RET} command." - - (interactive) - (c++-to-definition t)) - -(defun smart-c++-at-tag-p () - "Return C++ tag name that point is within, else nil." - (let* ((identifier-chars "_:~<>a-zA-Z0-9") - (identifier (concat "\\([_~:<a-zA-Z][" identifier-chars "]*" - "[ \t]*[^]) \t:;.,?~{}][^[( \t:;.,~^!|?{}]?[=*]?\\)[ \t\n]*("))) - (save-excursion - (skip-chars-backward identifier-chars) - (if (looking-at identifier) - (smart-flash-tag - (buffer-substring (match-beginning 1) (match-end 1)) - (match-beginning 1) (match-end 1)))))) - -(defun smart-emacs-lisp-mode-p () - "Return t if in a mode which uses Emacs Lisp symbols." - (or (memq major-mode '(emacs-lisp-mode lisp-interaction-mode debugger-mode)) - ;; Emacs Lisp symbols appear in Help buffers frequently. - (string-match "Help\\*$" (buffer-name)))) - -(defun smart-fortran (&optional identifier next) - "Jumps to the definition of optional Fortran IDENTIFIER or the one at point. -Optional second arg NEXT means jump to next matching Fortran tag. - -It assumes that its caller has already checked that the key was pressed in an -appropriate buffer and has moved the cursor to the selected buffer. - -If on a Fortran identifier, the identifier definition is displayed, -assuming the identifier is found within an `etags' generated tag file -in the current directory or any of its ancestor directories." - (interactive) - (let ((tag (or identifier (smart-fortran-at-tag-p)))) - ;; Set free variable tags-file-name so that next `find-tag' command uses - ;; whatever tags file is set here. - (setq tags-file-name (smart-tags-file buffer-file-name)) - (message "Looking for `%s' in `%s'..." tag tags-file-name) - (condition-case () - (progn - (smart-tags-display tag next) - (message "Found definition for `%s'." tag)) - (error - (message "`%s' not found in `%s'." tag tags-file-name) - (beep))))) - -;;;###autoload -(defun smart-fortran-at-tag-p () - "Return Fortran tag name that point is within, else nil." - (let* ((identifier-chars "_a-zA-Z0-9") - (identifier (concat "[_a-zA-Z][" identifier-chars "]*"))) - (save-excursion - (skip-chars-backward identifier-chars) - (if (looking-at identifier) - (smart-flash-tag - (buffer-substring (point) (match-end 0)) - (point) (match-end 0)))))) - -;;;###autoload -(defun smart-java (&optional identifier next) - "Jumps to the definition of optional Java IDENTIFIER or the one at point. -Optional second arg NEXT means jump to next matching Java tag. - -It assumes that its caller has already checked that the key was pressed in an -appropriate buffer and has moved the cursor to the selected buffer. - -If: - (1) within a commented @see cross-reference, the referent is displayed; - (2) on a `package' or `import' statement, the referent is displayed; - Look for referent files in the directory list `smart-java-package-dirs'. - (3) on an Java identifier, the identifier definition is displayed, - assuming the identifier is found within an `etags' generated tag file - in the current directory or any of its ancestor directories." - - (interactive) - (if (fboundp 'java-to-definition) - ;; Only fboundp if OO-Browser has been loaded. - (smart-java-oo-browser) - (or - (if identifier nil (or (smart-java-cross-reference) (smart-java-packages))) - (let ((tag (or identifier (smart-java-at-tag-p)))) - ;; Set free variable tags-file-name so that next `find-tag' command uses - ;; whatever tags file is set here. - (setq tags-file-name (smart-tags-file buffer-file-name)) - (message "Looking for `%s' in `%s'..." tag tags-file-name) - (condition-case () - (progn - (smart-tags-display tag next) - (message "Found definition for `%s'." tag)) - (error (progn (message "`%s' not found in `%s'." tag tags-file-name) - (beep)))))))) - -;;; The following should be called only if the OO-Browser is available. -(defun smart-java-oo-browser (&optional junk) - "Jumps to the definition of selected Java construct via OO-Browser support. -Optional JUNK is ignored. Does nothing if the OO-Browser is not available. - -It assumes that its caller has already checked that the key was pressed in an -appropriate buffer and has moved the cursor to the selected buffer. - -If key is pressed: - (1) within a commented @see cross-reference, the referent is displayed; - (2) on a `package' or `import' statement, the referent is displayed; - Look for referent files in the directory list `smart-java-package-dirs'. - (3) within a method declaration, its definition is displayed; - (4) on a class name, the class definition is shown." - - (interactive) - (or (smart-java-cross-reference) - (smart-java-packages) - (java-to-definition t))) - -;;;###autoload -(defun smart-java-at-tag-p () - "Return Java tag name that point is within, else nil." - (let* ((identifier-chars "_$.a-zA-Z0-9") - (identifier - (concat "[_$a-zA-Z][" identifier-chars "]*"))) - (save-excursion - (skip-chars-backward identifier-chars) - (if (looking-at identifier) - (smart-flash-tag - (buffer-substring (point) (match-end 0)) - (point) (match-end 0)))))) - -(defun smart-lisp (&optional next) - "Jumps to the definition of any selected Lisp construct. -If on an Emacs Lisp require, load, or autoload clause and `find-library' -from load-library package by Hallvard Furuseth (hallvard@ifi.uio.no) has -been loaded, jumps to library source, if possible. - -Otherwise, the construct must be found within an `etags' generated tag file -in the current directory or any of its ancestor directories in order for its -definition to be located. - -Optional NEXT means jump to next matching Lisp tag. When matching to an Emacs -Lisp tag using `wtags' (Bob Weiner's personal modifications to `etags'), -there is no next tag, so display documentation for current tag instead. - -This command assumes that its caller has already checked that the key was -pressed in an appropriate buffer and has moved the cursor to the selected -buffer." - - (interactive) - ;; Handle `require', `load', and `autoload' clauses in Emacs Lisp. - (or (and (fboundp 'find-library) - (smart-emacs-lisp-mode-p) - (let ((req) - (opoint (point))) - (setq req (and (search-backward "\(" nil t) - (looking-at (concat - "(\\(require\\|load\\|autoload\\)" - "[ \t]+.*['\"]" - "\\([^][() \t\n\^M`'\"]+\\)")))) - (goto-char opoint) - (if req (progn - (setq req (buffer-substring (match-beginning 2) - (match-end 2))) - (hpath:display-buffer (current-buffer)) - (find-library req) - t)))) - (let ((tag (smart-lisp-at-tag-p))) - ;; Set free variable tags-file-name so that next `find-tag' command - ;; uses whatever tags file is set here. - (setq tags-file-name (smart-tags-file default-directory)) - ;; This part only works properly for Emacs Lisp, so is conditionalized. - (if (and next (smart-emacs-lisp-mode-p) (featurep 'wtags)) - (progn (setq tag (intern tag)) - (cond ((fboundp tag) (describe-function tag)) - ((boundp tag) (describe-variable tag)) - (t (error "(smart-lisp): Unbound symbol: %s" tag)))) - (condition-case () - (smart-tags-display tag next) - (error (if (equal tags-file-name smart-emacs-tags-file) - (progn (message "`%s' not found in `%s'." - tag tags-file-name) - (beep)) - (setq tags-file-name smart-emacs-tags-file) - (smart-tags-display tag next)))))))) - -(defun smart-lisp-at-tag-p () - "Returns Lisp tag name that point is within, else nil. -Returns nil when point is within a Lisp `def' keyword." - (let* ((identifier-chars "-_*:+%$#!<>a-zA-Z0-9") - (identifier (concat "[-<*a-zA-Z][" identifier-chars "]*")) - (opoint (point))) - (save-excursion - (beginning-of-line) - (if (and (looking-at "\\(;*[ \t]*\\)?(def[^- \n\t]+") - (< opoint (match-end 0))) - nil - (goto-char opoint) - (skip-chars-backward identifier-chars) - (if (looking-at identifier) - (smart-flash-tag - (buffer-substring (point) (match-end 0)) - (point) (match-end 0))))))) - -;;;###autoload -(defun smart-lisp-mode-p () - "Return t if in a mode which uses Lisp symbols." - (or (smart-emacs-lisp-mode-p) - (memq major-mode '(lisp-mode scheme-mode)))) - -;;;###autoload -(defun smart-objc (&optional identifier next) - "Jumps to the definition of optional Objective-C IDENTIFIER or the one at point. -Optional second arg NEXT means jump to next matching Objective-C tag. - -It assumes that its caller has already checked that the key was pressed in an -appropriate buffer and has moved the cursor to the selected buffer. - -If: - (1) on a `#include' statement, the include file is displayed; - Look for include file in directory lists `smart-c-cpp-include-dirs' - and `smart-c-include-dirs'. - (2) on an Objective-C identifier, the identifier definition is displayed, - assuming the identifier is found within an `etags' generated tag file - in the current directory or any of its ancestor directories. - (3) if `smart-c-use-lib-man' is non-nil, the Objective-C identifier is - recognized as a library symbol, and a man page is found for the - identifier, then the man page is displayed." - - (interactive) - - (if (fboundp 'objc-to-definition) - ;; Only fboundp if OO-Browser has been loaded. - (smart-objc-oo-browser) - (or - (if identifier nil (smart-c-include-file)) - (let ((tag (or identifier (smart-objc-at-tag-p)))) - ;; Set free variable tags-file-name so that next `find-tag' command uses - ;; whatever tags file is set here. - (setq tags-file-name (smart-tags-file buffer-file-name)) - (message "Looking for `%s' in `%s'..." tag tags-file-name) - (condition-case () - (progn - (smart-tags-display tag next) - (message "Found definition for `%s'." tag)) - (error - (if (not smart-c-use-lib-man) - (progn (message "`%s' not found in `%s'." tag tags-file-name) - (beep)) - (message - "Checking if `%s' is an Objective-C library function..." tag) - (if (smart-library-symbol tag) - (progn - (message - "Displaying Objective-C library man page for `%s'." tag) - (manual-entry tag)) - (message "`%s' not found in `%s' or Objective-C libraries." - tag tags-file-name) - (beep))))))))) - -;;; The following should be called only if the OO-Browser is available. -(defun smart-objc-oo-browser (&optional junk) - "Jumps to the definition of selected Objective-C construct via OO-Browser support. -Optional JUNK is ignored. Does nothing if the OO-Browser is not available. - -It assumes that its caller has already checked that the key was pressed in an -appropriate buffer and has moved the cursor to the selected buffer. - -If key is pressed: - (1) on a `#include' statement, the include file is displayed; - Look for include file in directory lists `smart-c-cpp-include-dirs' - and `smart-c-include-dirs'. - (2) within a method declaration, its definition is displayed; - (3) on a class name, the class definition is shown. - - (2) and (3) require that an OO-Browser Environment has been loaded with - the {M-x br-env-load RET} command." - - (interactive) - (objc-to-definition t)) - -(defun smart-objc-at-tag-p () - "Return Objective-C tag name that point is within, else nil." - (let* ((identifier-chars "_a-zA-Z0-9") - (identifier - (concat "\\([-+][ \t]*\\)?\\([_a-zA-Z][" identifier-chars "]*\\)"))) - (save-excursion - (skip-chars-backward identifier-chars) - (if (looking-at identifier) - (smart-flash-tag - (buffer-substring (match-beginning 2) (match-end 2)) - (match-beginning 2) (match-end 2)))))) - -;;; ************************************************************************ -;;; Private functions -;;; ************************************************************************ + (buffer-substring (point) (match-end 0)))))) (defun smart-asm-include-file () "If point is on an include file line, tries to display file. Returns non-nil iff on an include file line, even if file is not found. -Look for include file in `smart-asm-include-dirs' and add suffix \".ins\" or +Look for include file in 'smart-asm-include-dirs' and add suffix \".ins\" or \".inc\" to filename if it lacks a suffix." (let ((opoint (point))) ;; Some assemblers utilize the C preprocessor, so try that first. @@ -568,7 +164,7 @@ (while dir-list (setq dir-list (if (setq path (car (directory-files - (car dir-list) t file))) + (car dir-list) t file))) nil (cdr dir-list)))) ;; @@ -577,32 +173,88 @@ (if path (if (and (file-readable-p path) (progn - (hpath:find path) + (if (br-in-browser) + (find-file path) + (find-file-other-window path)) (cond ((featurep 'asm-mode) t) ((load "asm-mode" nil 'nomessage) (provide 'asm-mode)) (t - (beep) - (message - "(smart-asm-include-file): asm-mode undefined.") - nil - )))) + (beep) + (message + "(smart-asm-include-file): asm-mode undefined.") + nil + )))) nil (beep) - (message "(smart-asm-include-file): `%s' unreadable." path)) + (message "(smart-asm-include-file): '%s' unreadable." path)) (beep) - (message "(smart-asm-include-file): `%s' not found." file)) + (message "(smart-asm-include-file): '%s' not found." file)) path)) ;; not on an include file line (t (goto-char opoint) nil)))) +(defun smart-c (&optional identifier next) + "Jumps to the definition of optional C IDENTIFIER or the one at point. +Optional second arg NEXT means jump to next matching C tag. + +It assumes that its caller has already checked that the key was pressed in an +appropriate buffer and has moved the cursor to the selected buffer. + +If: + (1) on a '#include' statement, the include file is displayed; + Look for include file in directory lists 'smart-c-cpp-include-dirs' + and 'smart-c-include-dirs'. + (2) on a C identifier, the identifier definition is displayed, + assuming the identifier is found within an 'etags' generated tag file + in the current directory or any of its ancestor directories. + (3) if 'smart-c-use-lib-man' is non-nil, the C identifier is + recognized as a library symbol, and a man page is found for the + identifier, then the man page is displayed." + + (interactive) + (or + (if identifier nil (smart-c-include-file)) + (let ((tag (or identifier (smart-c-at-tag-p)))) + ;; Set free variable tags-file-name so that next 'find-tag' command uses + ;; whatever tags file is set here. + (setq tags-file-name (smart-tags-file buffer-file-name)) + (message "Looking for '%s' in '%s'..." tag tags-file-name) + (condition-case () + (progn + (funcall (if (br-in-browser) + 'find-tag 'find-tag-other-window) + tag next) + (message "Found definition for '%s'." tag)) + (error + (if (not smart-c-use-lib-man) + (progn (message "'%s' not found in '%s'." tag tags-file-name) + (beep)) + (message "Checking if '%s' is a C library function..." tag) + (if (smart-library-symbol tag) + (progn (message "Displaying C library man page for '%s'." tag) + (manual-entry tag)) + (message "'%s' not found in '%s' or C libraries." + tag tags-file-name) + (beep)))))))) + +;;;###autoload +(defun smart-c-at-tag-p () + "Return C tag name that point is within, else nil." + (let* ((identifier-chars "_a-zA-Z0-9") + (identifier (concat "[_a-zA-Z][" identifier-chars "]*"))) + (save-excursion + (skip-chars-backward identifier-chars) + (if (looking-at identifier) + (buffer-substring (point) (match-end 0)))))) + (defun smart-c-include-file () "If point is on an include file line, tries to display file. Returns non-nil iff on an include file line, even if file is not found. -Look for include file in `smart-c-cpp-include-dirs' and in directory list -`smart-c-include-dirs'." +Look for include file in 'smart-c-cpp-include-dirs' and in directory list +'smart-c-include-dirs'." (let ((opoint (point))) (beginning-of-line) (if (looking-at smart-c-include-regexp) @@ -629,7 +281,9 @@ (if found (if (and (file-readable-p path) (progn - (hpath:find path) + (if (br-in-browser) + (find-file path) + (find-file-other-window path)) (cond ((or (featurep 'cc-mode) (featurep 'c-mode)) t) @@ -644,198 +298,298 @@ )))) nil (beep) - (message "(smart-c-include-file): `%s' unreadable." path)) + (message "(smart-c-include-file): '%s' unreadable." path)) (beep) - (message "(smart-c-include-file): `%s' not found." file)) + (message "(smart-c-include-file): '%s' not found." file)) path) (goto-char opoint) nil))) -(defun smart-flash-tag (tag start end) - "Tries to flash TAG at START to END in buffer, to indicate that it is serving as a hyperlink button. -Returns TAG." - ;; Button flashing code might not yet have been loaded if the whole - ;; Hyperbole system has not been started. - (if (fboundp 'hui:but-flash) - (progn - (ibut:label-set tag start end) - (hui:but-flash))) - tag) + +;;;###autoload +(defun smart-c++ (&optional identifier next) + "Jumps to the definition of optional C++ IDENTIFIER or the one at point. +Optional second arg NEXT means jump to next matching C++ tag. + +It assumes that its caller has already checked that the key was pressed in an +appropriate buffer and has moved the cursor to the selected buffer. + +If: + (1) on a '#include' statement, the include file is displayed; + Look for include file in directory lists 'smart-c-cpp-include-dirs' + and 'smart-c-include-dirs'. + (2) on a C++ identifier, the identifier definition is displayed, + assuming the identifier is found within an 'etags' generated tag file + in the current directory or any of its ancestor directories. + (3) if 'smart-c-use-lib-man' is non-nil, the C++ identifier is + recognized as a library symbol, and a man page is found for the + identifier, then the man page is displayed." + + (interactive) + (or + (if identifier nil (smart-c-include-file)) + (let ((tag (or identifier (smart-c++-at-tag-p)))) + ;; Set free variable tags-file-name so that next 'find-tag' command uses + ;; whatever tags file is set here. + (setq tags-file-name (smart-tags-file buffer-file-name)) + (message "Looking for '%s' in '%s'..." tag tags-file-name) + (condition-case () + (progn + (funcall (if (br-in-browser) + 'find-tag 'find-tag-other-window) + tag next) + (message "Found definition for '%s'." tag)) + (error + (if (not smart-c-use-lib-man) + (progn (message "'%s' not found in '%s'." tag tags-file-name) + (beep)) + (message "Checking if '%s' is a C++ library function..." tag) + (if (smart-library-symbol tag) + (progn (message "Displaying C++ library man page for '%s'." tag) + (manual-entry tag)) + (message "'%s' not found in '%s' or C++ libraries." + tag tags-file-name) + (beep)))))))) + +;;; The following should be called only if the OO-Browser is available. +;;;###autoload +(defun smart-c++-oobr (&optional junk) + "Jumps to the definition of selected C++ construct via OO-Browser support. +Optional JUNK is ignored. Does nothing if the OO-Browser is not available. + +It assumes that its caller has already checked that the key was pressed in an +appropriate buffer and has moved the cursor to the selected buffer. + +If key is pressed: + (1) on a '#include' statement, the include file is displayed; + Look for include file in directory lists 'smart-c-cpp-include-dirs' + and 'smart-c-include-dirs'. + (2) within a method declaration, its definition is displayed; + (3) on a class name, the class definition is shown. + + (2) and (3) require that an OO-Browser Environment has been loaded with + the {M-x br-env-load RTN} command." + + (interactive) + (c++-to-definition 'other-win)) -(defun smart-java-cross-reference () - "If within a Java @see comment, displays the associated definition for editing and returns non-nil, else nil. -Non-nil is returned even if the @see referent cannot be found. +(defun smart-c++-at-tag-p () + "Return C++ tag name that point is within, else nil." + (let* ((identifier-chars "_:~<>a-zA-Z0-9") + (identifier (concat "\\([_~:<a-zA-Z][" identifier-chars "]*" + "[ \t]*[^]) \t:;.,?~{}][^[( \t:;.,~^!|?{}]?[=*]?\\)[ \t\n]*("))) + (save-excursion + (skip-chars-backward identifier-chars) + (if (looking-at identifier) + (buffer-substring (point) (match-end 1)))))) + +(defun smart-emacs-lisp-mode-p () + "Return t if in a mode which uses Emacs Lisp symbols." + (or (eq major-mode 'emacs-lisp-mode) + (eq major-mode 'lisp-interaction-mode) + (eq major-mode 'debugger-mode) + ;; Emacs Lisp symbols appear in Help buffers frequently. + (string-match "Help\\*$" (buffer-name)))) + +(defun smart-fortran (&optional identifier next) + "Jumps to the definition of optional Fortran IDENTIFIER or the one at point. +Optional second arg NEXT means jump to next matching Fortran tag. + +It assumes that its caller has already checked that the key was pressed in an +appropriate buffer and has moved the cursor to the selected buffer. + +If on a Fortran identifier, the identifier definition is displayed, +assuming the identifier is found within an 'etags' generated tag file +in the current directory or any of its ancestor directories." + (interactive) + (let ((tag (or identifier (smart-fortran-at-tag-p)))) + ;; Set free variable tags-file-name so that next 'find-tag' command uses + ;; whatever tags file is set here. + (setq tags-file-name (smart-tags-file buffer-file-name)) + (message "Looking for '%s' in '%s'..." tag tags-file-name) + (condition-case () + (progn + (funcall (if (br-in-browser) + 'find-tag 'find-tag-other-window) + tag next) + (message "Found definition for '%s'." tag)) + (error + (message "'%s' not found in '%s'." tag tags-file-name) + (beep))))) + +;;;###autoload +(defun smart-fortran-at-tag-p () + "Return Fortran tag name that point is within, else nil." + (let* ((identifier-chars "_a-zA-Z0-9") + (identifier (concat "[_a-zA-Z][" identifier-chars "]*"))) + (save-excursion + (skip-chars-backward identifier-chars) + (if (looking-at identifier) + (buffer-substring (point) (match-end 0)))))) + +(defun smart-lisp (&optional next) + "Jumps to the definition of any selected Lisp construct. +If on an Emacs Lisp require, load, or autoload clause and 'find-library' +from load-library package by Hallvard Furuseth (hallvard@ifi.uio.no) has +been loaded, jumps to library source, if possible. + +Otherwise, the construct must be found within an 'etags' generated tag file +in the current directory or any of its ancestor directories in order for its +definition to be located. + +Optional NEXT means jump to next matching Lisp tag. When matching to an Emacs +Lisp tag using 'wtags' (Bob Weiner's personal modifications to 'etags'), +there is no next tag, so display documentation for current tag instead. + +This command assumes that its caller has already checked that the key was +pressed in an appropriate buffer and has moved the cursor to the selected +buffer." -Does nothing if the `oo-browser' command is undefined, since it requires that -package for class and feature lookups." - ;; - ;; Valid forms of @see cross-references are: - ;; * @see #getComponent - current class attribute - ;; * @see #waitForAll() - current class method, no arguments - ;; * @see #checkID(int, boolean) - current class method, with arguments - ;; * @see java.awt.ColorModel#getRGBdefault - library class method - ;; * @see Component#paintAll - class method - ;; * @see java.awt.GridBagLayout - library class - ;; * @see Container - class - ;; - ;; For simplicity sake, this code ignores the library path given with any - ;; class in favor of the OO-Browser's lookup tables. It also ignores any - ;; parameters associated with a method, and thus cannot distinguish between - ;; methods with the same name within a single class, which we believe to be - ;; fairly bad form anyway. - ;; - (let ((opoint (point))) - (if (and (eq major-mode 'java-mode) buffer-file-name - (fboundp 'br-env-load) - (or (looking-at "@see[ \t]+") - (and (re-search-backward "[@\n\r\f]" nil t) - (looking-at "@see[ \t]+")))) - (let ((class) (feature)) - ;; Ignore any library path preceding a classname (grouping 1) - (cond - ((looking-at - "@see[ \t]+\\(#\\)?\\([^][(){} \t\n\r\f#]+[.]\\)?\\([^][(){} \t\n\r\f#.]+\\)[][(){} \t\n\r\f]") - (if (match-beginning 1) - (setq class nil - feature (buffer-substring (match-beginning 3) - (match-end 3))) - (setq class (buffer-substring (match-beginning 3) (match-end 3)) - feature nil))) - ((looking-at - "@see[ \t]+\\([^][(){} \t\n\r\f#]+[.]\\)?\\([^][(){} \t\n\r\f#.]+\\)#\\([^][(){} \t\n\r\f#.]+\\)") - (setq class (buffer-substring (match-beginning 2) - (match-end 2)) - feature (buffer-substring (match-beginning 3) - (match-end 3))))) - ;; Return to original point. - (goto-char opoint) - ;; Lookup class / feature. - (cond - ((and (null class) (null feature)) - ;; Invalid or unrecognized @see format, so ignore. - (message "(smart-java-cross-reference): Invalid @see cross-reference format.") - (beep) - t) - ;; Ensure that a Java OO-Browser environment has been loaded. - (t (if (or (and (boundp 'br-lang-prefix) - (equal br-lang-prefix "java-") - (boundp 'br-env-file) (stringp br-env-file) - (null br-env-spec)) - ;; Load an existing Environment based on current - ;; buffer or prompt to build one. This also - ;; loads the "br-java.el" library in which the - ;; `java-class-def-regexp' variable used below - ;; is defined. - (and (br-env-load - (smart-tags-file - buffer-file-name - (if (boundp 'br-env-default-file) - br-env-default-file "OOBR"))) - (equal br-lang-prefix "java-"))) - (cond ((null feature) - (br-edit nil class)) - (t - (if (null class) - (if (save-excursion - (or (re-search-backward java-class-def-regexp nil t) - (re-search-forward java-class-def-regexp nil t))) - (setq class (buffer-substring - (match-beginning java-class-def-name-grpn) - (match-end java-class-def-name-grpn))) - (error "(smart-java-cross-reference): This @see must be in a class definition."))) - (br-edit-feature class feature t))) - (error "(smart-java-cross-reference): The OO-Browser failed to load a Java environment."))))) - ;; Return to original point. - (goto-char opoint) - nil))) + (interactive) + ;; Handle 'require', 'load', and 'autoload' clauses in Emacs Lisp. + (or (and (fboundp 'find-library) + (smart-emacs-lisp-mode-p) + (let ((req) + (opoint (point))) + (setq req (and (search-backward "\(" nil t) + (looking-at (concat + "(\\(require\\|load\\|autoload\\)" + "[ \t]+.*['\"]" + "\\([^][() \t\n\^M`'\"]+\\)")))) + (goto-char opoint) + (if req (progn + (setq req (buffer-substring (match-beginning 2) + (match-end 2))) + (pop-to-buffer nil t) + (find-library req) + t)))) + (let ((tag (smart-lisp-at-tag-p))) + ;; Set free variable tags-file-name so that next 'find-tag' command + ;; uses whatever tags file is set here. + (setq tags-file-name (smart-tags-file default-directory)) + ;; This part only works properly for Emacs Lisp, so is conditionalized. + (if (and next (smart-emacs-lisp-mode-p) (featurep 'wtags)) + (progn (setq tag (intern tag)) + (cond ((fboundp tag) (describe-function tag)) + ((boundp tag) (describe-variable tag)) + (t (error "(smart-lisp): Unbound symbol: %s" tag)))) + (condition-case () + (funcall (if (br-in-browser) + 'find-tag 'find-tag-other-window) + tag next) + (error (if (equal tags-file-name smart-emacs-tags-file) + nil + (setq tags-file-name smart-emacs-tags-file) + (funcall (if (br-in-browser) + 'find-tag 'find-tag-other-window) + tag next)))))))) + +(defun smart-lisp-at-tag-p () + "Returns Lisp tag name that point is within, else nil. +Returns nil when point is on the first line of a 'def' form past the first 4 +characters." + (let* ((identifier-chars "-_*:+%$#!<>a-zA-Z0-9") + (identifier (concat "[-<*a-zA-Z][" identifier-chars "]*")) + (opoint (point))) + (save-excursion + (beginning-of-line) + (if (and (looking-at "\\(;*[ \t]*\\)?(def[^- \n\t]+[ \n\t]") + (> opoint (match-end 0))) + nil + (goto-char opoint) + (skip-chars-backward identifier-chars) + (if (looking-at identifier) + (buffer-substring (point) (match-end 0))))))) + +(defun smart-lisp-mode-p () + "Return t if in a mode which uses Lisp symbols." + (or (smart-emacs-lisp-mode-p) + (eq major-mode 'lisp-mode) + (eq major-mode 'scheme-mode))) + +;;;###autoload +(defun smart-objc (&optional identifier next) + "Jumps to the definition of optional Objective-C IDENTIFIER or the one at point. +Optional second arg NEXT means jump to next matching Objective-C tag. + +It assumes that its caller has already checked that the key was pressed in an +appropriate buffer and has moved the cursor to the selected buffer. -(defun smart-java-library-path (library-name) - "Search up directory tree from current directory for a match to LIBRARY-NAME." - (let ((path default-directory) - (library-path) - (library-regexp (if (string-match "\\.\\|'//" library-name) - (regexp-quote - (concat (file-name-as-directory "") - (substring library-name 0 (match-beginning 0)) - (file-name-as-directory ""))))) - (start 0)) - ;; Return rightmost match to first part of library-name. - (if library-regexp - (while (string-match library-regexp path start) - (setq start (1+ (match-beginning 0)) - library-path (substring path 0 (match-beginning 0))))) - library-path)) +If: + (1) on a '#include' statement, the include file is displayed; + Look for include file in directory lists 'smart-c-cpp-include-dirs' + and 'smart-c-include-dirs'. + (2) on an Objective-C identifier, the identifier definition is displayed, + assuming the identifier is found within an 'etags' generated tag file + in the current directory or any of its ancestor directories. + (3) if 'smart-c-use-lib-man' is non-nil, the Objective-C identifier is + recognized as a library symbol, and a man page is found for the + identifier, then the man page is displayed." -(defun smart-java-packages () - "If point is on a `package' or `import' line, this tries to display the associated referent. -Returns non-nil iff on such a line, even if the referent is not found. -Look for packages in `smart-java-package-dirs'." - (let ((opoint (point))) - (beginning-of-line) - (if (looking-at smart-java-package-regexp) - (let ((keyword-type (buffer-substring - (match-beginning 1) (match-end 1))) - (referent (buffer-substring (match-beginning 2) (match-end 2))) - (found) - (subpath) - dir-list path subfile) - (goto-char opoint) - (if (string-equal keyword-type "package") - (let ((library-path (smart-java-library-path referent))) - (if library-path - (hpath:find (expand-file-name - (hypb:replace-match-string - "\\." referent (file-name-as-directory "") t) - library-path)) - ;; Show the current directory, which should contain this package. - (hpath:find default-directory))) - ;; This is an `import' statement. If it includes a *, show the - ;; associated library directory, otherwise, show the specific - ;; package. - (if (string-match "\\.\\*" referent) - (setq subfile (substring referent 0 (match-beginning 0)) - subfile (hypb:replace-match-string - "\\." subfile (file-name-as-directory "") t)) - (setq subpath (hypb:replace-match-string - "\\." referent (file-name-as-directory "") t) - subfile (concat subpath ".java"))) - ;; - ;; Try to find the path containing referent. - ;; - ;; Search up the current directory tree for a possible matching - ;; directory below which the referent library might live and add - ;; this to smart-java-package-dirs for searching. - (let ((library-path (smart-java-library-path referent))) - (if library-path - (setq dir-list (cons library-path smart-java-package-dirs)))) + (interactive) + (or + (if identifier nil (smart-c-include-file)) + (let ((tag (or identifier (smart-objc-at-tag-p)))) + ;; Set free variable tags-file-name so that next 'find-tag' command uses + ;; whatever tags file is set here. + (setq tags-file-name (smart-tags-file buffer-file-name)) + (message "Looking for '%s' in '%s'..." tag tags-file-name) + (condition-case () + (progn + (funcall (if (br-in-browser) + 'find-tag 'find-tag-other-window) + tag next) + (message "Found definition for '%s'." tag)) + (error + (if (not smart-c-use-lib-man) + (progn (message "'%s' not found in '%s'." tag tags-file-name) + (beep)) + (message + "Checking if '%s' is an Objective-C library function..." tag) + (if (smart-library-symbol tag) + (progn + (message + "Displaying Objective-C library man page for '%s'." tag) + (manual-entry tag)) + (message "'%s' not found in '%s' or Objective-C libraries." + tag tags-file-name) + (beep)))))))) - (while dir-list - (setq path (expand-file-name subfile (car dir-list)) - dir-list (if (setq found (file-exists-p path)) - nil - (cdr dir-list)))) - (if (and (not found) subpath hyperb:microcruft-os-p) - ;; Try .jav suffix. - (progn (setq subfile (concat subpath ".jav") - dir-list smart-java-package-dirs) - (while dir-list - (setq path (expand-file-name subfile (car dir-list)) - dir-list (if (setq found (file-exists-p path)) - nil - (cdr dir-list)))))) - ;; - ;; If found, display file - ;; - (if found - (if (file-readable-p path) - (hpath:find path) - (beep) - (message "(smart-java-packages): `%s' unreadable." path)) - (beep) - (message "(smart-java-packages): `%s' not found." referent)) - path)) - (goto-char opoint) - nil))) +;;; The following should be called only if the OO-Browser is available. +;;;###autoload +(defun smart-objc-oobr (&optional junk) + "Jumps to the definition of selected Objective-C construct via OO-Browser support. +Optional JUNK is ignored. Does nothing if the OO-Browser is not available. + +It assumes that its caller has already checked that the key was pressed in an +appropriate buffer and has moved the cursor to the selected buffer. + +If key is pressed: + (1) on a '#include' statement, the include file is displayed; + Look for include file in directory lists 'smart-c-cpp-include-dirs' + and 'smart-c-include-dirs'. + (2) within a method declaration, its definition is displayed; + (3) on a class name, the class definition is shown. + + (2) and (3) require that an OO-Browser Environment has been loaded with + the {M-x br-env-load RTN} command." + + (interactive) + (objc-to-definition 'other-win)) + +(defun smart-objc-at-tag-p () + "Return Objective-C tag name that point is within, else nil." + (let* ((identifier-chars "_a-zA-Z0-9") + (identifier + (concat "\\([-+][ \t]*\\)?\\([_a-zA-Z][" identifier-chars "]*\\)"))) + (save-excursion + (skip-chars-backward identifier-chars) + (if (looking-at identifier) + (buffer-substring (match-beginning 2) (match-end 2)))))) + +;;; ************************************************************************ +;;; Private functions +;;; ************************************************************************ (defun smart-library-symbol (tag) "Return non-nil if TAG is a library symbol listed in cache of such symbols. @@ -853,25 +607,6 @@ (kill-buffer buf) found))) -(defun smart-tags-display (tag next) - (if next (setq tag nil)) - (let ((func (or (if (fboundp 'find-tag-internal) 'find-tag-internal) - (if (fboundp 'find-tag-noselect) 'find-tag-noselect))) - ;; For XEmacs - (tags-always-exact t) - ;; For Emacs 19 - (find-tag-tag-order (if (boundp 'find-tag-tag-order) - find-tag-tag-order))) - (if find-tag-tag-order - (if next nil (setq find-tag-tag-order '(tag-exact-match-p))) - ;; For InfoDock (XEmacs may also take this branch), force exact match. - (if (stringp tag) (setq tag (list tag)))) - (if (and func (funcall func tag)) - (hpath:display-buffer (current-buffer))) - ;; Signals an error if tag is not found which is caught by many callers - ;; of this function. - (find-tag tag))) - ;;;###autoload (defun smart-tags-file-path (file) "Expand relative FILE name by looking it up in the nearest tags file. @@ -893,9 +628,8 @@ file)) ;;;###autoload -(defun smart-tags-file (curr-filename &optional name-of-tags-file) - "Return appropriate tags file name for CURR-FILENAME or `tags-file-name'. -Optional NAME-OF-TAGS-FILE is the literal filename for which to look." +(defun smart-tags-file (curr-filename) + "Return appropriate tags file name for CURR-FILENAME or 'tags-file-name'." (let ((path curr-filename) (tags-file)) (while (and @@ -906,7 +640,7 @@ (not (string-match ":?/\\'" path)) ;; No tags file (not (file-exists-p - (setq tags-file (expand-file-name (or name-of-tags-file "TAGS") path))))) + (setq tags-file (expand-file-name "TAGS" path))))) (setq tags-file nil)) (if (and (not tags-file) (stringp curr-filename)