;;!emacs ;; ;; FILE: br-ftr.el ;; SUMMARY: OO-Browser feature browsing support. ;; USAGE: GNU Emacs Lisp Library ;; KEYWORDS: oop, tools ;; ;; AUTHOR: Bob Weiner ;; ORG: BeOpen.com ;; ;; ORIG-DATE: 20-Aug-91 at 18:16:36 ;; LAST-MOD: 10-May-01 at 19:08:32 by Bob Weiner ;;; ************************************************************************ ;;; Other required Elisp libraries ;;; ************************************************************************ (mapcar 'require '(br-c-ft hypb)) ;;; ************************************************************************ ;;; Public variables ;;; ************************************************************************ (defconst br-attribute-type-regexp "[=&]" "Regular expression which matches the first non-whitespace character in an OO-Browser attribute listing.") (defconst br-feature-type-regexp "[-+=&%>1/]" "Regular expression which matches the first non-whitespace character in an OO-Browser feature listing.") (defconst br-routine-type-regexp "[-+>1/]" "Regular expression which matches the first non-whitespace character in an OO-Browser routine listing.") ;;; ************************************************************************ ;;; Public functions ;;; ************************************************************************ (defun br-edit-feature (class feature-name &optional other-win view-only) "Edit the definition of CLASS' FEATURE-NAME, optionally in some OTHER-WIN if non-nil. With optional VIEW-ONLY non-nil, view the feature definition instead of editing it. Return the pathname of the feature definition if found, else nil." (interactive (list nil (br-feature-complete 'must-match "Edit feature definition:") nil nil)) (let ((tag-and-file (br-feature-tag-and-file (if (null class) ;; Assume feature-name includes prepended class in ;; proper format, e.g. when called interactively. feature-name (concat class "::" feature-name))))) (if tag-and-file (br-edit-feature-from-tag (car tag-and-file) (cdr tag-and-file) other-win view-only)))) (defun br-edit-feature-from-tag (feature-tag feature-path &optional other-win view-only) "Edit feature for OO-Browser FEATURE-TAG of file FEATURE-PATH, optionally in OTHER-WIN if non-nil. With optional VIEW-ONLY, view feature definition instead of editing it. Return FEATURE-PATH if feature definition is found, else nil." (let ((err)) (cond ((and feature-path (file-readable-p feature-path)) (cond ((br-feature-found-p feature-path feature-tag nil other-win) (if view-only (setq buffer-read-only t) ;; Handle case of already existing buffer in ;; read only mode. (and buffer-read-only (file-writable-p feature-path) (setq buffer-read-only nil))) ;; ;; Force mode-line redisplay (set-buffer-modified-p (buffer-modified-p))) ((interactive-p) (setq err (format "(OO-Browser): No `%s' feature defined in Environment." feature-tag) feature-path nil)))) ((interactive-p) (setq err (format "(OO-Browser): `%s' - src file not found or not readable, %s" feature-tag feature-path) feature-path nil)) ;; Feature not found. (t (setq feature-path nil))) (if err (error err)) feature-path)) (defun br-find-feature (&optional feature-entry view-only other-win) "Display feature definition for optional FEATURE-ENTRY in VIEW-ONLY mode if non-nil in OTHER-WIN if non-nil. Return feature path if FEATURE-ENTRY is successfully displayed, nil otherwise. Can also signal an error when called interactively." (interactive) (and (interactive-p) (setq view-only current-prefix-arg)) (let ((feature-path)) (setq feature-entry (br-feature-tag-and-file (or feature-entry (br-feature-complete 'must-match (if view-only "View feature definition:" "Edit feature definition:")))) feature-path (cdr feature-entry) feature-entry (car feature-entry)) (br-edit-feature-from-tag feature-entry feature-path other-win view-only))) (defun br-find-feature-entry () "Return feature listing entry that point is within or nil. Remove any leading whitespace but leave any prefix character." (if (= (point) (point-max)) (skip-chars-backward " \t\n\r")) (save-excursion (beginning-of-line) (skip-chars-forward " \t") (if (or (br-at-feature-p) ;; Get current feature signature, if any. (br-feature-get-tag)) (let ((feature (br-buffer-substring (point) (progn (skip-chars-forward "^\t\n\r") (point))))) (if (and (equal br-lang-prefix "objc-") ;; Remove any trailing class from a category entry. (string-match "([^\)]+)" feature)) (substring feature 0 (match-end 0)) feature))))) (defun br-feature-entry () "Return a listing entry as displayed in the buffer (sans leading whitespace)." (save-excursion (beginning-of-line) (skip-chars-forward " \t") (br-buffer-substring (point) (progn (skip-chars-forward "^\t\n\r") (point))))) (defun br-feature-ancestor-implementors (class-name feature-name method-flag) "Display an *Implementors* buffer with ancestor implementor listings matching CLASS-NAME and FEATURE-NAME. The feature is a method if METHOD-FLAG is non-nil, otherwise, it is an attribute. Return the number of implementors found." (br-feature-relation-implementors class-name feature-name 'br-feature-insert-ancestor-implementors method-flag)) (defun br-feature-descendant-implementors (class-name feature-name method-flag) "Display an *Implementors* buffer with descendant implementor listings matching CLASS-NAME and FEATURE-NAME. The feature is a method if METHOD-FLAG is non-nil, otherwise, it is an attribute. Return the number of implementors found." (br-feature-relation-implementors class-name feature-name 'br-feature-insert-descendant-implementors method-flag)) (defun br-feature-complete (&optional must-match prompt) "Interactively complete feature entry if possible, and return it. Optional MUST-MATCH means must match a completion table entry. Optional PROMPT is the initial prompt string for the user." (interactive) (let ((default (br-feature-default)) (completion-ignore-case t) completions ftr-entry) ;; Prompt with possible completions of ftr-entry. (setq prompt (or prompt "Feature entry:") completions (br-element-completions) ftr-entry (if completions (completing-read (format "%s (default %s) " prompt default) completions nil must-match) (read-string (format "%s (default %s) " prompt default)))) (if (equal ftr-entry "") default ftr-entry))) (defun br-default-class-completions () "Return completion alist of the names of all default class instances." (cond ((not (and br-env-file (file-exists-p br-env-file) (file-readable-p br-env-file))) nil) ((and br-default-class-tags-completions (eq (car (cdr br-default-class-tags-completions)) ;; tags last mod time (apply '+ (nth 5 (file-attributes br-env-file)))) (equal br-env-file (car br-default-class-tags-completions))) (car (cdr (cdr br-default-class-tags-completions)))) (t (let ((elt-list) (elt-alist) (default-classes (delq nil (mapcar 'br-default-class-p (br-all-classes))))) (setq elt-list (apply 'nconc (mapcar (function (lambda (class) (br-feature-map-class-tags (function (lambda (tag) (br-feature-tag-name tag nil nil))) class))) default-classes))) (setq elt-list (br-set-of-strings (br-feature-tag-sort-list (nconc elt-list (delq nil (mapcar (function (lambda (class) (if (br-default-class-p class) nil class))) (br-all-classes)))))) elt-alist (mapcar 'list elt-list) br-default-class-tags-completions (list br-env-file ;; tags last mod time (apply '+ (nth 5 (file-attributes br-env-file))) elt-alist)) elt-alist)))) (defun br-element-completions () "Return completion alist of all current Environment elements." (cond ((not (and br-env-file (file-exists-p br-env-file) (file-readable-p br-env-file))) nil) ((and br-element-tags-completions (eq (car (cdr br-element-tags-completions)) ;; tags last mod time (apply '+ (nth 5 (file-attributes br-env-file)))) (equal br-env-file (car br-element-tags-completions))) (car (cdr (cdr br-element-tags-completions)))) (t (message "(OO-Browser): Computing element completions...") (let ((elt-list (br-feature-map-all-tags (function (lambda (tag) (br-feature-tag-name tag t nil))))) (elt-alist)) (setq elt-list (br-set-of-strings (br-feature-tag-sort-list elt-list)) elt-alist (mapcar 'list elt-list) br-element-tags-completions (list br-env-file ;; tags last mod time (apply '+ (nth 5 (file-attributes br-env-file))) elt-alist)) (message "(OO-Browser): Computing element completions...Done") elt-alist)))) (defun br-feature-completions () "Return completion alist of all current Environment features. This excludes default class elements." (cond ((not (and br-env-file (file-exists-p br-env-file) (file-readable-p br-env-file))) nil) ((and br-feature-tags-completions (eq (car (cdr br-feature-tags-completions)) ;; tags last mod time (apply '+ (nth 5 (file-attributes br-env-file)))) (equal br-env-file (car br-feature-tags-completions))) (car (cdr (cdr br-feature-tags-completions)))) (t (let ((ftr-alist) (ftr-list (apply 'nconc (mapcar (function (lambda (class) (br-feature-map-class-tags (function (lambda (tag) (br-feature-tag-name tag nil nil))) class))) ;; All classes except default classes. (delq nil (mapcar (function (lambda (class) (if (br-default-class-p class) nil class))) (br-all-classes))))))) (setq ftr-list (br-set-of-strings (br-feature-tag-sort-list ftr-list)) ftr-alist (mapcar 'list ftr-list) br-feature-tags-completions (list br-env-file ;; tags last mod time (apply '+ (nth 5 (file-attributes br-env-file))) ftr-alist)) ftr-alist)))) (defun br-feature-default () "Return a best guess default for the feature or class name at point. Try to return it in class::feature format." (cond ((and (br-browser-buffer-p) (br-listing-window-p)) (let ((ftr-tag (br-feature-get-tag))) (if ftr-tag (br-feature-tag-name ftr-tag t) ;; assume is a class entry (br-find-class-name)))) ((and (equal br-lang-prefix "c++-") (eq major-mode (symbol-function 'br-lang-mode))) (let ((member-name) (class-name) member-elts) (cond ((save-excursion (c++-feature-def-p)) (setq member-name (br-feature-signature-to-name (br-buffer-substring (match-beginning 0) (match-end 0)) t))) ((save-excursion (c++-skip-to-statement) (c++-feature-decl)) (setq member-name (br-feature-signature-to-name (br-buffer-substring (match-beginning 0) (match-end 0)) t))) (t (setq member-elts (c++-feature-at-reference-p) member-name (nth 4 member-elts) class-name (nth 2 member-elts)))) (if (or class-name (and member-name (string-match "::" member-name))) nil ;; We know member-name is actually a type if it contains a ;;