1 ;;; ebrowse.el --- Emacs C++ class browser & tags facility
3 ;; Copyright (C) 1992, 93, 94, 95, 96, 97, 98, 99, 2000, 2001, 2002, 2005
4 ;; Free Software Foundation Inc.
6 ;; Author: Gerd Moellmann <gerd@gnu.org>
8 ;; Keywords: C++ tags tools
10 ;; This file is part of GNU Emacs.
12 ;; GNU Emacs is free software; you can redistribute it and/or modify
13 ;; it under the terms of the GNU General Public License as published by
14 ;; the Free Software Foundation; either version 2, or (at your option)
17 ;; GNU Emacs is distributed in the hope that it will be useful,
18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 ;; GNU General Public License for more details.
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs; see the file COPYING. If not, write to
24 ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
28 ;; This package implements
30 ;; - A class browser for C++
31 ;; - A complete set of tags-like functions working on class trees
32 ;; - An electric buffer list showing class browser buffers only
34 ;; Documentation is found in a separate Info file.
50 "Settings for the C++ class browser."
54 (defcustom ebrowse-search-path nil
55 "*List of directories to search for source files in a class tree.
56 Elements should be directory names; nil as an element means to try
57 to find source files relative to the location of the BROWSE file loaded."
59 :type '(repeat (choice (const :tag "Default" nil)
60 (string :tag "Directory"))))
63 (defcustom ebrowse-view/find-hook nil
64 "*Hooks run after finding or viewing a member or class."
69 (defcustom ebrowse-not-found-hook nil
70 "*Hooks run when finding or viewing a member or class was not successful."
75 (defcustom ebrowse-electric-list-mode-hook nil
76 "*Hook called by `ebrowse-electric-position-mode'."
81 (defcustom ebrowse-max-positions 50
82 "*Number of markers saved on electric position stack."
88 (defgroup ebrowse-tree nil
89 "Settings for class tree buffers."
93 (defcustom ebrowse-tree-mode-hook nil
94 "*Hook run in each new tree buffer."
99 (defcustom ebrowse-tree-buffer-name "*Tree*"
100 "*The default name of class tree buffers."
105 (defcustom ebrowse--indentation 4
106 "*The amount by which subclasses are indented in the tree."
111 (defcustom ebrowse-source-file-column 40
112 "*The column in which source file names are displayed in the tree."
117 (defcustom ebrowse-tree-left-margin 2
118 "*Amount of space left at the left side of the tree display.
119 This space is used to display markers."
125 (defgroup ebrowse-member nil
126 "Settings for member buffers."
130 (defcustom ebrowse-default-declaration-column 25
131 "*The column in which member declarations are displayed in member buffers."
132 :group 'ebrowse-member
136 (defcustom ebrowse-default-column-width 25
137 "*The width of the columns in member buffers (short display form)."
138 :group 'ebrowse-member
142 (defcustom ebrowse-member-buffer-name "*Members*"
143 "*The name of the buffer for member display."
144 :group 'ebrowse-member
148 (defcustom ebrowse-member-mode-hook nil
149 "*Run in each new member buffer."
150 :group 'ebrowse-member
155 (defgroup ebrowse-faces nil
156 "Faces used by Ebrowse."
160 (defface ebrowse-tree-mark
161 '((((min-colors 88)) (:foreground "red1"))
162 (t (:foreground "red")))
163 "*The face used for the mark character in the tree."
164 :group 'ebrowse-faces)
165 ;; backward-compatibility alias
166 (put 'ebrowse-tree-mark-face 'face-alias 'ebrowse-tree-mark)
169 (defface ebrowse-root-class
170 '((((min-colors 88)) (:weight bold :foreground "blue1"))
171 (t (:weight bold :foreground "blue")))
172 "*The face used for root classes in the tree."
173 :group 'ebrowse-faces)
174 ;; backward-compatibility alias
175 (put 'ebrowse-root-class-face 'face-alias 'ebrowse-root-class)
178 (defface ebrowse-file-name
180 "*The face for filenames displayed in the tree."
181 :group 'ebrowse-faces)
182 ;; backward-compatibility alias
183 (put 'ebrowse-file-name-face 'face-alias 'ebrowse-file-name)
186 (defface ebrowse-default
188 "*Face for everything else in the tree not having other faces."
189 :group 'ebrowse-faces)
190 ;; backward-compatibility alias
191 (put 'ebrowse-default-face 'face-alias 'ebrowse-default)
194 (defface ebrowse-member-attribute
195 '((((min-colors 88)) (:foreground "red1"))
196 (t (:foreground "red")))
197 "*Face used to display member attributes."
198 :group 'ebrowse-faces)
199 ;; backward-compatibility alias
200 (put 'ebrowse-member-attribute-face 'face-alias 'ebrowse-member-attribute)
203 (defface ebrowse-member-class
204 '((t (:foreground "purple")))
205 "*Face used to display the class title in member buffers."
206 :group 'ebrowse-faces)
207 ;; backward-compatibility alias
208 (put 'ebrowse-member-class-face 'face-alias 'ebrowse-member-class)
211 (defface ebrowse-progress
212 '((((min-colors 88)) (:background "blue1"))
213 (t (:background "blue")))
214 "*Face for progress indicator."
215 :group 'ebrowse-faces)
216 ;; backward-compatibility alias
217 (put 'ebrowse-progress-face 'face-alias 'ebrowse-progress)
223 (defun ebrowse-some (predicate vector)
224 "Return true if PREDICATE is true of some element of VECTOR.
225 If so, return the value returned by PREDICATE."
226 (let ((length (length vector))
229 (while (and (< i length) (not result))
230 (setq result (funcall predicate (aref vector i))
235 (defun ebrowse-every (predicate vector)
236 "Return true if PREDICATE is true of every element of VECTOR."
237 (let ((length (length vector))
240 (while (and (< i length) result)
241 (setq result (funcall predicate (aref vector i))
246 (defun ebrowse-position (item list &optional test)
247 "Return the position of ITEM in LIST or nil if not found.
248 Compare items with `eq' or TEST if specified."
252 (when (funcall test item (car list))
253 (setq found i list nil))
254 (setq list (cdr list) i (1+ i))))
257 (when (eq item (car list))
258 (setq found i list nil))
259 (setq list (cdr list) i (1+ i)))))
263 (defun ebrowse-delete-if-not (predicate list)
264 "Remove elements not satisfying PREDICATE from LIST and return the result.
265 This is a destructive operation."
268 (let ((next (cdr list)))
269 (when (funcall predicate (car list))
270 (setq result (nconc result list))
271 (setf (cdr list) nil))
276 (defmacro ebrowse-output (&rest body)
277 "Eval BODY with a writable current buffer.
278 Preserve buffer's modified state."
279 (let ((modified (make-symbol "--ebrowse-output--")))
280 `(let (buffer-read-only (,modified (buffer-modified-p)))
283 (set-buffer-modified-p ,modified)))))
286 (defmacro ebrowse-ignoring-completion-case (&rest body)
287 "Eval BODY with `completion-ignore-case' bound to t."
288 `(let ((completion-ignore-case t))
292 (defmacro ebrowse-save-selective (&rest body)
293 "Eval BODY with `selective-display' restored at the end."
294 (let ((var (make-symbol "var")))
295 `(let ((,var selective-display))
298 (setq selective-display ,var)))))
301 (defmacro ebrowse-for-all-trees (spec &rest body)
302 "For all trees in SPEC, eval BODY."
303 (let ((var (make-symbol "var"))
304 (spec-var (car spec))
306 `(loop for ,var being the symbols of ,array
307 as ,spec-var = (get ,var 'ebrowse-root) do
308 (when (vectorp ,spec-var)
311 ;;; Set indentation for macros above.
313 (put 'ebrowse-output 'lisp-indent-hook 0)
314 (put 'ebrowse-ignoring-completion-case 'lisp-indent-hook 0)
315 (put 'ebrowse-save-selective 'lisp-indent-hook 0)
316 (put 'ebrowse-for-all-trees 'lisp-indent-hook 1)
319 (defsubst ebrowse-set-face (start end face)
320 "Set face of a region START END to FACE."
321 (overlay-put (make-overlay start end) 'face face))
324 (defun ebrowse-completing-read-value (prompt table initial-input)
325 "Read a string in the minibuffer, with completion.
326 Case is ignored in completions.
328 PROMPT is a string to prompt with; normally it ends in a colon and a space.
329 TABLE is an alist whose elements' cars are strings, or an obarray.
330 TABLE can also be a function to do the completion itself.
331 If INITIAL-INPUT is non-nil, insert it in the minibuffer initially.
332 If it is (STRING . POSITION), the initial input
333 is STRING, but point is placed POSITION characters into the string."
334 (ebrowse-ignoring-completion-case
335 (completing-read prompt table nil t initial-input)))
338 (defun ebrowse-value-in-buffer (sym buffer)
339 "Return the value of SYM in BUFFER."
340 (let ((old-buffer (current-buffer)))
345 (set-buffer old-buffer))))
348 (defun ebrowse-rename-buffer (new-name)
349 "Rename current buffer to NEW-NAME.
350 If a buffer with name NEW-NAME already exists, delete it first."
351 (let ((old-buffer (get-buffer new-name)))
352 (unless (eq old-buffer (current-buffer))
354 (save-excursion (kill-buffer old-buffer)))
355 (rename-buffer new-name))))
358 (defun ebrowse-trim-string (string)
359 "Return a copy of STRING with leading white space removed.
360 Replace sequences of newlines with a single space."
361 (when (string-match "^[ \t\n\r]+" string)
362 (setq string (substring string (match-end 0))))
363 (loop while (string-match "[\n]+" string)
364 finally return string do
365 (setq string (replace-match " " nil t string))))
368 (defun ebrowse-width-of-drawable-area ()
369 "Return the width of the display area for the current buffer.
370 If buffer is displayed in a window, use that window's width,
371 otherwise use the current frame's width."
372 (let ((window (get-buffer-window (current-buffer))))
374 (window-width window)
378 ;;; Structure definitions
380 (defstruct (ebrowse-hs (:type vector) :named)
381 "Header structure found at the head of BROWSE files."
382 ;; A version string that is compared against the version number of
383 ;; the Lisp package when the file is loaded. This is done to
384 ;; detect file format changes.
386 ;; Command line options used for producing the BROWSE file.
388 ;; The following slot is currently not used. It's kept to keep
389 ;; the file format compatible.
391 ;; A slot that is filled out after the tree is loaded. This slot is
392 ;; set to a hash table mapping members to lists of classes in which
397 (defstruct (ebrowse-ts (:type vector) :named)
399 Following the header structure, a BROWSE file contains a number
400 of `ebrowse-ts' structures, each one describing one root class of
401 the class hierarchy with all its subclasses."
402 ;; A `ebrowse-cs' structure describing the root class.
404 ;; A list of `ebrowse-ts' structures for all subclasses.
406 ;; Lists of `ebrowse-ms' structures for each member in a group of
408 member-variables member-functions static-variables static-functions
410 ;; List of `ebrowse-ts' structures for base classes. This slot is
411 ;; filled at load time.
413 ;; A marker slot used in the tree buffer (can be saved back to disk.
417 (defstruct (ebrowse-bs (:type vector) :named)
418 "Common sub-structure.
419 A common structure defining an occurrence of some name in the
421 ;; The class or member name as a string constant
423 ;; An optional string for the scope of nested classes or for
426 ;; Various flags describing properties of classes/members, e.g. is
427 ;; template, is const etc.
429 ;; File in which the entity is found. If this is part of a
430 ;; `ebrowse-ms' member description structure, and FILE is nil, then
431 ;; search for the name in the SOURCE-FILE of the members class.
433 ;; Regular expression to search for. This slot can be a number in
434 ;; which case the number is the file position at which the regular
435 ;; expression is found in a separate regexp file (see the header
436 ;; structure). This slot can be nil in which case the regular
437 ;; expression will be generated from the class/member name.
439 ;; The buffer position at which the search for the class or member
444 (defstruct (ebrowse-cs (:include ebrowse-bs) (:type vector) :named)
446 This is the structure stored in the CLASS slot of a `ebrowse-ts'
447 structure. It describes the location of the class declaration."
451 (defstruct (ebrowse-ms (:include ebrowse-bs) (:type vector) :named)
453 This is the structure describing a single member. The `ebrowse-ts'
454 structure contains various lists for the different types of
456 ;; Public, protected, private
458 ;; The file in which the member's definition can be found.
460 ;; Same as PATTERN above, but for the member definition.
462 ;; Same as POINT above but for member definition.
467 ;;; Some macros to access the FLAGS slot of a MEMBER.
469 (defsubst ebrowse-member-bit-set-p (member bit)
470 "Value is non-nil if MEMBER's bit BIT is set."
471 (/= 0 (logand (ebrowse-bs-flags member) bit)))
474 (defsubst ebrowse-virtual-p (member)
475 "Value is non-nil if MEMBER is virtual."
476 (ebrowse-member-bit-set-p member 1))
479 (defsubst ebrowse-inline-p (member)
480 "Value is non-nil if MEMBER is inline."
481 (ebrowse-member-bit-set-p member 2))
484 (defsubst ebrowse-const-p (member)
485 "Value is non-nil if MEMBER is const."
486 (ebrowse-member-bit-set-p member 4))
489 (defsubst ebrowse-pure-virtual-p (member)
490 "Value is non-nil if MEMBER is a pure virtual function."
491 (ebrowse-member-bit-set-p member 8))
494 (defsubst ebrowse-mutable-p (member)
495 "Value is non-nil if MEMBER is mutable."
496 (ebrowse-member-bit-set-p member 16))
499 (defsubst ebrowse-template-p (member)
500 "Value is non-nil if MEMBER is a template."
501 (ebrowse-member-bit-set-p member 32))
504 (defsubst ebrowse-explicit-p (member)
505 "Value is non-nil if MEMBER is explicit."
506 (ebrowse-member-bit-set-p member 64))
509 (defsubst ebrowse-throw-list-p (member)
510 "Value is non-nil if MEMBER has a throw specification."
511 (ebrowse-member-bit-set-p member 128))
514 (defsubst ebrowse-extern-c-p (member)
515 "Value is non-nil if MEMBER.is `extern \"C\"'."
516 (ebrowse-member-bit-set-p member 256))
519 (defsubst ebrowse-define-p (member)
520 "Value is non-nil if MEMBER is a define."
521 (ebrowse-member-bit-set-p member 512))
524 (defconst ebrowse-version-string "ebrowse 5.0"
525 "Version string expected in BROWSE files.")
528 (defconst ebrowse-globals-name "*Globals*"
529 "The name used for the surrogate class.containing global entities.
530 This must be the same that `ebrowse' uses.")
533 (defvar ebrowse--last-regexp nil
534 "Last regular expression searched for in tree and member buffers.
535 Each tree and member buffer maintains its own search history.")
536 (make-variable-buffer-local 'ebrowse--last-regexp)
539 (defconst ebrowse-member-list-accessors
540 '(ebrowse-ts-member-variables
541 ebrowse-ts-member-functions
542 ebrowse-ts-static-variables
543 ebrowse-ts-static-functions
546 "List of accessors for member lists.
547 Each element is the symbol of an accessor function.
548 The nth element must be the accessor for the nth member list
549 in an `ebrowse-ts' structure.")
552 ;;; FIXME: Add more doc strings for the buffer-local variables below.
554 (defvar ebrowse--tree-obarray nil
555 "Obarray holding all `ebrowse-ts' structures of a class tree.
556 Buffer-local in Ebrowse buffers.")
559 (defvar ebrowse--tags-file-name nil
560 "File from which BROWSE file was loaded.
561 Buffer-local in Ebrowse buffers.")
564 (defvar ebrowse--header nil
565 "Header structure of type `ebrowse-hs' of a class tree.
566 Buffer-local in Ebrowse buffers.")
569 (defvar ebrowse--frozen-flag nil
570 "Non-nil means an Ebrowse buffer won't be reused.
571 Buffer-local in Ebrowse buffers.")
574 (defvar ebrowse--show-file-names-flag nil
575 "Non-nil means show file names in a tree buffer.
576 Buffer-local in Ebrowse tree buffers.")
579 (defvar ebrowse--long-display-flag nil
580 "Non-nil means show members in long display form.
581 Buffer-local in Ebrowse member buffers.")
584 (defvar ebrowse--n-columns nil
585 "Number of columns to display for short member display form.
586 Buffer-local in Ebrowse member buffers.")
589 (defvar ebrowse--column-width nil
590 "Width of a columns to display for short member display form.
591 Buffer-local in Ebrowse member buffers.")
594 (defvar ebrowse--virtual-display-flag nil
595 "Non-nil means display virtual members in a member buffer.
596 Buffer-local in Ebrowse member buffers.")
599 (defvar ebrowse--inline-display-flag nil
600 "Non-nil means display inline members in a member buffer.
601 Buffer-local in Ebrowse member buffers.")
604 (defvar ebrowse--const-display-flag nil
605 "Non-nil means display const members in a member buffer.
606 Buffer-local in Ebrowse member buffers.")
609 (defvar ebrowse--pure-display-flag nil
610 "Non-nil means display pure virtual members in a member buffer.
611 Buffer-local in Ebrowse member buffers.")
614 (defvar ebrowse--filters nil
615 "Filter for display of public, protected, and private members.
616 This is a vector of three elements. An element nil means the
617 corresponding members are not shown.
618 Buffer-local in Ebrowse member buffers.")
621 (defvar ebrowse--show-inherited-flag nil
622 "Non-nil means display inherited members in a member buffer.
623 Buffer-local in Ebrowse member buffers.")
626 (defvar ebrowse--attributes-flag nil
627 "Non-nil means display member attributes in a member buffer.
628 Buffer-local in Ebrowse member buffers.")
631 (defvar ebrowse--source-regexp-flag nil
632 "Non-nil means display member regexps in a member buffer.
633 Buffer-local in Ebrowse member buffers.")
636 (defvar ebrowse--displayed-class nil
637 "Class displayed in a member buffer, a `ebrowse-ts' structure.
638 Buffer-local in Ebrowse member buffers.")
641 (defvar ebrowse--accessor nil
642 "Member list displayed in a member buffer.
643 This is a symbol whose function definition is an accessor for the
644 member list in `ebrowse-cs' structures.
645 Buffer-local in Ebrowse member buffers.")
648 (defvar ebrowse--member-list nil
649 "The list of `ebrowse-ms' structures displayed in a member buffer.
650 Buffer-local in Ebrowse member buffers.")
653 (defvar ebrowse--decl-column nil
654 "Column in which declarations are displayed in member buffers.
655 Buffer-local in Ebrowse member buffers.")
658 (defvar ebrowse--frame-configuration nil
659 "Frame configuration saved when viewing a class/member in another frame.
660 Buffer-local in Ebrowse buffers.")
663 (defvar ebrowse--view-exit-action nil
664 "Action to perform after viewing a class/member.
665 Either `kill-buffer' or nil.
666 Buffer-local in Ebrowse buffers.")
669 (defvar ebrowse--tree nil
671 Buffer-local in Ebrowse buffers.")
674 ;;; Temporaries used to communicate with `ebrowse-find-pattern'.
676 (defvar ebrowse-temp-position-to-view nil)
677 (defvar ebrowse-temp-info-to-view nil)
680 (defvar ebrowse-tree-mode-map ()
681 "The keymap used in tree mode buffers.")
684 (defvar ebrowse--member-mode-strings nil
685 "Strings displayed in the mode line of member buffers.")
688 (defvar ebrowse-member-mode-map ()
689 "The keymap used in the member buffers.")
692 ;;; Define mode line titles for each member list.
694 (put 'ebrowse-ts-member-variables 'ebrowse-title "Member Variables")
695 (put 'ebrowse-ts-member-functions 'ebrowse-title "Member Functions")
696 (put 'ebrowse-ts-static-variables 'ebrowse-title "Static Variables")
697 (put 'ebrowse-ts-static-functions 'ebrowse-title "Static Functions")
698 (put 'ebrowse-ts-friends 'ebrowse-title "Friends")
699 (put 'ebrowse-ts-types 'ebrowse-title "Types")
701 (put 'ebrowse-ts-member-variables 'ebrowse-global-title "Global Variables")
702 (put 'ebrowse-ts-member-functions 'ebrowse-global-title "Global Functions")
703 (put 'ebrowse-ts-static-variables 'ebrowse-global-title "Static Variables")
704 (put 'ebrowse-ts-static-functions 'ebrowse-global-title "Static Functions")
705 (put 'ebrowse-ts-friends 'ebrowse-global-title "Defines")
706 (put 'ebrowse-ts-types 'ebrowse-global-title "Types")
710 ;;; Operations on `ebrowse-ts' structures
712 (defun ebrowse-files-table (&optional marked-only)
713 "Return an obarray containing all files mentioned in the current tree.
714 The tree is expected in the buffer-local variable `ebrowse--tree-obarray'.
715 MARKED-ONLY non-nil means include marked classes only."
716 (let ((files (make-hash-table :test 'equal))
718 (ebrowse-for-all-trees (tree ebrowse--tree-obarray)
719 (when (or (not marked-only) (ebrowse-ts-mark tree))
720 (let ((class (ebrowse-ts-class tree)))
721 (when (zerop (% (incf i) 20))
722 (ebrowse-show-progress "Preparing file list" (zerop i)))
723 ;; Add files mentioned in class description
724 (let ((source-file (ebrowse-cs-source-file class))
725 (file (ebrowse-cs-file class)))
727 (puthash source-file source-file files))
729 (puthash file file files))
730 ;; For all member lists in this class
731 (loop for accessor in ebrowse-member-list-accessors do
732 (loop for m in (funcall accessor tree)
733 for file = (ebrowse-ms-file m)
734 for def-file = (ebrowse-ms-definition-file m) do
736 (puthash file file files))
738 (puthash def-file def-file files))))))))
742 (defun ebrowse-files-list (&optional marked-only)
743 "Return a list containing all files mentioned in a tree.
744 MARKED-ONLY non-nil means include marked classes only."
746 (maphash #'(lambda (file dummy) (setq list (cons file list)))
747 (ebrowse-files-table marked-only))
751 (defun* ebrowse-marked-classes-p ()
752 "Value is non-nil if any class in the current class tree is marked."
753 (ebrowse-for-all-trees (tree ebrowse--tree-obarray)
754 (when (ebrowse-ts-mark tree)
755 (return-from ebrowse-marked-classes-p tree))))
758 (defsubst ebrowse-globals-tree-p (tree)
759 "Return t if TREE is the one for global entities."
760 (string= (ebrowse-bs-name (ebrowse-ts-class tree))
761 ebrowse-globals-name))
764 (defsubst ebrowse-qualified-class-name (class)
765 "Return the name of CLASS with scope prepended, if any."
766 (if (ebrowse-cs-scope class)
767 (concat (ebrowse-cs-scope class) "::" (ebrowse-cs-name class))
768 (ebrowse-cs-name class)))
771 (defun ebrowse-tree-obarray-as-alist (&optional qualified-names-p)
772 "Return an alist describing all classes in a tree.
773 Each elements in the list has the form (CLASS-NAME . TREE).
774 CLASS-NAME is the name of the class. TREE is the
775 class tree whose root is QUALIFIED-CLASS-NAME.
776 QUALIFIED-NAMES-P non-nil means return qualified names as CLASS-NAME.
777 The class tree is found in the buffer-local variable `ebrowse--tree-obarray'."
779 (if qualified-names-p
780 (ebrowse-for-all-trees (tree ebrowse--tree-obarray)
782 (acons (ebrowse-qualified-class-name (ebrowse-ts-class tree))
784 (ebrowse-for-all-trees (tree ebrowse--tree-obarray)
786 (acons (ebrowse-cs-name (ebrowse-ts-class tree))
791 (defun ebrowse-sort-tree-list (list)
792 "Sort a LIST of `ebrowse-ts' structures by qualified class names."
795 (string< (ebrowse-qualified-class-name (ebrowse-ts-class a))
796 (ebrowse-qualified-class-name (ebrowse-ts-class b))))))
799 (defun ebrowse-class-in-tree (class tree)
800 "Search for a class with name CLASS in TREE.
801 If CLASS is found, return the tail of TREE starting at CLASS. This function
802 is used during the load phase where classes appended to a file replace older
804 (let ((tclass (ebrowse-ts-class class))
806 (while (and tree (not found))
807 (let ((root-ptr tree))
808 (when (string= (ebrowse-qualified-class-name (ebrowse-ts-class (car root-ptr)))
809 (ebrowse-qualified-class-name tclass))
810 (setq found root-ptr))
811 (setq tree (cdr tree))))
815 (defun ebrowse-base-classes (tree)
816 "Return list of base-classes of TREE by searching subclass lists.
817 This function must be used instead of the struct slot
818 `base-classes' to access the base-class list directly because it
819 computes this information lazily."
820 (or (ebrowse-ts-base-classes tree)
821 (setf (ebrowse-ts-base-classes tree)
822 (loop with to-search = (list tree)
824 as search = (pop to-search)
825 while search finally return result
826 do (ebrowse-for-all-trees (ti ebrowse--tree-obarray)
827 (when (memq search (ebrowse-ts-subclasses ti))
828 (unless (memq ti result)
829 (setq result (nconc result (list ti))))
830 (push ti to-search)))))))
833 (defun ebrowse-direct-base-classes (tree)
834 "Return the list of direct super classes of TREE."
836 (dolist (s (ebrowse-base-classes tree))
837 (when (memq tree (ebrowse-ts-subclasses s))
838 (setq result (cons s result))))
843 ;;; Operations on MEMBER structures/lists
845 (defun ebrowse-name/accessor-alist (tree accessor)
846 "Return an alist containing all members of TREE in group ACCESSOR.
847 ACCESSOR is the accessor function for the member list.
848 Elements of the result have the form (NAME . ACCESSOR), where NAME
850 (loop for member in (funcall accessor tree)
851 collect (cons (ebrowse-ms-name member) accessor)))
854 (defun ebrowse-name/accessor-alist-for-visible-members ()
855 "Return an alist describing all members visible in the current buffer.
856 Each element of the list has the form (MEMBER-NAME . ACCESSOR),
857 where MEMBER-NAME is the member's name, and ACCESSOR is the struct
858 accessor with which the member's list can be accessed in an `ebrowse-ts'
859 structure. The list includes inherited members if these are visible."
860 (let* ((list (ebrowse-name/accessor-alist ebrowse--displayed-class
862 (if ebrowse--show-inherited-flag
864 (loop for tree in (ebrowse-base-classes
865 ebrowse--displayed-class)
866 nconc (ebrowse-name/accessor-alist
867 tree ebrowse--accessor)))
871 (defun ebrowse-name/accessor-alist-for-class-members ()
872 "Like `ebrowse-name/accessor-alist-for-visible-members'.
873 This function includes members of base classes if base class members
874 are visible in the buffer."
876 (dolist (func ebrowse-member-list-accessors list)
877 (setq list (nconc list (ebrowse-name/accessor-alist
878 ebrowse--displayed-class func)))
879 (when ebrowse--show-inherited-flag
880 (dolist (class (ebrowse-base-classes ebrowse--displayed-class))
882 (nconc list (ebrowse-name/accessor-alist class func))))))))
885 ;;; Progress indication
887 (defvar ebrowse-n-boxes 0)
888 (defconst ebrowse-max-boxes 60)
890 (defun ebrowse-show-progress (title &optional start)
891 "Display a progress indicator.
892 TITLE is the title of the progress message. START non-nil means
893 this is the first progress message displayed."
894 (let (message-log-max)
895 (when start (setq ebrowse-n-boxes 0))
896 (setq ebrowse-n-boxes (mod (1+ ebrowse-n-boxes) ebrowse-max-boxes))
897 (message (concat title ": "
898 (propertize (make-string ebrowse-n-boxes
899 (if (display-color-p) ?\ ?+))
900 'face 'ebrowse-progress)))))
903 ;;; Reading a tree from disk
905 (defun ebrowse-read ()
906 "Read `ebrowse-hs' and `ebrowse-ts' structures in the current buffer.
907 Return a list (HEADER TREE) where HEADER is the file header read
908 and TREE is a list of `ebrowse-ts' structures forming the class tree."
909 (let ((header (condition-case nil
910 (read (current-buffer))
911 (error (error "No Ebrowse file header found"))))
913 ;; Check file format.
914 (unless (ebrowse-hs-p header)
915 (error "No Ebrowse file header found"))
916 (unless (string= (ebrowse-hs-version header) ebrowse-version-string)
917 (error "File has wrong version `%s' (`%s' expected)"
918 (ebrowse-hs-version header) ebrowse-version-string))
919 ;; Read Lisp objects. Temporarily increase `gc-cons-threshold' to
920 ;; prevent a GC that would not free any memory.
921 (let ((gc-cons-threshold 2000000))
922 (while (not (progn (skip-chars-forward " \t\n\r") (eobp)))
923 (let* ((root (read (current-buffer)))
924 (old-root-ptr (ebrowse-class-in-tree root tree)))
925 (ebrowse-show-progress "Reading data" (null tree))
927 (setcar old-root-ptr root)
933 (defun ebrowse-revert-tree-buffer-from-file (ignore-auto-save noconfirm)
934 "Function installed as `revert-buffer-function' in tree buffers.
935 See that variable's documentation for the meaning of IGNORE-AUTO-SAVE and
937 (when (or noconfirm (yes-or-no-p "Revert tree from disk? "))
938 (loop for member-buffer in (ebrowse-same-tree-member-buffer-list)
939 do (kill-buffer member-buffer))
941 (insert-file (or buffer-file-name ebrowse--tags-file-name))
946 (defun ebrowse-create-tree-buffer (tree tags-file header obarray pop)
947 "Create a new tree buffer for tree TREE.
948 The tree was loaded from file TAGS-FILE.
949 HEADER is the header structure of the file.
950 OBARRAY is an obarray with a symbol for each class in the tree.
951 POP non-nil means popup the buffer up at the end.
952 Return the buffer created."
953 (let ((name ebrowse-tree-buffer-name))
954 (set-buffer (get-buffer-create name))
956 (setq ebrowse--tree tree
957 ebrowse--tags-file-name tags-file
958 ebrowse--tree-obarray obarray
959 ebrowse--header header
960 ebrowse--frozen-flag nil)
961 (ebrowse-redraw-tree)
962 (set-buffer-modified-p nil)
964 (switch (switch-to-buffer name))
965 (pop (pop-to-buffer name)))
970 ;;; Operations for member obarrays
972 (defun ebrowse-fill-member-table ()
973 "Return an obarray holding all members of all classes in the current tree.
975 For each member, a symbol is added to the obarray. Members are
976 extracted from the buffer-local tree `ebrowse--tree-obarray'.
978 Each symbol has its property `ebrowse-info' set to a list (TREE MEMBER-LIST
979 MEMBER) where TREE is the tree in which the member is defined,
980 MEMBER-LIST is a symbol describing the member list in which the member
981 is found, and MEMBER is a MEMBER structure describing the member.
983 The slot `member-table' of the buffer-local header structure of
984 type `ebrowse-hs' is set to the resulting obarray."
985 (let ((members (make-hash-table :test 'equal))
987 (setf (ebrowse-hs-member-table ebrowse--header) nil)
989 ;; For all classes...
990 (ebrowse-for-all-trees (c ebrowse--tree-obarray)
991 (when (zerop (% (incf i) 10))
992 (ebrowse-show-progress "Preparing member lookup" (zerop i)))
993 (loop for f in ebrowse-member-list-accessors do
994 (loop for m in (funcall f c) do
995 (let* ((member-name (ebrowse-ms-name m))
996 (value (gethash member-name members)))
997 (push (list c f m) value)
998 (puthash member-name value members)))))
999 (setf (ebrowse-hs-member-table ebrowse--header) members)))
1002 (defun ebrowse-member-table (header)
1003 "Return the member obarray. Build it it hasn't been set up yet.
1004 HEADER is the tree header structure of the class tree."
1005 (when (null (ebrowse-hs-member-table header))
1006 (loop for buffer in (ebrowse-browser-buffer-list)
1007 until (eq header (ebrowse-value-in-buffer 'ebrowse--header buffer))
1011 (ebrowse-fill-member-table))))
1012 (ebrowse-hs-member-table header))
1016 ;;; Operations on TREE obarrays
1018 (defun ebrowse-build-tree-obarray (tree)
1019 "Make sure every class in TREE is represented by a unique object.
1020 Build obarray of all classes in TREE."
1021 (let ((classes (make-vector 127 0)))
1022 ;; Add root classes...
1023 (loop for root in tree
1025 (intern (ebrowse-qualified-class-name (ebrowse-ts-class root)) classes)
1026 do (unless (get sym 'ebrowse-root)
1027 (setf (get sym 'ebrowse-root) root)))
1028 ;; Process subclasses
1029 (ebrowse-insert-supers tree classes)
1033 (defun ebrowse-insert-supers (tree classes)
1034 "Build base class lists in class tree TREE.
1035 CLASSES is an obarray used to collect classes.
1037 Helper function for `ebrowse-build-tree-obarray'. Base classes should
1038 be ordered so that immediate base classes come first, then the base
1039 class of the immediate base class and so on. This means that we must
1040 construct the base-class list top down with adding each level at the
1041 beginning of the base-class list.
1043 We have to be cautious here not to end up in an infinite recursion
1044 if for some reason a circle is in the inheritance graph."
1045 (loop for class in tree
1046 as subclasses = (ebrowse-ts-subclasses class) do
1047 ;; Make sure every class is represented by a unique object
1048 (loop for subclass on subclasses
1050 (ebrowse-qualified-class-name (ebrowse-ts-class (car subclass)))
1054 ;; Replace the subclass tree with the one found in
1055 ;; CLASSES if there is already an entry for that class
1056 ;; in it. Otherwise make a new entry.
1058 ;; CAVEAT: If by some means (e.g., use of the
1059 ;; preprocessor in class declarations, a name is marked
1060 ;; as a subclass of itself on some path, we would end up
1061 ;; in an endless loop. We have to omit subclasses from
1062 ;; the recursion that already have been processed.
1063 (if (get sym 'ebrowse-root)
1064 (setf (car subclass) (get sym 'ebrowse-root))
1065 (setf (get sym 'ebrowse-root) (car subclass))))
1066 ;; Process subclasses
1067 (ebrowse-insert-supers subclasses classes)))
1072 (unless ebrowse-tree-mode-map
1073 (let ((map (make-keymap)))
1074 (setf ebrowse-tree-mode-map map)
1075 (suppress-keymap map)
1077 (when (display-mouse-p)
1078 (define-key map [down-mouse-3] 'ebrowse-mouse-3-in-tree-buffer)
1079 (define-key map [mouse-2] 'ebrowse-mouse-2-in-tree-buffer)
1080 (define-key map [down-mouse-1] 'ebrowse-mouse-1-in-tree-buffer))
1082 (let ((map1 (make-sparse-keymap)))
1083 (suppress-keymap map1 t)
1084 (define-key map "L" map1)
1085 (define-key map1 "d" 'ebrowse-tree-command:show-friends)
1086 (define-key map1 "f" 'ebrowse-tree-command:show-member-functions)
1087 (define-key map1 "F" 'ebrowse-tree-command:show-static-member-functions)
1088 (define-key map1 "t" 'ebrowse-tree-command:show-types)
1089 (define-key map1 "v" 'ebrowse-tree-command:show-member-variables)
1090 (define-key map1 "V" 'ebrowse-tree-command:show-static-member-variables))
1092 (let ((map1 (make-sparse-keymap)))
1093 (suppress-keymap map1 t)
1094 (define-key map "M" map1)
1095 (define-key map1 "a" 'ebrowse-mark-all-classes)
1096 (define-key map1 "t" 'ebrowse-toggle-mark-at-point))
1098 (let ((map1 (make-sparse-keymap)))
1099 (suppress-keymap map1 t)
1100 (define-key map "T" map1)
1101 (define-key map1 "f" 'ebrowse-toggle-file-name-display)
1102 (define-key map1 "s" 'ebrowse-show-file-name-at-point)
1103 (define-key map1 "w" 'ebrowse-set-tree-indentation)
1104 (define-key map "x" 'ebrowse-statistics))
1106 (define-key map "n" 'ebrowse-repeat-member-search)
1107 (define-key map "q" 'bury-buffer)
1108 (define-key map "*" 'ebrowse-expand-all)
1109 (define-key map "+" 'ebrowse-expand-branch)
1110 (define-key map "-" 'ebrowse-collapse-branch)
1111 (define-key map "/" 'ebrowse-read-class-name-and-go)
1112 (define-key map " " 'ebrowse-view-class-declaration)
1113 (define-key map "?" 'describe-mode)
1114 (define-key map "\C-i" 'ebrowse-pop/switch-to-member-buffer-for-same-tree)
1115 (define-key map "\C-k" 'ebrowse-remove-class-at-point)
1116 (define-key map "\C-l" 'ebrowse-redraw-tree)
1117 (define-key map "\C-m" 'ebrowse-find-class-declaration)))
1121 ;;; Tree-mode - mode for tree buffers
1124 (defun ebrowse-tree-mode ()
1125 "Major mode for Ebrowse class tree buffers.
1126 Each line corresponds to a class in a class tree.
1127 Letters do not insert themselves, they are commands.
1128 File operations in the tree buffer work on class tree data structures.
1129 E.g.\\[save-buffer] writes the tree to the file it was loaded from.
1131 Tree mode key bindings:
1132 \\{ebrowse-tree-mode-map}"
1134 (let* ((ident (propertized-buffer-identification "C++ Tree"))
1135 header tree buffer-read-only)
1137 (kill-all-local-variables)
1138 (use-local-map ebrowse-tree-mode-map)
1140 (unless (zerop (buffer-size))
1141 (goto-char (point-min))
1142 (multiple-value-setq (header tree) (ebrowse-read))
1143 (message "Sorting. Please be patient...")
1144 (setq tree (ebrowse-sort-tree-list tree))
1148 (mapcar 'make-local-variable
1149 '(ebrowse--tags-file-name
1150 ebrowse--indentation
1153 ebrowse--show-file-names-flag
1154 ebrowse--frozen-flag
1155 ebrowse--tree-obarray
1156 revert-buffer-function))
1158 (setf ebrowse--show-file-names-flag nil
1159 ebrowse--tree-obarray (make-vector 127 0)
1160 ebrowse--frozen-flag nil
1161 major-mode 'ebrowse-tree-mode
1162 mode-name "Ebrowse-Tree"
1163 mode-line-buffer-identification ident
1166 selective-display-ellipses t
1167 revert-buffer-function 'ebrowse-revert-tree-buffer-from-file
1168 ebrowse--header header
1170 ebrowse--tags-file-name (buffer-file-name)
1171 ebrowse--tree-obarray (and tree (ebrowse-build-tree-obarray tree))
1172 ebrowse--frozen-flag nil)
1174 (add-hook 'local-write-file-hooks 'ebrowse-write-file-hook-fn)
1175 (modify-syntax-entry ?_ (char-to-string (char-syntax ?a)))
1177 (ebrowse-redraw-tree)
1178 (set-buffer-modified-p nil))
1179 (run-mode-hooks 'ebrowse-tree-mode-hook)))
1183 (defun ebrowse-update-tree-buffer-mode-line ()
1184 "Update the tree buffer mode line."
1185 (ebrowse-rename-buffer (if ebrowse--frozen-flag
1186 (ebrowse-frozen-tree-buffer-name
1187 ebrowse--tags-file-name)
1188 ebrowse-tree-buffer-name))
1189 (force-mode-line-update))
1193 ;;; Removing classes from trees
1195 (defun ebrowse-remove-class-and-kill-member-buffers (tree class)
1196 "Remove from TREE class CLASS.
1197 Kill all member buffers still containing a reference to the class."
1198 (let ((sym (intern-soft (ebrowse-cs-name (ebrowse-ts-class class))
1199 ebrowse--tree-obarray)))
1200 (setf tree (delq class tree)
1201 (get sym 'ebrowse-root) nil)
1203 (setf (ebrowse-ts-subclasses root)
1204 (delq class (ebrowse-ts-subclasses root))
1205 (ebrowse-ts-base-classes root) nil)
1206 (ebrowse-remove-class-and-kill-member-buffers
1207 (ebrowse-ts-subclasses root) class))
1208 (ebrowse-kill-member-buffers-displaying class)
1212 (defun ebrowse-remove-class-at-point (forced)
1213 "Remove the class point is on from the class tree.
1214 Do not ask for confirmation if FORCED is non-nil."
1216 (let* ((class (ebrowse-tree-at-point))
1217 (class-name (ebrowse-cs-name (ebrowse-ts-class class)))
1218 (subclasses (ebrowse-ts-subclasses class)))
1220 (y-or-n-p (concat "Delete class " class-name "? ")))
1221 (setf ebrowse--tree (ebrowse-remove-class-and-kill-member-buffers
1222 ebrowse--tree class))
1223 (set-buffer-modified-p t)
1224 (message "%s %sdeleted." class-name
1225 (if subclasses "and derived classes " ""))
1226 (ebrowse-redraw-tree))
1227 (t (message "Aborted")))))
1231 ;;; Marking classes in the tree buffer
1233 (defun ebrowse-toggle-mark-at-point (&optional n-times)
1234 "Toggle mark for class cursor is on.
1235 If given a numeric N-TIMES argument, mark that many classes."
1237 (let (to-change pnt)
1238 ;; Get the classes whose mark must be toggled. Note that
1239 ;; ebrowse-tree-at-point might issue an error.
1240 (condition-case error
1241 (loop repeat (or n-times 1)
1242 as tree = (ebrowse-tree-at-point)
1244 (setf (ebrowse-ts-mark tree) (not (ebrowse-ts-mark tree)))
1246 (push tree to-change)))
1249 ;; For all these classes, reverse the mark char in the display
1250 ;; by a regexp replace over the whole buffer. The reason for this
1251 ;; is that classes might have multiple base classes. If this is
1252 ;; the case, they are displayed more than once in the tree.
1254 (loop for tree in to-change
1255 as regexp = (concat "^.*\\b"
1257 (ebrowse-cs-name (ebrowse-ts-class tree)))
1260 (goto-char (point-min))
1261 (loop while (re-search-forward regexp nil t)
1263 (goto-char (match-beginning 0))
1265 (insert-char (if (ebrowse-ts-mark tree) ?> ? ) 1)
1266 (ebrowse-set-mark-props (1- (point)) (point) tree)
1267 (goto-char (match-end 0)))))))))
1270 (defun ebrowse-mark-all-classes (prefix)
1271 "Unmark, with PREFIX mark, all classes in the tree."
1273 (ebrowse-for-all-trees (tree ebrowse--tree-obarray)
1274 (setf (ebrowse-ts-mark tree) prefix))
1275 (ebrowse-redraw-marks (point-min) (point-max)))
1278 (defun ebrowse-redraw-marks (start end)
1279 "Display class marker signs in the tree between START and END."
1284 (goto-char (point-min))
1285 (dolist (root ebrowse--tree)
1286 (ebrowse-draw-marks-fn root start end))))
1287 (ebrowse-update-tree-buffer-mode-line)))
1290 (defun ebrowse-draw-marks-fn (tree start end)
1291 "Display class marker signs in TREE between START and END."
1292 (when (>= (point) start)
1294 (insert (if (ebrowse-ts-mark tree) ?> ? ))
1295 (ebrowse-set-mark-props (1- (point)) (point) tree))
1297 (when (> (point) end)
1299 (dolist (sub (ebrowse-ts-subclasses tree))
1300 (ebrowse-draw-marks-fn sub start end)))
1304 ;;; File name display in tree buffers
1306 (defun ebrowse-show-file-name-at-point (prefix)
1307 "Show filename in the line point is in.
1308 With PREFIX, insert that many filenames."
1310 (unless ebrowse--show-file-names-flag
1313 (let ((tree (ebrowse-tree-at-point))
1317 (skip-chars-forward " \t*a-zA-Z0-9_")
1319 file-name-existing (looking-at "("))
1320 (delete-region start (save-excursion (end-of-line) (point)))
1321 (unless file-name-existing
1322 (indent-to ebrowse-source-file-column)
1323 (insert "(" (or (ebrowse-cs-file
1324 (ebrowse-ts-class tree))
1327 (ebrowse-set-face start (point) 'ebrowse-file-name)
1329 (forward-line 1))))))
1332 (defun ebrowse-toggle-file-name-display ()
1333 "Toggle display of filenames in tree buffer."
1335 (setf ebrowse--show-file-names-flag (not ebrowse--show-file-names-flag))
1336 (let ((old-line (count-lines (point-min) (point))))
1337 (ebrowse-redraw-tree)
1338 (goto-line old-line)))
1342 ;;; General member and tree buffer functions
1344 (defun ebrowse-member-buffer-p (buffer)
1345 "Value is non-nil if BUFFER is a member buffer."
1346 (eq (cdr (assoc 'major-mode (buffer-local-variables buffer)))
1347 'ebrowse-member-mode))
1350 (defun ebrowse-tree-buffer-p (buffer)
1351 "Value is non-nil if BUFFER is a class tree buffer."
1352 (eq (cdr (assoc 'major-mode (buffer-local-variables buffer)))
1353 'ebrowse-tree-mode))
1356 (defun ebrowse-buffer-p (buffer)
1357 "Value is non-nil if BUFFER is a tree or member buffer."
1358 (memq (cdr (assoc 'major-mode (buffer-local-variables buffer)))
1359 '(ebrowse-tree-mode ebrowse-member-mode)))
1362 (defun ebrowse-browser-buffer-list ()
1363 "Return a list of all tree or member buffers."
1364 (ebrowse-delete-if-not 'ebrowse-buffer-p (buffer-list)))
1367 (defun ebrowse-member-buffer-list ()
1368 "Return a list of all member buffers."
1369 (ebrowse-delete-if-not 'ebrowse-member-buffer-p (buffer-list)))
1372 (defun ebrowse-tree-buffer-list ()
1373 "Return a list of all tree buffers."
1374 (ebrowse-delete-if-not 'ebrowse-tree-buffer-p (buffer-list)))
1377 (defun ebrowse-known-class-trees-buffer-list ()
1378 "Return a list of buffers containing class trees.
1379 The list will contain, for each class tree loaded,
1380 one buffer. Prefer tree buffers over member buffers."
1381 (let ((buffers (nconc (ebrowse-tree-buffer-list)
1382 (ebrowse-member-buffer-list)))
1383 (set (make-hash-table))
1385 (dolist (buffer buffers)
1386 (let ((tree (ebrowse-value-in-buffer 'ebrowse--tree buffer)))
1387 (unless (gethash tree set)
1388 (push buffer result))
1389 (puthash tree t set)))
1393 (defun ebrowse-same-tree-member-buffer-list ()
1394 "Return a list of members buffers with same tree as current buffer."
1395 (ebrowse-delete-if-not
1397 (eq (ebrowse-value-in-buffer 'ebrowse--tree buffer)
1399 (ebrowse-member-buffer-list)))
1403 (defun ebrowse-pop/switch-to-member-buffer-for-same-tree (arg)
1404 "Pop to the buffer displaying members.
1405 Switch to buffer if prefix ARG.
1406 If no member buffer exists, make one."
1408 (let ((buf (or (first (ebrowse-same-tree-member-buffer-list))
1409 (get-buffer ebrowse-member-buffer-name)
1410 (ebrowse-tree-command:show-member-functions))))
1413 (switch-to-buffer buf)
1414 (pop-to-buffer buf)))
1418 (defun ebrowse-switch-to-next-member-buffer ()
1419 "Switch to next member buffer."
1421 (let* ((list (ebrowse-member-buffer-list))
1422 (next-list (cdr (memq (current-buffer) list)))
1423 (next-buffer (if next-list (car next-list) (car list))))
1424 (if (eq next-buffer (current-buffer))
1425 (error "No next buffer")
1427 (switch-to-buffer next-buffer))))
1430 (defun ebrowse-kill-member-buffers-displaying (tree)
1431 "Kill all member buffers displaying TREE."
1432 (loop for buffer in (ebrowse-member-buffer-list)
1433 as class = (ebrowse-value-in-buffer 'ebrowse--displayed-class buffer)
1434 when (eq class tree) do (kill-buffer buffer)))
1437 (defun ebrowse-frozen-tree-buffer-name (tags-file-name)
1438 "Return the buffer name of a tree which is associated TAGS-FILE-NAME."
1439 (concat ebrowse-tree-buffer-name " (" tags-file-name ")"))
1442 (defun ebrowse-pop-to-browser-buffer (arg)
1443 "Pop to a browser buffer from any other buffer.
1444 Pop to member buffer if no prefix ARG, to tree buffer otherwise."
1446 (let ((buffer (get-buffer (if arg
1447 ebrowse-tree-buffer-name
1448 ebrowse-member-buffer-name))))
1452 ebrowse-member-buffer-name
1453 ebrowse-tree-buffer-name))))
1455 (error "No browser buffer found"))
1456 (pop-to-buffer buffer)))
1460 ;;; Misc tree buffer commands
1462 (defun ebrowse-set-tree-indentation ()
1463 "Set the indentation width of the tree display."
1465 (let ((width (string-to-number (read-from-minibuffer
1466 (concat "Indentation ("
1467 (int-to-string ebrowse--indentation)
1470 (setf ebrowse--indentation width)
1471 (ebrowse-redraw-tree))))
1474 (defun ebrowse-read-class-name-and-go (&optional class)
1475 "Position cursor on CLASS.
1476 Read a class name from the minibuffer if CLASS is nil."
1478 (ebrowse-ignoring-completion-case
1479 ;; If no class specified, read the class name from mini-buffer
1482 (completing-read "Goto class: "
1483 (ebrowse-tree-obarray-as-alist) nil t)))
1484 (ebrowse-save-selective
1485 (goto-char (point-min))
1487 (setf selective-display nil)
1488 (setq ebrowse--last-regexp (concat "\\b" class "\\b"))
1489 (if (re-search-forward ebrowse--last-regexp nil t)
1491 (goto-char (match-beginning 0))
1492 (ebrowse-unhide-base-classes))
1493 (error "Not found")))))
1497 ;;; Showing various kinds of member buffers
1499 (defun ebrowse-tree-command:show-member-variables (arg)
1500 "Display member variables; with prefix ARG in frozen member buffer."
1502 (ebrowse-display-member-buffer 'ebrowse-ts-member-variables arg))
1505 (defun ebrowse-tree-command:show-member-functions (&optional arg)
1506 "Display member functions; with prefix ARG in frozen member buffer."
1508 (ebrowse-display-member-buffer 'ebrowse-ts-member-functions arg))
1511 (defun ebrowse-tree-command:show-static-member-variables (arg)
1512 "Display static member variables; with prefix ARG in frozen member buffer."
1514 (ebrowse-display-member-buffer 'ebrowse-ts-static-variables arg))
1517 (defun ebrowse-tree-command:show-static-member-functions (arg)
1518 "Display static member functions; with prefix ARG in frozen member buffer."
1520 (ebrowse-display-member-buffer 'ebrowse-ts-static-functions arg))
1523 (defun ebrowse-tree-command:show-friends (arg)
1524 "Display friend functions; with prefix ARG in frozen member buffer."
1526 (ebrowse-display-member-buffer 'ebrowse-ts-friends arg))
1529 (defun ebrowse-tree-command:show-types (arg)
1530 "Display types defined in a class; with prefix ARG in frozen member buffer."
1532 (ebrowse-display-member-buffer 'ebrowse-ts-types arg))
1536 ;;; Viewing or finding a class declaration
1538 (defun ebrowse-tree-at-point ()
1539 "Return the class structure for the class point is on."
1540 (or (get-text-property (point) 'ebrowse-tree)
1541 (error "Not on a class")))
1544 (defun* ebrowse-view/find-class-declaration (&key view where)
1545 "View or find the declarator of the class point is on.
1546 VIEW non-nil means view it. WHERE is additional position info."
1547 (let* ((class (ebrowse-ts-class (ebrowse-tree-at-point)))
1548 (file (ebrowse-cs-file class))
1549 (browse-struct (make-ebrowse-bs
1550 :name (ebrowse-cs-name class)
1551 :pattern (ebrowse-cs-pattern class)
1552 :flags (ebrowse-cs-flags class)
1553 :file (ebrowse-cs-file class)
1554 :point (ebrowse-cs-point class))))
1555 (ebrowse-view/find-file-and-search-pattern
1557 (list ebrowse--header class nil)
1559 ebrowse--tags-file-name
1564 (defun ebrowse-find-class-declaration (prefix-arg)
1565 "Find a class declaration and position cursor on it.
1566 PREFIX-ARG 4 means find it in another window.
1567 PREFIX-ARG 5 means find it in another frame."
1569 (ebrowse-view/find-class-declaration
1571 :where (cond ((= prefix-arg 4) 'other-window)
1572 ((= prefix-arg 5) 'other-frame)
1576 (defun ebrowse-view-class-declaration (prefix-arg)
1577 "View class declaration and position cursor on it.
1578 PREFIX-ARG 4 means view it in another window.
1579 PREFIX-ARG 5 means view it in another frame."
1581 (ebrowse-view/find-class-declaration
1583 :where (cond ((= prefix-arg 4) 'other-window)
1584 ((= prefix-arg 5) 'other-frame)
1591 (defun ebrowse-find-source-file (file tags-file-name)
1592 "Find source file FILE.
1593 Source files are searched for (a) relative to TAGS-FILE-NAME
1594 which is the path of the BROWSE file from which the class tree was loaded,
1595 and (b) in the directories named in `ebrowse-search-path'."
1597 (try-file (expand-file-name file
1598 (file-name-directory tags-file-name))))
1599 (if (file-readable-p try-file)
1600 (setq file-name try-file)
1601 (let ((search-in ebrowse-search-path))
1602 (while (and search-in
1604 (let ((try-file (expand-file-name file (car search-in))))
1605 (if (file-readable-p try-file)
1606 (setq file-name try-file))
1607 (setq search-in (cdr search-in))))))
1609 (error "File `%s' not found" file))
1613 (defun ebrowse-view-file-other-window (file)
1614 "View a file FILE in another window.
1615 This is a replacement for `view-file-other-window' which does not
1616 seem to work. It should be removed when `view.el' is fixed."
1618 (let ((old-arrangement (current-window-configuration))
1619 (had-a-buf (get-file-buffer file))
1620 (buf-to-view (find-file-noselect file)))
1621 (switch-to-buffer-other-window buf-to-view)
1622 (view-mode-enter old-arrangement
1623 (and (not had-a-buf)
1624 (not (buffer-modified-p buf-to-view))
1628 (defun ebrowse-view-exit-fn (buffer)
1629 "Function called when exiting View mode in BUFFER.
1630 Restore frame configuration active before viewing the file,
1631 and possibly kill the viewed buffer."
1632 (let (exit-action original-frame-configuration)
1635 (setq original-frame-configuration ebrowse--frame-configuration
1636 exit-action ebrowse--view-exit-action))
1637 ;; Delete the frame in which we viewed.
1638 (mapcar 'delete-frame
1639 (loop for frame in (frame-list)
1640 when (not (assq frame original-frame-configuration))
1643 (funcall exit-action buffer))))
1646 (defun ebrowse-view-file-other-frame (file)
1647 "View a file FILE in another frame.
1648 The new frame is deleted when it is no longer used."
1650 (let ((old-frame-configuration (current-frame-configuration))
1651 (old-arrangement (current-window-configuration))
1652 (had-a-buf (get-file-buffer file))
1653 (buf-to-view (find-file-noselect file)))
1654 (switch-to-buffer-other-frame buf-to-view)
1655 (make-local-variable 'ebrowse--frame-configuration)
1656 (setq ebrowse--frame-configuration old-frame-configuration)
1657 (make-local-variable 'ebrowse--view-exit-action)
1658 (setq ebrowse--view-exit-action
1659 (and (not had-a-buf)
1660 (not (buffer-modified-p buf-to-view))
1662 (view-mode-enter old-arrangement 'ebrowse-view-exit-fn)))
1665 (defun ebrowse-view/find-file-and-search-pattern
1666 (struc info file tags-file-name &optional view where)
1667 "Find or view a member or class.
1668 STRUC is an `ebrowse-bs' structure (or a structure including that)
1669 describing what to search.
1670 INFO is a list (HEADER MEMBER-OR-CLASS ACCESSOR). HEADER is the
1671 header structure of a class tree. MEMBER-OR-CLASS is either an
1672 `ebrowse-ms' or `ebrowse-cs' structure depending on what is searched.
1673 ACCESSOR is an accessor function for the member list of a member
1674 if MEMBER-OR-CLASS is an `ebrowse-ms'.
1675 FILE is the file to search the member in.
1676 FILE is not taken out of STRUC here because the filename in STRUC
1677 may be nil in which case the filename of the class description is used.
1678 TAGS-FILE-NAME is the name of the BROWSE file from which the
1680 If VIEW is non-nil, view file else find the file.
1681 WHERE is either `other-window', `other-frame' or `this-window' and
1682 specifies where to find/view the result."
1684 (error "Sorry, no file information available for %s"
1685 (ebrowse-bs-name struc)))
1686 ;; Get the source file to view or find.
1687 (setf file (ebrowse-find-source-file file tags-file-name))
1688 ;; If current window is dedicated, use another frame.
1689 (when (window-dedicated-p (selected-window))
1690 (setf where 'other-window))
1692 (setf ebrowse-temp-position-to-view struc
1693 ebrowse-temp-info-to-view info)
1694 (unless (boundp 'view-mode-hook)
1695 (setq view-mode-hook nil))
1696 (push 'ebrowse-find-pattern view-mode-hook)
1698 (other-window (ebrowse-view-file-other-window file))
1699 (other-frame (ebrowse-view-file-other-frame file))
1700 (t (view-file file))))
1703 (other-window (find-file-other-window file))
1704 (other-frame (find-file-other-frame file))
1705 (t (find-file file)))
1706 (ebrowse-find-pattern struc info))))
1709 (defun ebrowse-symbol-regexp (name)
1710 "Generate a suitable regular expression for a member or class NAME.
1711 This is `regexp-quote' for most symbols, except for operator names
1712 which may contain whitespace. For these symbols, replace white
1713 space in the symbol name (generated by BROWSE) with a regular
1714 expression matching any number of whitespace characters."
1715 (loop with regexp = (regexp-quote name)
1717 finally return regexp
1718 while (string-match "[ \t]+" regexp start)
1719 do (setq regexp (concat (substring regexp 0 (match-beginning 0))
1721 (substring regexp (match-end 0)))
1722 start (+ (match-beginning 0) 5))))
1725 (defun ebrowse-class-declaration-regexp (name)
1726 "Construct a regexp for a declaration of class NAME."
1727 (concat "^[ \t]*\\(template[ \t\n]*<.*>\\)?"
1728 "[ \t\n]*\\(class\\|struct\\|union\\).*\\S_"
1729 (ebrowse-symbol-regexp name)
1733 (defun ebrowse-variable-declaration-regexp (name)
1734 "Construct a regexp for matching a variable NAME."
1735 (concat "\\S_" (ebrowse-symbol-regexp name) "\\S_"))
1738 (defun ebrowse-function-declaration/definition-regexp (name)
1739 "Construct a regexp for matching a function NAME."
1740 (concat "^[a-zA-Z0-9_:*&<>, \t]*\\S_"
1741 (ebrowse-symbol-regexp name)
1745 (defun ebrowse-pp-define-regexp (name)
1746 "Construct a regexp matching a define of NAME."
1747 (concat "^[ \t]*#[ \t]*define[ \t]+" (regexp-quote name)))
1750 (defun* ebrowse-find-pattern (&optional position info &aux viewing)
1753 This is a kluge: Ebrowse allows you to find or view a file containing
1754 a pattern. To be able to do a search in a viewed buffer,
1755 `view-mode-hook' is temporarily set to this function;
1756 `ebrowse-temp-position-to-view' holds what to search for.
1758 INFO is a list (TREE-HEADER TREE-OR-MEMBER MEMBER-LIST)."
1760 (pop view-mode-hook)
1762 position ebrowse-temp-position-to-view
1763 info ebrowse-temp-info-to-view))
1765 (let* ((pattern (ebrowse-bs-pattern position))
1766 (start (ebrowse-bs-point position))
1769 (destructuring-bind (header class-or-member member-list) info
1770 ;; If no pattern is specified, construct one from the member name.
1771 (when (stringp pattern)
1772 (setq pattern (concat "^.*" (regexp-quote pattern))))
1773 ;; Construct a regular expression if none given.
1775 (typecase class-or-member
1778 ((ebrowse-ts-member-variables
1779 ebrowse-ts-static-variables
1781 (setf pattern (ebrowse-variable-declaration-regexp
1782 (ebrowse-bs-name position))))
1784 (if (ebrowse-define-p class-or-member)
1785 (setf pattern (ebrowse-pp-define-regexp (ebrowse-bs-name position)))
1786 (setf pattern (ebrowse-function-declaration/definition-regexp
1787 (ebrowse-bs-name position)))))))
1789 (setf pattern (ebrowse-class-declaration-regexp
1790 (ebrowse-bs-name position))))))
1791 ;; Begin searching some OFFSET from the original point where the
1792 ;; regular expression was found by the parse, and step forward.
1793 ;; When there is no regular expression in the database and a
1794 ;; member definition/declaration was not seen by the parser,
1796 (when (and (boundp 'ebrowse-debug)
1797 (symbol-value 'ebrowse-debug))
1798 (y-or-n-p (format "start = %d" start))
1801 (loop do (goto-char (max (point-min) (- start offset)))
1802 when (re-search-forward pattern (+ start offset) t) return t
1804 do (incf offset offset)))
1807 (run-hooks 'ebrowse-view/find-hook))
1808 ((numberp (ebrowse-bs-pattern position))
1810 (if ebrowse-not-found-hook
1811 (run-hooks 'ebrowse-not-found-hook)
1812 (message "Not found")
1815 (if ebrowse-not-found-hook
1816 (run-hooks 'ebrowse-not-found-hook)
1818 (error "Not found"))
1819 (message "Not found")
1823 ;;; Drawing the tree
1825 (defun ebrowse-redraw-tree (&optional quietly)
1826 "Redisplay the complete tree.
1827 QUIETLY non-nil means don't display progress messages."
1829 (or quietly (message "Displaying..."))
1833 (ebrowse-draw-tree-fn)))
1834 (ebrowse-update-tree-buffer-mode-line)
1835 (or quietly (message nil)))
1838 (defun ebrowse-set-mark-props (start end tree)
1839 "Set text properties for class marker signs between START and END.
1840 TREE denotes the class shown."
1841 (add-text-properties
1843 `(mouse-face highlight ebrowse-what mark ebrowse-tree ,tree
1844 help-echo "double-mouse-1: mark/unmark"))
1845 (ebrowse-set-face start end 'ebrowse-tree-mark))
1848 (defun* ebrowse-draw-tree-fn (&aux stack1 stack2 start)
1849 "Display a single class and recursively its subclasses.
1850 This function may look weird, but this is faster than recursion."
1851 (setq stack1 (make-list (length ebrowse--tree) 0)
1852 stack2 (copy-sequence ebrowse--tree))
1854 as level = (pop stack1)
1855 as tree = (pop stack2)
1856 as class = (ebrowse-ts-class tree) do
1857 (let ((start-of-line (point))
1858 start-of-class-name end-of-class-name)
1860 (insert (if (ebrowse-ts-mark tree) ">" " "))
1862 ;; Indent and insert class name
1863 (indent-to (+ (* level ebrowse--indentation)
1864 ebrowse-tree-left-margin))
1865 (setq start (point))
1866 (insert (ebrowse-qualified-class-name class))
1868 ;; If template class, add <>
1869 (when (ebrowse-template-p class)
1871 (ebrowse-set-face start (point) (if (zerop level)
1874 (setf start-of-class-name start
1875 end-of-class-name (point))
1876 ;; If filenames are to be displayed...
1877 (when ebrowse--show-file-names-flag
1878 (indent-to ebrowse-source-file-column)
1879 (setq start (point))
1881 (or (ebrowse-cs-file class)
1884 (ebrowse-set-face start (point) 'ebrowse-file-name))
1885 (ebrowse-set-mark-props start-of-line (1+ start-of-line) tree)
1886 (add-text-properties
1887 start-of-class-name end-of-class-name
1888 `(mouse-face highlight ebrowse-what class-name
1890 help-echo "double-mouse-1: (un)expand tree; mouse-2: member functions, mouse-3: menu"))
1892 ;; Push subclasses, if any.
1893 (when (ebrowse-ts-subclasses tree)
1895 (nconc (copy-sequence (ebrowse-ts-subclasses tree)) stack2)
1897 (nconc (make-list (length (ebrowse-ts-subclasses tree))
1898 (1+ level)) stack1)))))
1902 ;;; Expanding/ collapsing tree branches
1904 (defun ebrowse-expand-branch (arg)
1905 "Expand a sub-tree that has been previously collapsed.
1906 With prefix ARG, expand all sub-trees."
1909 (ebrowse-expand-all arg)
1910 (ebrowse-collapse-fn nil)))
1913 (defun ebrowse-collapse-branch (arg)
1914 "Fold (do no longer display) the subclasses of the current class.
1915 \(The class cursor is on.) With prefix ARG, fold all trees in the buffer."
1918 (ebrowse-expand-all (not arg))
1919 (ebrowse-collapse-fn t)))
1922 (defun ebrowse-expand-all (collapse)
1923 "Expand or fold all trees in the buffer.
1924 COLLAPSE non-nil means fold them."
1926 (let ((line-end (if collapse "^\n" "^\r"))
1927 (insertion (if collapse "\r" "\n")))
1930 (goto-char (point-min))
1931 (while (not (progn (skip-chars-forward line-end) (eobp)))
1932 (when (or (not collapse)
1937 (skip-chars-forward "\n ")))))))
1940 (defun ebrowse-unhide-base-classes ()
1941 "Unhide the line the cursor is on and all base classes."
1944 (let (indent last-indent)
1945 (skip-chars-backward "^\r\n")
1946 (when (not (looking-at "[\r\n][^ \t]"))
1947 (skip-chars-forward "\r\n \t")
1948 (while (and (or (null last-indent) ;first time
1949 (> indent 1)) ;not root class
1950 (re-search-backward "[\r\n][ \t]*" nil t))
1951 (setf indent (- (match-end 0)
1952 (match-beginning 0)))
1953 (when (or (null last-indent)
1954 (< indent last-indent))
1955 (setf last-indent indent)
1956 (when (looking-at "\r")
1959 (backward-char 1)))))))
1962 (defun ebrowse-hide-line (collapse)
1963 "Hide/show a single line in the tree.
1964 COLLAPSE non-nil means hide."
1967 (skip-chars-forward "^\r\n")
1969 (insert (if collapse 13 10)))))
1972 (defun ebrowse-collapse-fn (collapse)
1973 "Collapse or expand a branch of the tree.
1974 COLLAPSE non-nil means collapse the branch."
1978 (skip-chars-forward "> \t")
1979 (let ((indentation (current-column)))
1980 (while (and (not (eobp))
1982 (skip-chars-forward "^\r\n")
1983 (goto-char (1+ (point)))
1984 (skip-chars-forward "> \t")
1985 (> (current-column) indentation)))
1986 (ebrowse-hide-line collapse)
1987 (skip-chars-forward "^\r\n")
1988 (goto-char (1+ (point))))))))
1991 ;;; Electric tree selection
1993 (defvar ebrowse-electric-list-mode-map ()
1994 "Keymap used in electric Ebrowse buffer list window.")
1997 (unless ebrowse-electric-list-mode-map
1998 (let ((map (make-keymap))
1999 (submap (make-keymap)))
2000 (setq ebrowse-electric-list-mode-map map)
2001 (fillarray (car (cdr map)) 'ebrowse-electric-list-undefined)
2002 (fillarray (car (cdr submap)) 'ebrowse-electric-list-undefined)
2003 (define-key map "\e" submap)
2004 (define-key map "\C-z" 'suspend-emacs)
2005 (define-key map "\C-h" 'Helper-help)
2006 (define-key map "?" 'Helper-describe-bindings)
2007 (define-key map "\C-c" nil)
2008 (define-key map "\C-c\C-c" 'ebrowse-electric-list-quit)
2009 (define-key map "q" 'ebrowse-electric-list-quit)
2010 (define-key map " " 'ebrowse-electric-list-select)
2011 (define-key map "\C-l" 'recenter)
2012 (define-key map "\C-u" 'universal-argument)
2013 (define-key map "\C-p" 'previous-line)
2014 (define-key map "\C-n" 'next-line)
2015 (define-key map "p" 'previous-line)
2016 (define-key map "n" 'next-line)
2017 (define-key map "v" 'ebrowse-electric-view-buffer)
2018 (define-key map "\C-v" 'scroll-up)
2019 (define-key map "\ev" 'scroll-down)
2020 (define-key map "\e\C-v" 'scroll-other-window)
2021 (define-key map "\e>" 'end-of-buffer)
2022 (define-key map "\e<" 'beginning-of-buffer)
2023 (define-key map "\e>" 'end-of-buffer)))
2025 (put 'ebrowse-electric-list-mode 'mode-class 'special)
2026 (put 'ebrowse-electric-list-undefined 'suppress-keymap t)
2029 (defun ebrowse-electric-list-mode ()
2030 "Mode for electric tree list mode."
2031 (kill-all-local-variables)
2032 (use-local-map ebrowse-electric-list-mode-map)
2033 (setq mode-name "Electric Position Menu"
2034 mode-line-buffer-identification "Electric Tree Menu")
2035 (when (memq 'mode-name mode-line-format)
2036 (setq mode-line-format (copy-sequence mode-line-format))
2037 (setcar (memq 'mode-name mode-line-format) "Tree Buffers"))
2038 (make-local-variable 'Helper-return-blurb)
2039 (setq Helper-return-blurb "return to buffer editing"
2042 major-mode 'ebrowse-electric-list-mode)
2043 (run-mode-hooks 'ebrowse-electric-list-mode-hook))
2046 (defun ebrowse-list-tree-buffers ()
2047 "Display a list of all tree buffers."
2048 (set-buffer (get-buffer-create "*Tree Buffers*"))
2049 (setq buffer-read-only nil)
2051 (insert "Tree\n" "----\n")
2052 (dolist (buffer (ebrowse-known-class-trees-buffer-list))
2053 (insert (buffer-name buffer) "\n"))
2054 (setq buffer-read-only t))
2058 (defun ebrowse-electric-choose-tree ()
2059 "Return a buffer containing a tree or nil if no tree found or canceled."
2061 (unless (car (ebrowse-known-class-trees-buffer-list))
2062 (error "No tree buffers"))
2063 (let (select buffer window)
2064 (save-window-excursion
2065 (save-window-excursion (ebrowse-list-tree-buffers))
2066 (setq window (Electric-pop-up-window "*Tree Buffers*")
2067 buffer (window-buffer window))
2068 (shrink-window-if-larger-than-buffer window)
2072 (ebrowse-electric-list-mode)
2074 (catch 'ebrowse-electric-list-select
2075 (message "<<< Press Space to bury the list >>>")
2076 (let ((first (progn (goto-char (point-min))
2079 (last (progn (goto-char (point-max))
2084 (Electric-command-loop 'ebrowse-electric-list-select
2087 'ebrowse-electric-list-looper
2088 (cons first last))))))
2090 (bury-buffer buffer)
2094 (setq select (ebrowse-electric-get-buffer select)))
2095 (kill-buffer buffer)
2099 (defun ebrowse-electric-list-looper (state condition)
2100 "Prevent cursor from moving beyond the buffer end.
2101 Don't let it move into the title lines.
2102 See 'Electric-command-loop' for a description of STATE and CONDITION."
2103 (cond ((and condition
2104 (not (memq (car condition)
2105 '(buffer-read-only end-of-buffer
2106 beginning-of-buffer))))
2107 (signal (car condition) (cdr condition)))
2108 ((< (point) (car state))
2109 (goto-char (point-min))
2111 ((> (point) (cdr state))
2112 (goto-char (point-max))
2114 (if (pos-visible-in-window-p (point-max))
2118 (defun ebrowse-electric-list-undefined ()
2119 "Function called for keys that are undefined."
2121 (message "Type C-h for help, ? for commands, q to quit, Space to select.")
2125 (defun ebrowse-electric-list-quit ()
2126 "Discard the buffer list."
2128 (throw 'ebrowse-electric-list-select nil))
2131 (defun ebrowse-electric-list-select ()
2132 "Select a buffer from the buffer list."
2134 (throw 'ebrowse-electric-list-select (point)))
2137 (defun ebrowse-electric-get-buffer (point)
2138 "Get a buffer corresponding to the line POINT is in."
2139 (let ((index (- (count-lines (point-min) point) 2)))
2140 (nth index (ebrowse-known-class-trees-buffer-list))))
2143 ;;; View a buffer for a tree.
2145 (defun ebrowse-electric-view-buffer ()
2146 "View buffer point is on."
2148 (let ((buffer (ebrowse-electric-get-buffer (point))))
2150 (view-buffer buffer))
2152 (error "Buffer no longer exists")))))
2155 (defun ebrowse-choose-from-browser-buffers ()
2156 "Read a browser buffer name from the minibuffer and return that buffer."
2157 (let* ((buffers (ebrowse-known-class-trees-buffer-list)))
2159 (if (not (second buffers))
2161 (or (ebrowse-electric-choose-tree) (error "No tree buffer")))
2162 (let* ((insert-default-directory t)
2163 (file (read-file-name "Find tree: " nil nil t)))
2166 (find-buffer-visiting file)))))
2171 (unless ebrowse-member-mode-map
2172 (let ((map (make-keymap)))
2173 (setf ebrowse-member-mode-map map)
2174 (suppress-keymap map)
2176 (when (display-mouse-p)
2177 (define-key map [down-mouse-3] 'ebrowse-member-mouse-3)
2178 (define-key map [mouse-2] 'ebrowse-member-mouse-2))
2180 (let ((map1 (make-sparse-keymap)))
2181 (suppress-keymap map1 t)
2182 (define-key map "C" map1)
2183 (define-key map1 "b" 'ebrowse-switch-member-buffer-to-base-class)
2184 (define-key map1 "c" 'ebrowse-switch-member-buffer-to-any-class)
2185 (define-key map1 "d" 'ebrowse-switch-member-buffer-to-derived-class)
2186 (define-key map1 "n" 'ebrowse-switch-member-buffer-to-next-sibling-class)
2187 (define-key map1 "p" 'ebrowse-switch-member-buffer-to-previous-sibling-class))
2189 (let ((map1 (make-sparse-keymap)))
2190 (suppress-keymap map1 t)
2191 (define-key map "D" map1)
2192 (define-key map1 "a" 'ebrowse-toggle-member-attributes-display)
2193 (define-key map1 "b" 'ebrowse-toggle-base-class-display)
2194 (define-key map1 "f" 'ebrowse-freeze-member-buffer)
2195 (define-key map1 "l" 'ebrowse-toggle-long-short-display)
2196 (define-key map1 "r" 'ebrowse-toggle-regexp-display)
2197 (define-key map1 "w" 'ebrowse-set-member-buffer-column-width))
2199 (let ((map1 (make-sparse-keymap)))
2200 (suppress-keymap map1 t)
2201 (define-key map "F" map1)
2202 (let ((map2 (make-sparse-keymap)))
2203 (suppress-keymap map2 t)
2204 (define-key map1 "a" map2)
2205 (define-key map2 "i" 'ebrowse-toggle-private-member-filter)
2206 (define-key map2 "o" 'ebrowse-toggle-protected-member-filter)
2207 (define-key map2 "u" 'ebrowse-toggle-public-member-filter))
2208 (define-key map1 "c" 'ebrowse-toggle-const-member-filter)
2209 (define-key map1 "i" 'ebrowse-toggle-inline-member-filter)
2210 (define-key map1 "p" 'ebrowse-toggle-pure-member-filter)
2211 (define-key map1 "r" 'ebrowse-remove-all-member-filters)
2212 (define-key map1 "v" 'ebrowse-toggle-virtual-member-filter))
2214 (let ((map1 (make-sparse-keymap)))
2215 (suppress-keymap map1 t)
2216 (define-key map "L" map1)
2217 (define-key map1 "d" 'ebrowse-display-friends-member-list)
2218 (define-key map1 "f" 'ebrowse-display-function-member-list)
2219 (define-key map1 "F" 'ebrowse-display-static-functions-member-list)
2220 (define-key map1 "n" 'ebrowse-display-next-member-list)
2221 (define-key map1 "p" 'ebrowse-display-previous-member-list)
2222 (define-key map1 "t" 'ebrowse-display-types-member-list)
2223 (define-key map1 "v" 'ebrowse-display-variables-member-list)
2224 (define-key map1 "V" 'ebrowse-display-static-variables-member-list))
2226 (let ((map1 (make-sparse-keymap)))
2227 (suppress-keymap map1 t)
2228 (define-key map "G" map1)
2229 (define-key map1 "m" 'ebrowse-goto-visible-member/all-member-lists)
2230 (define-key map1 "n" 'ebrowse-repeat-member-search)
2231 (define-key map1 "v" 'ebrowse-goto-visible-member))
2233 (define-key map "f" 'ebrowse-find-member-declaration)
2234 (define-key map "m" 'ebrowse-switch-to-next-member-buffer)
2235 (define-key map "q" 'bury-buffer)
2236 (define-key map "t" 'ebrowse-show-displayed-class-in-tree)
2237 (define-key map "v" 'ebrowse-view-member-declaration)
2238 (define-key map " " 'ebrowse-view-member-definition)
2239 (define-key map "?" 'describe-mode)
2240 (define-key map "\C-i" 'ebrowse-pop-from-member-to-tree-buffer)
2241 (define-key map "\C-l" 'ebrowse-redisplay-member-buffer)
2242 (define-key map "\C-m" 'ebrowse-find-member-definition)))
2249 (defun ebrowse-member-mode ()
2250 "Major mode for Ebrowse member buffers.
2252 \\{ebrowse-member-mode-map}"
2253 (kill-all-local-variables)
2254 (use-local-map ebrowse-member-mode-map)
2255 (setq major-mode 'ebrowse-member-mode)
2256 (mapcar 'make-local-variable
2257 '(ebrowse--decl-column ;display column
2258 ebrowse--n-columns ;number of short columns
2259 ebrowse--column-width ;width of columns above
2260 ebrowse--show-inherited-flag ;include inherited members?
2261 ebrowse--filters ;public, protected, private
2262 ebrowse--accessor ;vars, functions, friends
2263 ebrowse--displayed-class ;class displayed
2264 ebrowse--long-display-flag ;display with regexps?
2265 ebrowse--source-regexp-flag ;show source regexp?
2266 ebrowse--attributes-flag ;show `virtual' and `inline'
2267 ebrowse--member-list ;list of members displayed
2268 ebrowse--tree ;the class tree
2269 ebrowse--member-mode-strings ;part of mode line
2270 ebrowse--tags-file-name ;
2272 ebrowse--tree-obarray
2273 ebrowse--virtual-display-flag
2274 ebrowse--inline-display-flag
2275 ebrowse--const-display-flag
2276 ebrowse--pure-display-flag
2277 ebrowse--frozen-flag)) ;buffer not automagically reused
2278 (setq mode-name "Ebrowse-Members"
2279 mode-line-buffer-identification
2280 (propertized-buffer-identification "C++ Members")
2282 ebrowse--long-display-flag nil
2283 ebrowse--attributes-flag t
2284 ebrowse--show-inherited-flag t
2285 ebrowse--source-regexp-flag nil
2286 ebrowse--filters [0 1 2]
2287 ebrowse--decl-column ebrowse-default-declaration-column
2288 ebrowse--column-width ebrowse-default-column-width
2289 ebrowse--virtual-display-flag nil
2290 ebrowse--inline-display-flag nil
2291 ebrowse--const-display-flag nil
2292 ebrowse--pure-display-flag nil)
2293 (modify-syntax-entry ?_ (char-to-string (char-syntax ?a)))
2294 (run-mode-hooks 'ebrowse-member-mode-hook))
2298 ;;; Member mode mode line
2300 (defsubst ebrowse-class-name-displayed-in-member-buffer ()
2301 "Return the name of the class displayed in the member buffer."
2302 (ebrowse-cs-name (ebrowse-ts-class ebrowse--displayed-class)))
2305 (defsubst ebrowse-member-list-name ()
2306 "Return a string describing what is displayed in the member buffer."
2307 (get ebrowse--accessor (if (ebrowse-globals-tree-p ebrowse--displayed-class)
2308 'ebrowse-global-title
2312 (defun ebrowse-update-member-buffer-mode-line ()
2313 "Update the mode line of member buffers."
2314 (let* ((name (when ebrowse--frozen-flag
2315 (concat (ebrowse-class-name-displayed-in-member-buffer)
2317 (ident (concat name (ebrowse-member-list-name))))
2318 (setq mode-line-buffer-identification
2319 (propertized-buffer-identification ident))
2320 (ebrowse-rename-buffer (if name ident ebrowse-member-buffer-name))
2321 (force-mode-line-update)))
2324 ;;; Misc member buffer commands
2326 (defun ebrowse-freeze-member-buffer ()
2327 "Toggle frozen status of current buffer."
2329 (setq ebrowse--frozen-flag (not ebrowse--frozen-flag))
2330 (ebrowse-redisplay-member-buffer))
2333 (defun ebrowse-show-displayed-class-in-tree (arg)
2334 "Show the currently displayed class in the tree window.
2335 With prefix ARG, switch to the tree buffer else pop to it."
2337 (let ((class-name (ebrowse-class-name-displayed-in-member-buffer)))
2338 (when (ebrowse-pop-from-member-to-tree-buffer arg)
2339 (ebrowse-read-class-name-and-go class-name))))
2342 (defun ebrowse-set-member-buffer-column-width ()
2343 "Set the column width of the member display.
2344 The new width is read from the minibuffer."
2346 (let ((width (string-to-number
2347 (read-from-minibuffer
2348 (concat "Column width ("
2349 (int-to-string (if ebrowse--long-display-flag
2350 ebrowse--decl-column
2351 ebrowse--column-width))
2354 (if ebrowse--long-display-flag
2355 (setq ebrowse--decl-column width)
2356 (setq ebrowse--column-width width))
2357 (ebrowse-redisplay-member-buffer))))
2360 (defun ebrowse-pop-from-member-to-tree-buffer (arg)
2361 "Pop from a member buffer to the matching tree buffer.
2362 Switch to the buffer if prefix ARG. If no tree buffer exists,
2365 (let ((buf (or (get-buffer (ebrowse-frozen-tree-buffer-name
2366 ebrowse--tags-file-name))
2367 (get-buffer ebrowse-tree-buffer-name)
2368 (ebrowse-create-tree-buffer ebrowse--tree
2369 ebrowse--tags-file-name
2371 ebrowse--tree-obarray
2374 (funcall (if arg 'switch-to-buffer 'pop-to-buffer) buf))
2379 ;;; Switching between member lists
2381 (defun ebrowse-display-member-list-for-accessor (accessor)
2382 "Switch the member buffer to display the member list for ACCESSOR."
2383 (setf ebrowse--accessor accessor
2384 ebrowse--member-list (funcall accessor ebrowse--displayed-class))
2385 (ebrowse-redisplay-member-buffer))
2388 (defun ebrowse-cyclic-display-next/previous-member-list (incr)
2389 "Switch buffer to INCR'th next/previous list of members."
2390 (let ((index (ebrowse-position ebrowse--accessor
2391 ebrowse-member-list-accessors)))
2392 (setf ebrowse--accessor
2395 ebrowse-member-list-accessors)
2396 (first ebrowse-member-list-accessors)))
2398 (or (and (>= (decf index) 0)
2400 ebrowse-member-list-accessors))
2401 (first (last ebrowse-member-list-accessors))))))
2402 (ebrowse-display-member-list-for-accessor ebrowse--accessor)))
2405 (defun ebrowse-display-next-member-list ()
2406 "Switch buffer to next member list."
2408 (ebrowse-cyclic-display-next/previous-member-list 1))
2411 (defun ebrowse-display-previous-member-list ()
2412 "Switch buffer to previous member list."
2414 (ebrowse-cyclic-display-next/previous-member-list -1))
2417 (defun ebrowse-display-function-member-list ()
2418 "Display the list of member functions."
2420 (ebrowse-display-member-list-for-accessor 'ebrowse-ts-member-functions))
2423 (defun ebrowse-display-variables-member-list ()
2424 "Display the list of member variables."
2426 (ebrowse-display-member-list-for-accessor 'ebrowse-ts-member-variables))
2429 (defun ebrowse-display-static-variables-member-list ()
2430 "Display the list of static member variables."
2432 (ebrowse-display-member-list-for-accessor 'ebrowse-ts-static-variables))
2435 (defun ebrowse-display-static-functions-member-list ()
2436 "Display the list of static member functions."
2438 (ebrowse-display-member-list-for-accessor 'ebrowse-ts-static-functions))
2441 (defun ebrowse-display-friends-member-list ()
2442 "Display the list of friends."
2444 (ebrowse-display-member-list-for-accessor 'ebrowse-ts-friends))
2447 (defun ebrowse-display-types-member-list ()
2448 "Display the list of types."
2450 (ebrowse-display-member-list-for-accessor 'ebrowse-ts-types))
2454 ;;; Filters and other display attributes
2456 (defun ebrowse-toggle-member-attributes-display ()
2457 "Toggle display of `virtual', `inline', `const' etc."
2459 (setq ebrowse--attributes-flag (not ebrowse--attributes-flag))
2460 (ebrowse-redisplay-member-buffer))
2463 (defun ebrowse-toggle-base-class-display ()
2464 "Toggle the display of members inherited from base classes."
2466 (setf ebrowse--show-inherited-flag (not ebrowse--show-inherited-flag))
2467 (ebrowse-redisplay-member-buffer))
2470 (defun ebrowse-toggle-pure-member-filter ()
2471 "Toggle display of pure virtual members."
2473 (setf ebrowse--pure-display-flag (not ebrowse--pure-display-flag))
2474 (ebrowse-redisplay-member-buffer))
2477 (defun ebrowse-toggle-const-member-filter ()
2478 "Toggle display of const members."
2480 (setf ebrowse--const-display-flag (not ebrowse--const-display-flag))
2481 (ebrowse-redisplay-member-buffer))
2484 (defun ebrowse-toggle-inline-member-filter ()
2485 "Toggle display of inline members."
2487 (setf ebrowse--inline-display-flag (not ebrowse--inline-display-flag))
2488 (ebrowse-redisplay-member-buffer))
2491 (defun ebrowse-toggle-virtual-member-filter ()
2492 "Toggle display of virtual members."
2494 (setf ebrowse--virtual-display-flag (not ebrowse--virtual-display-flag))
2495 (ebrowse-redisplay-member-buffer))
2498 (defun ebrowse-remove-all-member-filters ()
2499 "Remove all filters."
2502 (aset ebrowse--filters i i))
2503 (setq ebrowse--pure-display-flag nil
2504 ebrowse--const-display-flag nil
2505 ebrowse--virtual-display-flag nil
2506 ebrowse--inline-display-flag nil)
2507 (ebrowse-redisplay-member-buffer))
2510 (defun ebrowse-toggle-public-member-filter ()
2511 "Toggle visibility of public members."
2513 (ebrowse-set-member-access-visibility 0)
2514 (ebrowse-redisplay-member-buffer))
2517 (defun ebrowse-toggle-protected-member-filter ()
2518 "Toggle visibility of protected members."
2520 (ebrowse-set-member-access-visibility 1)
2521 (ebrowse-redisplay-member-buffer))
2524 (defun ebrowse-toggle-private-member-filter ()
2525 "Toggle visibility of private members."
2527 (ebrowse-set-member-access-visibility 2)
2528 (ebrowse-redisplay-member-buffer))
2531 (defun ebrowse-set-member-access-visibility (vis)
2532 (setf (aref ebrowse--filters vis)
2533 (if (aref ebrowse--filters vis) nil vis)))
2536 (defun ebrowse-toggle-long-short-display ()
2537 "Toggle between long and short display form of member buffers."
2539 (setf ebrowse--long-display-flag (not ebrowse--long-display-flag))
2540 (ebrowse-redisplay-member-buffer))
2543 (defun ebrowse-toggle-regexp-display ()
2544 "Toggle declaration/definition regular expression display.
2545 Used in member buffers showing the long display form."
2547 (setf ebrowse--source-regexp-flag (not ebrowse--source-regexp-flag))
2548 (ebrowse-redisplay-member-buffer))
2552 ;;; Viewing/finding members
2554 (defun ebrowse-find-member-definition (&optional prefix)
2555 "Find the file containing a member definition.
2556 With PREFIX 4. find file in another window, with prefix 5
2557 find file in another frame."
2559 (ebrowse-view/find-member-declaration/definition prefix nil t))
2562 (defun ebrowse-view-member-definition (prefix)
2563 "View the file containing a member definition.
2564 With PREFIX 4. find file in another window, with prefix 5
2565 find file in another frame."
2567 (ebrowse-view/find-member-declaration/definition prefix t t))
2570 (defun ebrowse-find-member-declaration (prefix)
2571 "Find the file containing a member's declaration.
2572 With PREFIX 4. find file in another window, with prefix 5
2573 find file in another frame."
2575 (ebrowse-view/find-member-declaration/definition prefix nil))
2578 (defun ebrowse-view-member-declaration (prefix)
2579 "View the file containing a member's declaration.
2580 With PREFIX 4. find file in another window, with prefix 5
2581 find file in another frame."
2583 (ebrowse-view/find-member-declaration/definition prefix t))
2586 (defun* ebrowse-view/find-member-declaration/definition
2587 (prefix view &optional definition info header tags-file-name)
2588 "Find or view a member declaration or definition.
2589 With PREFIX 4. find file in another window, with prefix 5
2590 find file in another frame.
2591 DEFINITION non-nil means find the definition, otherwise find the
2593 INFO is a list (TREE ACCESSOR MEMBER) describing the member to
2595 TAGS-FILE-NAME is the file name of the BROWSE file."
2597 (setq header ebrowse--header))
2598 (unless tags-file-name
2599 (setq tags-file-name ebrowse--tags-file-name))
2600 (let (tree member accessor file on-class
2601 (where (if (= prefix 4) 'other-window
2602 (if (= prefix 5) 'other-frame 'this-window))))
2603 ;; If not given as parameters, get the necessary information
2604 ;; out of the member buffer.
2606 (setq tree (first info)
2607 accessor (second info)
2608 member (third info))
2609 (multiple-value-setq (tree member on-class)
2610 (ebrowse-member-info-from-point))
2611 (setq accessor ebrowse--accessor))
2612 ;; View/find class if on a line containing a class name.
2614 (return-from ebrowse-view/find-member-declaration/definition
2615 (ebrowse-view/find-file-and-search-pattern
2616 (ebrowse-ts-class tree)
2617 (list ebrowse--header (ebrowse-ts-class tree) nil)
2618 (ebrowse-cs-file (ebrowse-ts-class tree))
2619 tags-file-name view where)))
2620 ;; For some member lists, it doesn't make sense to search for
2621 ;; a definition. If this is requested, silently search for the
2623 (when (and definition
2624 (eq accessor 'ebrowse-ts-member-variables))
2625 (setq definition nil))
2626 ;; Construct a suitable `browse' struct for definitions.
2628 (setf member (make-ebrowse-ms
2629 :name (ebrowse-ms-name member)
2630 :file (ebrowse-ms-definition-file member)
2631 :pattern (ebrowse-ms-definition-pattern
2633 :flags (ebrowse-ms-flags member)
2634 :point (ebrowse-ms-definition-point
2636 ;; When no file information in member, use that of the class
2637 (setf file (or (ebrowse-ms-file member)
2639 (ebrowse-cs-source-file (ebrowse-ts-class tree))
2640 (ebrowse-cs-file (ebrowse-ts-class tree)))))
2641 ;; When we have no regular expressions in the database the only
2642 ;; indication that the parser hasn't seen a definition/declaration
2643 ;; is that the search start point will be zero.
2644 (if (or (null file) (zerop (ebrowse-ms-point member)))
2645 (if (y-or-n-p (concat "No information about "
2646 (if definition "definition" "declaration")
2648 (if definition "declaration" "definition")
2650 (ebrowse-ms-name member)
2654 ;; Recurse with new info.
2655 (ebrowse-view/find-member-declaration/definition
2656 prefix view (not definition) info header tags-file-name))
2657 (error "Search canceled"))
2659 (ebrowse-view/find-file-and-search-pattern
2660 (make-ebrowse-bs :name (ebrowse-ms-name member)
2661 :pattern (ebrowse-ms-pattern member)
2662 :file (ebrowse-ms-file member)
2663 :flags (ebrowse-ms-flags member)
2664 :point (ebrowse-ms-point member))
2665 (list header member accessor)
2673 ;;; Drawing the member buffer
2675 (defun ebrowse-redisplay-member-buffer ()
2676 "Force buffer redisplay."
2678 (let ((display-fn (if ebrowse--long-display-flag
2679 'ebrowse-draw-member-long-fn
2680 'ebrowse-draw-member-short-fn)))
2684 (ebrowse-draw-member-buffer-class-line)
2685 (funcall display-fn ebrowse--member-list ebrowse--displayed-class)
2686 ;; Show inherited members if corresponding switch is on
2687 (when ebrowse--show-inherited-flag
2688 (dolist (super (ebrowse-base-classes ebrowse--displayed-class))
2689 (goto-char (point-max))
2690 (insert (if (bolp) "\n\n" "\n"))
2691 (ebrowse-draw-member-buffer-class-line super)
2692 (funcall display-fn (funcall ebrowse--accessor super) super)))
2693 (ebrowse-update-member-buffer-mode-line))))
2696 (defun ebrowse-draw-member-buffer-class-line (&optional class)
2697 "Display the title line for a class section in the member buffer.
2698 CLASS non-nil means display that class' title. Otherwise use
2699 the class cursor is on."
2700 (let ((start (point))
2701 (tree (or class ebrowse--displayed-class))
2705 (setq class-name-start (point))
2706 (insert (ebrowse-qualified-class-name (ebrowse-ts-class tree)))
2707 (when (ebrowse-template-p (ebrowse-ts-class tree))
2709 (setq class-name-end (point))
2711 (ebrowse-set-face start (point) 'ebrowse-member-class)
2712 (add-text-properties
2713 class-name-start class-name-end
2714 '(ebrowse-what class-name
2715 mouse-face highlight
2716 help-echo "mouse-3: menu"))
2717 (put-text-property start class-name-end 'ebrowse-tree tree)))
2720 (defun ebrowse-display-member-buffer (list &optional stand-alone class)
2721 "Start point for member buffer creation.
2722 LIST is the member list to display. STAND-ALONE non-nil
2723 means the member buffer is standalone. CLASS is its class."
2724 (let* ((classes ebrowse--tree-obarray)
2725 (tree ebrowse--tree)
2726 (tags-file-name ebrowse--tags-file-name)
2727 (header ebrowse--header)
2728 temp-buffer-setup-hook
2729 (temp-buffer (get-buffer ebrowse-member-buffer-name)))
2730 ;; Get the class description from the name the cursor
2731 ;; is on if not specified as an argument.
2733 (setq class (ebrowse-tree-at-point)))
2734 (with-output-to-temp-buffer ebrowse-member-buffer-name
2736 (set-buffer standard-output)
2737 ;; If new buffer, set the mode and initial values of locals
2739 (ebrowse-member-mode))
2740 ;; Set local variables
2741 (setq ebrowse--member-list (funcall list class)
2742 ebrowse--displayed-class class
2743 ebrowse--accessor list
2744 ebrowse--tree-obarray classes
2745 ebrowse--frozen-flag stand-alone
2746 ebrowse--tags-file-name tags-file-name
2747 ebrowse--header header
2750 (ebrowse-redisplay-member-buffer)
2751 (current-buffer)))))
2754 (defun ebrowse-member-display-p (member)
2755 "Return t if MEMBER must be displayed under the current filter settings."
2756 (if (and (aref ebrowse--filters (ebrowse-ms-visibility member))
2757 (or (null ebrowse--const-display-flag)
2758 (ebrowse-const-p member))
2759 (or (null ebrowse--inline-display-flag)
2760 (ebrowse-inline-p member))
2761 (or (null ebrowse--pure-display-flag)
2762 (ebrowse-bs-p member))
2763 (or (null ebrowse--virtual-display-flag)
2764 (ebrowse-virtual-p member)))
2768 (defun ebrowse-draw-member-attributes (member)
2769 "Insert a string for the attributes of MEMBER."
2770 (insert (if (ebrowse-template-p member) "T" "-")
2771 (if (ebrowse-extern-c-p member) "C" "-")
2772 (if (ebrowse-virtual-p member) "v" "-")
2773 (if (ebrowse-inline-p member) "i" "-")
2774 (if (ebrowse-const-p member) "c" "-")
2775 (if (ebrowse-pure-virtual-p member) "0" "-")
2776 (if (ebrowse-mutable-p member) "m" "-")
2777 (if (ebrowse-explicit-p member) "e" "-")
2778 (if (ebrowse-throw-list-p member) "t" "-")))
2781 (defun ebrowse-draw-member-regexp (member-struc)
2782 "Insert a string for the regular expression matching MEMBER-STRUC."
2783 (let ((pattern (if ebrowse--source-regexp-flag
2784 (ebrowse-ms-definition-pattern
2786 (ebrowse-ms-pattern member-struc))))
2787 (cond ((stringp pattern)
2788 (insert (ebrowse-trim-string pattern) "...\n")
2789 (beginning-of-line 0)
2790 (move-to-column (+ 4 ebrowse--decl-column))
2791 (while (re-search-forward "[ \t]+" nil t)
2792 (delete-region (match-beginning 0) (match-end 0))
2794 (beginning-of-line 2))
2796 (insert "[not recorded or unknown]\n")))))
2799 (defun ebrowse-draw-member-long-fn (member-list tree)
2800 "Display member buffer for MEMBER-LIST in long form.
2801 TREE is the class tree of MEMBER-LIST."
2802 (dolist (member-struc (mapcar 'ebrowse-member-display-p member-list))
2804 (let ((name (ebrowse-ms-name member-struc))
2806 ;; Insert member name truncated to the right length
2807 (insert (substring name
2810 (1- ebrowse--decl-column))))
2811 (add-text-properties
2813 `(mouse-face highlight ebrowse-what member-name
2814 ebrowse-member ,member-struc
2816 help-echo "mouse-2: view definition; mouse-3: menu"))
2817 ;; Display virtual, inline, and const status
2818 (setf start (point))
2819 (indent-to ebrowse--decl-column)
2820 (put-text-property start (point) 'mouse-face nil)
2821 (when ebrowse--attributes-flag
2822 (let ((start (point)))
2824 (ebrowse-draw-member-attributes member-struc)
2826 (ebrowse-set-face start (point)
2827 'ebrowse-member-attribute)))
2829 (ebrowse-draw-member-regexp member-struc))))
2831 (goto-char (point-min)))
2834 (defun ebrowse-draw-member-short-fn (member-list tree)
2835 "Display MEMBER-LIST in short form.
2836 TREE is the class tree in which the members are found."
2838 (column-width (+ ebrowse--column-width
2839 (if ebrowse--attributes-flag 12 0))))
2840 ;; Get the number of columns to draw.
2841 (setq ebrowse--n-columns
2842 (max 1 (/ (ebrowse-width-of-drawable-area) column-width)))
2843 (dolist (member (mapcar #'ebrowse-member-display-p member-list))
2845 (let ((name (ebrowse-ms-name member))
2847 (start-of-column (point))
2849 (indent-to (* i column-width))
2850 (put-text-property start-of-column (point) 'mouse-face nil)
2851 (setq start-of-entry (point))
2852 ;; Show various attributes
2853 (when ebrowse--attributes-flag
2855 (ebrowse-draw-member-attributes member)
2857 (ebrowse-set-face start-of-entry (point)
2858 'ebrowse-member-attribute))
2859 ;; insert member name truncated to column width
2860 (setq start-of-name (point))
2861 (insert (substring name 0
2863 (1- ebrowse--column-width))))
2864 ;; set text properties
2865 (add-text-properties
2866 start-of-name (point)
2867 `(ebrowse-what member-name
2868 ebrowse-member ,member
2869 mouse-face highlight
2871 help-echo "mouse-2: view definition; mouse-3: menu"))
2873 (when (>= i ebrowse--n-columns)
2878 (goto-char (point-min))))
2882 ;;; Killing members from tree
2884 (defun ebrowse-member-info-from-point ()
2885 "Ger information about the member at point.
2886 The result has the form (TREE MEMBER NULL-P). TREE is the tree
2887 we're in, MEMBER is the member we're on. NULL-P is t if MEMBER
2889 (let ((tree (or (get-text-property (point) 'ebrowse-tree)
2890 (error "No information at point")))
2891 (member (get-text-property (point) 'ebrowse-member)))
2892 (list tree member (null member))))
2896 ;;; Switching member buffer to display a selected member
2898 (defun ebrowse-goto-visible-member/all-member-lists (prefix)
2899 "Position cursor on a member read from the minibuffer.
2900 With PREFIX, search all members in the tree. Otherwise consider
2901 only members visible in the buffer."
2903 (ebrowse-ignoring-completion-case
2904 (let* ((completion-list (ebrowse-name/accessor-alist-for-class-members))
2905 (member (completing-read "Goto member: " completion-list nil t))
2906 (accessor (cdr (assoc member completion-list))))
2908 (error "`%s' not found" member))
2909 (unless (eq accessor ebrowse--accessor)
2910 (setf ebrowse--accessor accessor
2911 ebrowse--member-list (funcall accessor ebrowse--displayed-class))
2912 (ebrowse-redisplay-member-buffer))
2913 (ebrowse-move-point-to-member member))))
2916 (defun ebrowse-goto-visible-member (repeat)
2917 "Position point on a member.
2918 Read the member's name from the minibuffer. Consider only members
2919 visible in the member buffer.
2920 REPEAT non-nil means repeat the search that number of times."
2922 (ebrowse-ignoring-completion-case
2924 (let* ((completion-list (ebrowse-name/accessor-alist-for-visible-members))
2925 (member (completing-read "Goto member: " completion-list nil t)))
2926 (ebrowse-move-point-to-member member repeat))))
2930 ;;; Searching a member in the member buffer
2932 (defun ebrowse-repeat-member-search (repeat)
2933 "Repeat the last regular expression search.
2934 REPEAT, if specified, says repeat the search REPEAT times."
2936 (unless ebrowse--last-regexp
2937 (error "No regular expression remembered"))
2938 ;; Skip over word the point is on
2939 (skip-chars-forward "^ \t\n")
2940 ;; Search for regexp from point
2941 (if (re-search-forward ebrowse--last-regexp nil t repeat)
2943 (goto-char (match-beginning 0))
2944 (skip-chars-forward " \t\n"))
2945 ;; If not found above, repeat search from buffer start
2946 (goto-char (point-min))
2947 (if (re-search-forward ebrowse--last-regexp nil t)
2949 (goto-char (match-beginning 0))
2950 (skip-chars-forward " \t\n"))
2951 (error "Not found"))))
2954 (defun* ebrowse-move-point-to-member (name &optional count &aux member)
2955 "Set point on member NAME in the member buffer
2956 COUNT, if specified, says search the COUNT'th member with the same name."
2957 (goto-char (point-min))
2960 (substring name 0 (min (length name) (1- ebrowse--column-width)))
2961 ebrowse--last-regexp
2962 (concat "[ \t\n]" (regexp-quote member) "[ \n\t]"))
2963 (if (re-search-forward ebrowse--last-regexp nil t count)
2964 (goto-char (1+ (match-beginning 0)))
2965 (error "Not found")))
2969 ;;; Switching member buffer to another class.
2971 (defun ebrowse-switch-member-buffer-to-other-class (title compl-list)
2972 "Switch member buffer to a class read from the minibuffer.
2973 Use TITLE as minibuffer prompt.
2974 COMPL-LIST is a completion list to use."
2975 (let* ((initial (unless (second compl-list)
2976 (first (first compl-list))))
2977 (class (or (ebrowse-completing-read-value title compl-list initial)
2978 (error "Not found"))))
2979 (setf ebrowse--displayed-class class
2980 ebrowse--member-list (funcall ebrowse--accessor ebrowse--displayed-class))
2981 (ebrowse-redisplay-member-buffer)))
2984 (defun ebrowse-switch-member-buffer-to-any-class ()
2985 "Switch member buffer to a class read from the minibuffer."
2987 (ebrowse-switch-member-buffer-to-other-class
2988 "Goto class: " (ebrowse-tree-obarray-as-alist)))
2991 (defun ebrowse-switch-member-buffer-to-base-class (arg)
2992 "Switch buffer to ARG'th base class."
2994 (let ((supers (or (ebrowse-direct-base-classes ebrowse--displayed-class)
2995 (error "No base classes"))))
2996 (if (and arg (second supers))
2997 (let ((alist (loop for s in supers
2998 collect (cons (ebrowse-qualified-class-name
2999 (ebrowse-ts-class s))
3001 (ebrowse-switch-member-buffer-to-other-class
3002 "Goto base class: " alist))
3003 (setq ebrowse--displayed-class (first supers)
3004 ebrowse--member-list
3005 (funcall ebrowse--accessor ebrowse--displayed-class))
3006 (ebrowse-redisplay-member-buffer))))
3008 (defun ebrowse-switch-member-buffer-to-next-sibling-class (arg)
3009 "Move to ARG'th next sibling."
3011 (ebrowse-switch-member-buffer-to-sibling-class arg))
3014 (defun ebrowse-switch-member-buffer-to-previous-sibling-class (arg)
3015 "Move to ARG'th previous sibling."
3017 (ebrowse-switch-member-buffer-to-sibling-class (- arg)))
3020 (defun ebrowse-switch-member-buffer-to-sibling-class (inc)
3021 "Switch member display to nth sibling class.
3022 Prefix arg INC specifies which one."
3024 (let ((containing-list ebrowse--tree)
3026 (supers (ebrowse-direct-base-classes ebrowse--displayed-class)))
3027 (flet ((trees-alist (trees)
3028 (loop for tr in trees
3029 collect (cons (ebrowse-cs-name
3030 (ebrowse-ts-class tr)) tr))))
3032 (let ((tree (if (second supers)
3033 (ebrowse-completing-read-value
3034 "Relative to base class: "
3035 (trees-alist supers) nil)
3037 (unless tree (error "Not found"))
3038 (setq containing-list (ebrowse-ts-subclasses tree)))))
3039 (setq index (+ inc (ebrowse-position ebrowse--displayed-class
3041 (cond ((minusp index) (message "No previous class"))
3042 ((null (nth index containing-list)) (message "No next class")))
3043 (setq index (max 0 (min index (1- (length containing-list)))))
3044 (setq cls (nth index containing-list))
3045 (setf ebrowse--displayed-class cls
3046 ebrowse--member-list (funcall ebrowse--accessor cls))
3047 (ebrowse-redisplay-member-buffer)))
3050 (defun ebrowse-switch-member-buffer-to-derived-class (arg)
3051 "Switch member display to nth derived class.
3052 Prefix arg ARG says which class should be displayed. Default is
3053 the first derived class."
3055 (flet ((ebrowse-tree-obarray-as-alist ()
3056 (loop for s in (ebrowse-ts-subclasses
3057 ebrowse--displayed-class)
3058 collect (cons (ebrowse-cs-name
3059 (ebrowse-ts-class s)) s))))
3060 (let ((subs (or (ebrowse-ts-subclasses ebrowse--displayed-class)
3061 (error "No derived classes"))))
3062 (if (and arg (second subs))
3063 (ebrowse-switch-member-buffer-to-other-class
3064 "Goto derived class: " (ebrowse-tree-obarray-as-alist))
3065 (setq ebrowse--displayed-class (first subs)
3066 ebrowse--member-list
3067 (funcall ebrowse--accessor ebrowse--displayed-class))
3068 (ebrowse-redisplay-member-buffer)))))
3072 ;;; Member buffer mouse functions
3074 (defun ebrowse-displaying-functions ()
3075 (eq ebrowse--accessor 'ebrowse-ts-member-functions))
3076 (defun ebrowse-displaying-variables ()
3077 (eq ebrowse--accessor 'ebrowse-ts-member-variables))
3078 (defun ebrowse-displaying-static-functions ()
3080 (defun ebrowse-displaying-static-variables ()
3082 (defun ebrowse-displaying-types ()
3083 (eq ebrowse--accessor 'ebrowse-ts-types))
3084 (defun ebrowse-displaying-friends ()
3085 (eq ebrowse--accessor 'ebrowse-ts-friends))
3088 ebrowse-member-buffer-object-menu ebrowse-member-mode-map
3089 "Object menu for the member buffer itself."
3092 ["Functions" ebrowse-display-function-member-list
3093 :help "Show the list of member functions"
3095 :selected (eq ebrowse--accessor 'ebrowse-ts-member-functions)
3097 ["Variables" ebrowse-display-variables-member-list
3098 :help "Show the list of member variables"
3100 :selected (eq ebrowse--accessor 'ebrowse-ts-member-variables)
3102 ["Static Functions" ebrowse-display-static-functions-member-list
3103 :help "Show the list of static member functions"
3105 :selected (eq ebrowse--accessor 'ebrowse-ts-static-functions)
3107 ["Static Variables" ebrowse-display-static-variables-member-list
3108 :help "Show the list of static member variables"
3110 :selected (eq ebrowse--accessor 'ebrowse-ts-static-variables)
3112 ["Types" ebrowse-display-types-member-list
3113 :help "Show the list of nested types"
3115 :selected (eq ebrowse--accessor 'ebrowse-ts-types)
3117 ["Friends/Defines" ebrowse-display-friends-member-list
3118 :help "Show the list of friends or defines"
3120 :selected (eq ebrowse--accessor 'ebrowse-ts-friends)
3123 ["Up" ebrowse-switch-member-buffer-to-base-class
3124 :help "Show the base class of this class"
3126 ["Down" ebrowse-switch-member-buffer-to-derived-class
3127 :help "Show a derived class class of this class"
3129 ["Next Sibling" ebrowse-switch-member-buffer-to-next-sibling-class
3130 :help "Show the next sibling class"
3132 ["Previous Sibling" ebrowse-switch-member-buffer-to-previous-sibling-class
3133 :help "Show the previous sibling class"
3136 ["Show in Tree" ebrowse-show-displayed-class-in-tree
3137 :help "Show this class in the class tree"
3139 ["Find in this Class" ebrowse-goto-visible-member
3140 :help "Search for a member of this class"
3142 ["Find in Tree" ebrowse-goto-visible-member/all-member-lists
3143 :help "Search for a member in any class"
3146 ["Inherited" ebrowse-toggle-base-class-display
3147 :help "Toggle display of inherited members"
3149 :selected ebrowse--show-inherited-flag
3151 ["Attributes" ebrowse-toggle-member-attributes-display
3152 :help "Show member attributes"
3154 :selected ebrowse--attributes-flag
3156 ["Long Display" ebrowse-toggle-long-short-display
3157 :help "Toggle the member display format"
3159 :selected ebrowse--long-display-flag
3161 ["Column Width" ebrowse-set-member-buffer-column-width
3162 :help "Set the display's column width"
3165 ["Public" ebrowse-toggle-public-member-filter
3166 :help "Toggle the visibility of public members"
3168 :selected (not (aref ebrowse--filters 0))
3170 ["Protected" ebrowse-toggle-protected-member-filter
3171 :help "Toggle the visibility of protected members"
3173 :selected (not (aref ebrowse--filters 1))
3175 ["Private" ebrowse-toggle-private-member-filter
3176 :help "Toggle the visibility of private members"
3178 :selected (not (aref ebrowse--filters 2))
3180 ["Virtual" ebrowse-toggle-virtual-member-filter
3181 :help "Toggle the visibility of virtual members"
3183 :selected ebrowse--virtual-display-flag
3185 ["Inline" ebrowse-toggle-inline-member-filter
3186 :help "Toggle the visibility of inline members"
3188 :selected ebrowse--inline-display-flag
3190 ["Const" ebrowse-toggle-const-member-filter
3191 :help "Toggle the visibility of const members"
3193 :selected ebrowse--const-display-flag
3195 ["Pure" ebrowse-toggle-pure-member-filter
3196 :help "Toggle the visibility of pure virtual members"
3198 :selected ebrowse--pure-display-flag
3201 ["Show all" ebrowse-remove-all-member-filters
3202 :help "Remove any display filters"
3205 ["Tree" ebrowse-pop-from-member-to-tree-buffer
3206 :help "Pop to the class tree buffer"
3208 ["Next Member Buffer" ebrowse-switch-to-next-member-buffer
3209 :help "Switch to the next member buffer of this class tree"
3211 ["Freeze" ebrowse-freeze-member-buffer
3212 :help "Freeze (do not reuse) this member buffer"
3216 (defun ebrowse-on-class-name ()
3217 "Value is non-nil if point is on a class name."
3218 (eq (get-text-property (point) 'ebrowse-what) 'class-name))
3221 (defun ebrowse-on-member-name ()
3222 "Value is non-nil if point is on a member name."
3223 (eq (get-text-property (point) 'ebrowse-what) 'member-name))
3227 ebrowse-member-class-name-object-menu ebrowse-member-mode-map
3228 "Object menu for class names in member buffer."
3230 ["Find" ebrowse-find-member-definition
3231 :help "Find this class in the source files"
3232 :active (eq (get-text-property (point) 'ebrowse-what) 'class-name)]
3233 ["View" ebrowse-view-member-definition
3234 :help "View this class in the source files"
3235 :active (eq (get-text-property (point) 'ebrowse-what) 'class-name)]))
3239 ebrowse-member-name-object-menu ebrowse-member-mode-map
3240 "Object menu for member names"
3242 ["Find Definition" ebrowse-find-member-definition
3243 :help "Find this member's definition in the source files"
3244 :active (ebrowse-on-member-name)]
3245 ["Find Declaration" ebrowse-find-member-declaration
3246 :help "Find this member's declaration in the source files"
3247 :active (ebrowse-on-member-name)]
3248 ["View Definition" ebrowse-view-member-definition
3249 :help "View this member's definition in the source files"
3250 :active (ebrowse-on-member-name)]
3251 ["View Declaration" ebrowse-view-member-declaration
3252 :help "View this member's declaration in the source files"
3253 :active (ebrowse-on-member-name)]))
3256 (defun ebrowse-member-mouse-3 (event)
3257 "Handle `mouse-3' events in member buffers.
3258 EVENT is the mouse event."
3260 (mouse-set-point event)
3261 (case (event-click-count event)
3262 (2 (ebrowse-find-member-definition))
3263 (1 (case (get-text-property (posn-point (event-start event))
3266 (ebrowse-popup-menu ebrowse-member-name-object-menu event))
3268 (ebrowse-popup-menu ebrowse-member-class-name-object-menu event))
3270 (ebrowse-popup-menu ebrowse-member-buffer-object-menu event))))))
3273 (defun ebrowse-member-mouse-2 (event)
3274 "Handle `mouse-2' events in member buffers.
3275 EVENT is the mouse event."
3277 (mouse-set-point event)
3278 (case (event-click-count event)
3279 (2 (ebrowse-find-member-definition))
3280 (1 (case (get-text-property (posn-point (event-start event))
3283 (ebrowse-view-member-definition 0))))))
3289 (defun ebrowse-class-alist-for-member (tree-header name)
3290 "Return information about a member in a class tree.
3291 TREE-HEADER is the header structure of the class tree.
3292 NAME is the name of the member.
3293 Value is an alist of elements (CLASS-NAME . (CLASS LIST NAME)),
3294 where each element describes one occurrence of member NAME in the tree.
3295 CLASS-NAME is the qualified name of the class in which the
3296 member was found. The CDR of the acons is described in function
3297 `ebrowse-class/index/member-for-member'."
3298 (let ((table (ebrowse-member-table tree-header))
3302 (dolist (info (gethash name table) alist)
3303 (unless (memq (first info) known-classes)
3304 (setf alist (acons (ebrowse-qualified-class-name
3305 (ebrowse-ts-class (first info)))
3307 known-classes (cons (first info) known-classes)))))))
3310 (defun ebrowse-choose-tree ()
3311 "Choose a class tree to use.
3312 If there's more than one class tree loaded, let the user choose
3313 the one he wants. Value is (TREE HEADER BUFFER), with TREE being
3314 the class tree, HEADER the header structure of the tree, and BUFFER
3315 being the tree or member buffer containing the tree."
3316 (let* ((buffer (ebrowse-choose-from-browser-buffers)))
3317 (if buffer (list (ebrowse-value-in-buffer 'ebrowse--tree buffer)
3318 (ebrowse-value-in-buffer 'ebrowse--header buffer)
3322 (defun ebrowse-tags-read-name (header prompt)
3323 "Read a C++ identifier from the minibuffer.
3324 HEADER is the `ebrowse-hs' structure of the class tree.
3325 Prompt with PROMPT. Insert into the minibuffer a C++ identifier read
3326 from point as default. Value is a list (CLASS-NAME MEMBER-NAME)."
3328 (let* (start member-info (members (ebrowse-member-table header)))
3329 (multiple-value-bind (class-name member-name)
3330 (ebrowse-tags-read-member+class-name)
3332 (error "No member name at point"))
3334 (let* ((name (ebrowse-ignoring-completion-case
3335 (completing-read prompt members nil nil member-name)))
3336 (completion-result (try-completion name members)))
3337 ;; Cannot rely on `try-completion' returning t for exact
3338 ;; matches! It returns the name as a string.
3339 (unless (setq member-info (gethash name members))
3340 (if (y-or-n-p "No exact match found. Try substrings? ")
3342 (or (first (ebrowse-list-of-matching-members
3343 members (regexp-quote name) name))
3344 (error "Sorry, nothing found")))
3345 (error "Canceled")))
3346 (list class-name name))
3347 (list class-name (read-from-minibuffer prompt member-name)))))))
3350 (defun ebrowse-tags-read-member+class-name ()
3351 "Read a C++ identifier from point.
3352 Value is (CLASS-NAME MEMBER-NAME).
3353 CLASS-NAME is the name of the class if the identifier was qualified.
3354 It is nil otherwise.
3355 MEMBER-NAME is the name of the member found."
3357 (skip-chars-backward "a-zA-Z0-9_")
3358 (let* ((start (point))
3359 (name (progn (skip-chars-forward "a-zA-Z0-9_")
3360 (buffer-substring start (point))))
3362 (list class name))))
3365 (defun ebrowse-tags-choose-class (tree header name initial-class-name)
3366 "Read a class name for a member from the minibuffer.
3367 TREE is the class tree we operate on.
3368 HEADER is its header structure.
3369 NAME is the name of the member.
3370 INITIAL-CLASS-NAME is an initial class name to insert in the minibuffer.
3371 Value is a list (TREE ACCESSOR MEMBER) for the member."
3372 (let ((alist (or (ebrowse-class-alist-for-member header name)
3373 (error "No classes with member `%s' found" name))))
3374 (ebrowse-ignoring-completion-case
3375 (if (null (second alist))
3377 (push ?\? unread-command-events)
3378 (cdr (assoc (completing-read "In class: "
3379 alist nil t initial-class-name)
3383 (defun* ebrowse-tags-view/find-member-decl/defn
3384 (prefix &key view definition member-name)
3385 "If VIEW is t, view, else find an occurrence of MEMBER-NAME.
3387 If DEFINITION is t, find or view the member definition else its
3388 declaration. This function reads the member's name from the
3389 current buffer like FIND-TAG. It then prepares a completion list
3390 of all classes containing a member with the given name and lets
3391 the user choose the class to use. As a last step, a tags search
3392 is performed that positions point on the member declaration or
3394 (multiple-value-bind
3395 (tree header tree-buffer) (ebrowse-choose-tree)
3396 (unless tree (error "No class tree"))
3397 (let* ((marker (point-marker))
3402 (multiple-value-setq (class-name name)
3403 (ebrowse-tags-read-name
3405 (concat (if view "View" "Find") " member "
3406 (if definition "definition" "declaration") ": "))))
3407 (setq info (ebrowse-tags-choose-class tree header name class-name))
3408 (ebrowse-push-position marker info)
3409 ;; Goto the occurrence of the member
3410 (ebrowse-view/find-member-declaration/definition
3411 prefix view definition info
3413 (ebrowse-value-in-buffer 'ebrowse--tags-file-name tree-buffer))
3414 ;; Record position jumped to
3415 (ebrowse-push-position (point-marker) info t))))
3419 (defun ebrowse-tags-view-declaration ()
3420 "View declaration of member at point."
3422 (ebrowse-tags-view/find-member-decl/defn 0 :view t :definition nil))
3426 (defun ebrowse-tags-find-declaration ()
3427 "Find declaration of member at point."
3429 (ebrowse-tags-view/find-member-decl/defn 0 :view nil :definition nil))
3433 (defun ebrowse-tags-view-definition ()
3434 "View definition of member at point."
3436 (ebrowse-tags-view/find-member-decl/defn 0 :view t :definition t))
3440 (defun ebrowse-tags-find-definition ()
3441 "Find definition of member at point."
3443 (ebrowse-tags-view/find-member-decl/defn 0 :view nil :definition t))
3446 (defun ebrowse-tags-view-declaration-other-window ()
3447 "View declaration of member at point in other window."
3449 (ebrowse-tags-view/find-member-decl/defn 4 :view t :definition nil))
3453 (defun ebrowse-tags-find-declaration-other-window ()
3454 "Find declaration of member at point in other window."
3456 (ebrowse-tags-view/find-member-decl/defn 4 :view nil :definition nil))
3460 (defun ebrowse-tags-view-definition-other-window ()
3461 "View definition of member at point in other window."
3463 (ebrowse-tags-view/find-member-decl/defn 4 :view t :definition t))
3467 (defun ebrowse-tags-find-definition-other-window ()
3468 "Find definition of member at point in other window."
3470 (ebrowse-tags-view/find-member-decl/defn 4 :view nil :definition t))
3473 (defun ebrowse-tags-view-declaration-other-frame ()
3474 "View definition of member at point in other frame."
3476 (ebrowse-tags-view/find-member-decl/defn 5 :view t :definition nil))
3480 (defun ebrowse-tags-find-declaration-other-frame ()
3481 "Find definition of member at point in other frame."
3483 (ebrowse-tags-view/find-member-decl/defn 5 :view nil :definition nil))
3487 (defun ebrowse-tags-view-definition-other-frame ()
3488 "View definition of member at point in other frame."
3490 (ebrowse-tags-view/find-member-decl/defn 5 :view t :definition t))
3494 (defun ebrowse-tags-find-definition-other-frame ()
3495 "Find definition of member at point in other frame."
3497 (ebrowse-tags-view/find-member-decl/defn 5 :view nil :definition t))
3500 (defun ebrowse-tags-select/create-member-buffer (tree-buffer info)
3501 "Select or create member buffer.
3502 TREE-BUFFER specifies the tree to use. INFO describes the member.
3503 It is a list (TREE ACCESSOR MEMBER)."
3504 (let ((buffer (get-buffer ebrowse-member-buffer-name)))
3505 (cond ((null buffer)
3506 (set-buffer tree-buffer)
3507 (switch-to-buffer (ebrowse-display-member-buffer
3508 (second info) nil (first info))))
3510 (switch-to-buffer buffer)
3511 (setq ebrowse--displayed-class (first info)
3512 ebrowse--accessor (second info)
3513 ebrowse--member-list (funcall ebrowse--accessor ebrowse--displayed-class))
3514 (ebrowse-redisplay-member-buffer)))
3515 (ebrowse-move-point-to-member (ebrowse-ms-name (third info)))))
3518 (defun ebrowse-tags-display-member-buffer (&optional fix-name)
3519 "Display a member buffer for a member.
3520 FIX-NAME non-nil means display the buffer for that member.
3521 Otherwise read a member name from point."
3523 (multiple-value-bind
3524 (tree header tree-buffer) (ebrowse-choose-tree)
3525 (unless tree (error "No class tree"))
3526 (let* ((marker (point-marker)) class-name (name fix-name) info)
3528 (multiple-value-setq (class-name name)
3529 (ebrowse-tags-read-name header
3530 (concat "Find member list of: "))))
3531 (setq info (ebrowse-tags-choose-class tree header name class-name))
3532 (ebrowse-push-position marker info)
3533 (ebrowse-tags-select/create-member-buffer tree-buffer info))))
3536 (defun ebrowse-list-of-matching-members (members regexp &optional name)
3537 "Return a list of members in table MEMBERS matching REGEXP or NAME.
3538 Both NAME and REGEXP may be nil in which case exact or regexp matches
3541 (when (or name regexp)
3542 (maphash #'(lambda (member-name info)
3543 (when (or (and name (string= name member-name))
3544 (and regexp (string-match regexp member-name)))
3545 (setq list (cons member-name list))))
3550 (defun ebrowse-tags-apropos ()
3551 "Display a list of members matching a regexp read from the minibuffer."
3553 (let* ((buffer (or (ebrowse-choose-from-browser-buffers)
3554 (error "No tree buffer")))
3555 (header (ebrowse-value-in-buffer 'ebrowse--header buffer))
3556 (members (ebrowse-member-table header))
3557 temp-buffer-setup-hook
3558 (regexp (read-from-minibuffer "List members matching regexp: ")))
3559 (with-output-to-temp-buffer (concat "*Apropos Members*")
3560 (set-buffer standard-output)
3562 (insert "Members matching `" regexp "'\n\n")
3563 (loop for s in (ebrowse-list-of-matching-members members regexp) do
3564 (loop for info in (gethash s members) do
3565 (ebrowse-draw-file-member-info info))))))
3568 (defun ebrowse-tags-list-members-in-file ()
3569 "Display a list of members found in a file.
3570 The file name is read from the minibuffer."
3572 (let* ((buffer (or (ebrowse-choose-from-browser-buffers)
3573 (error "No tree buffer")))
3574 (files (save-excursion (set-buffer buffer) (ebrowse-files-table)))
3575 (file (completing-read "List members in file: " files nil t))
3576 (header (ebrowse-value-in-buffer 'ebrowse--header buffer))
3577 temp-buffer-setup-hook
3578 (members (ebrowse-member-table header)))
3579 (with-output-to-temp-buffer (concat "*Members in file " file "*")
3580 (set-buffer standard-output)
3582 #'(lambda (member-name list)
3583 (loop for info in list
3584 as member = (third info)
3585 as class = (ebrowse-ts-class (first info))
3586 when (or (and (null (ebrowse-ms-file member))
3587 (string= (ebrowse-cs-file class) file))
3588 (string= file (ebrowse-ms-file member)))
3589 do (ebrowse-draw-file-member-info info "decl.")
3590 when (or (and (null (ebrowse-ms-definition-file member))
3591 (string= (ebrowse-cs-source-file class) file))
3592 (string= file (ebrowse-ms-definition-file member)))
3593 do (ebrowse-draw-file-member-info info "defn.")))
3597 (defun* ebrowse-draw-file-member-info (info &optional (kind ""))
3598 "Display a line in an the members per file info buffer.
3599 INFO describes the member. It has the form (TREE ACCESSOR MEMBER).
3600 TREE is the class of the member to display.
3601 ACCESSOR is the accessor symbol of its member list.
3602 MEMBER is the member structure.
3603 KIND is an additional string printed in the buffer."
3604 (let* ((tree (first info))
3605 (globals-p (ebrowse-globals-tree-p tree)))
3607 (insert (ebrowse-cs-name (ebrowse-ts-class tree))))
3608 (insert "::" (ebrowse-ms-name (third info)))
3612 (insert (case (second info)
3613 ('ebrowse-ts-member-functions "member function")
3614 ('ebrowse-ts-member-variables "member variable")
3615 ('ebrowse-ts-static-functions "static function")
3616 ('ebrowse-ts-static-variables "static variable")
3617 ('ebrowse-ts-friends (if globals-p "define" "friend"))
3618 ('ebrowse-ts-types "type")
3622 (defvar ebrowse-last-completion nil
3623 "Text inserted by the last completion operation.")
3626 (defvar ebrowse-last-completion-start nil
3627 "String which was the basis for the last completion operation.")
3630 (defvar ebrowse-last-completion-location nil
3631 "Buffer position at which the last completion operation was initiated.")
3634 (defvar ebrowse-last-completion-obarray nil
3635 "Member used in last completion operation.")
3638 (make-variable-buffer-local 'ebrowse-last-completion-obarray)
3639 (make-variable-buffer-local 'ebrowse-last-completion-location)
3640 (make-variable-buffer-local 'ebrowse-last-completion)
3641 (make-variable-buffer-local 'ebrowse-last-completion-start)
3645 (defun ebrowse-some-member-table ()
3646 "Return a hash table containing all members of a tree.
3647 If there's only one tree loaded, use that. Otherwise let the
3649 (let* ((buffers (ebrowse-known-class-trees-buffer-list))
3650 (buffer (cond ((and (first buffers) (not (second buffers)))
3652 (t (or (ebrowse-electric-choose-tree)
3653 (error "No tree buffer")))))
3654 (header (ebrowse-value-in-buffer 'ebrowse--header buffer)))
3655 (ebrowse-member-table header)))
3658 (defun ebrowse-cyclic-successor-in-string-list (string list)
3659 "Return the item following STRING in LIST.
3660 If STRING is the last element, return the first element as successor."
3661 (or (nth (1+ (ebrowse-position string list 'string=)) list)
3665 ;;; Symbol completion
3668 (defun* ebrowse-tags-complete-symbol (prefix)
3669 "Perform completion on the C++ symbol preceding point.
3670 A second call of this function without changing point inserts the next match.
3671 A call with prefix PREFIX reads the symbol to insert from the minibuffer with
3674 (let* ((end (point))
3675 (begin (save-excursion (skip-chars-backward "a-zA-Z_0-9") (point)))
3676 (pattern (buffer-substring begin end))
3679 ;; With prefix, read name from minibuffer with completion.
3681 (let* ((members (ebrowse-some-member-table))
3682 (completion (completing-read "Insert member: "
3683 members nil t pattern)))
3685 (setf ebrowse-last-completion-location nil)
3686 (delete-region begin end)
3687 (insert completion))))
3688 ;; If this function is called at the same point the last
3689 ;; expansion ended, insert the next expansion.
3690 ((eq (point) ebrowse-last-completion-location)
3691 (setf list (all-completions ebrowse-last-completion-start
3692 ebrowse-last-completion-obarray)
3693 completion (ebrowse-cyclic-successor-in-string-list
3694 ebrowse-last-completion list))
3695 (cond ((null completion)
3696 (error "No completion"))
3697 ((string= completion pattern)
3698 (error "No further completion"))
3700 (delete-region begin end)
3702 (setf ebrowse-last-completion completion
3703 ebrowse-last-completion-location (point)))))
3704 ;; First time the function is called at some position in the
3705 ;; buffer: Start new completion.
3707 (let* ((members (ebrowse-some-member-table))
3708 (completion (first (all-completions pattern members nil))))
3709 (cond ((eq completion t))
3711 (error "Can't find completion for `%s'" pattern))
3713 (delete-region begin end)
3716 (setf ebrowse-last-completion-location (point)
3717 ebrowse-last-completion-start pattern
3718 ebrowse-last-completion completion
3719 ebrowse-last-completion-obarray members))))))))
3722 ;;; Tags query replace & search
3724 (defvar ebrowse-tags-loop-form ()
3725 "Form for `ebrowse-loop-continue'.
3726 Evaluated for each file in the tree. If it returns nil, proceed
3727 with the next file.")
3729 (defvar ebrowse-tags-next-file-list ()
3730 "A list of files to be processed.")
3733 (defvar ebrowse-tags-next-file-path nil
3734 "The path relative to which files have to be searched.")
3737 (defvar ebrowse-tags-loop-last-file nil
3738 "The last file visited via `ebrowse-tags-loop'.")
3741 (defun ebrowse-tags-next-file (&optional initialize tree-buffer)
3742 "Select next file among files in current tag table.
3743 Non-nil argument INITIALIZE (prefix arg, if interactive) initializes
3744 to the beginning of the list of files in the tag table.
3745 TREE-BUFFER specifies the class tree we operate on."
3747 ;; Call with INITIALIZE non-nil initializes the files list.
3748 ;; If more than one tree buffer is loaded, let the user choose
3749 ;; on which tree (s)he wants to operate.
3751 (let ((buffer (or tree-buffer (ebrowse-choose-from-browser-buffers))))
3754 (setq ebrowse-tags-next-file-list
3755 (ebrowse-files-list (ebrowse-marked-classes-p))
3756 ebrowse-tags-loop-last-file
3758 ebrowse-tags-next-file-path
3759 (file-name-directory ebrowse--tags-file-name)))))
3760 ;; End of the loop if the stack of files is empty.
3761 (unless ebrowse-tags-next-file-list
3762 (error "All files processed"))
3763 ;; ebrowse-tags-loop-last-file is the last file that was visited due
3764 ;; to a call to BROWSE-LOOP (see below). If that file is still
3765 ;; in memory, and it wasn't modified, throw its buffer away to
3766 ;; prevent cluttering up the buffer list.
3767 (when ebrowse-tags-loop-last-file
3768 (let ((buffer (get-file-buffer ebrowse-tags-loop-last-file)))
3770 (not (buffer-modified-p buffer)))
3771 (kill-buffer buffer))))
3772 ;; Remember this buffer file name for later deletion, if it
3773 ;; wasn't visited by other means.
3774 (let ((file (expand-file-name (car ebrowse-tags-next-file-list)
3775 ebrowse-tags-next-file-path)))
3776 (setq ebrowse-tags-loop-last-file (if (get-file-buffer file) nil file))
3777 ;; Find the file and pop the file list. Pop has to be done
3778 ;; before the file is loaded because FIND-FILE might encounter
3779 ;; an error, and we want to be able to proceed with the next
3780 ;; file in this case.
3781 (pop ebrowse-tags-next-file-list)
3786 (defun ebrowse-tags-loop-continue (&optional first-time tree-buffer)
3787 "Repeat last operation on files in tree.
3788 FIRST-TIME non-nil means this is not a repetition, but the first time.
3789 TREE-BUFFER if indirectly specifies which files to loop over."
3792 (ebrowse-tags-next-file first-time tree-buffer)
3793 (goto-char (point-min)))
3794 (while (not (eval ebrowse-tags-loop-form))
3795 (ebrowse-tags-next-file)
3796 (message "Scanning file `%s'..." buffer-file-name)
3797 (goto-char (point-min))))
3801 (defun ebrowse-tags-search (regexp)
3802 "Search for REGEXP in all files in a tree.
3803 If marked classes exist, process marked classes, only.
3804 If regular expression is nil, repeat last search."
3805 (interactive "sTree search (regexp): ")
3806 (if (and (string= regexp "")
3807 (eq (car ebrowse-tags-loop-form) 're-search-forward))
3808 (ebrowse-tags-loop-continue)
3809 (setq ebrowse-tags-loop-form (list 're-search-forward regexp nil t))
3810 (ebrowse-tags-loop-continue 'first-time)))
3814 (defun ebrowse-tags-query-replace (from to)
3815 "Query replace FROM with TO in all files of a class tree.
3816 With prefix arg, process files of marked classes only."
3818 "sTree query replace (regexp): \nsTree query replace %s by: ")
3819 (setq ebrowse-tags-loop-form
3820 (list 'and (list 'save-excursion
3821 (list 're-search-forward from nil t))
3822 (list 'not (list 'perform-replace from to t t nil))))
3823 (ebrowse-tags-loop-continue 'first-time))
3827 (defun ebrowse-tags-search-member-use (&optional fix-name)
3828 "Search for call sites of a member.
3829 If FIX-NAME is specified, search uses of that member.
3830 Otherwise, read a member name from the minibuffer.
3831 Searches in all files mentioned in a class tree for something that
3832 looks like a function call to the member."
3834 ;; Choose the tree to use if there is more than one.
3835 (multiple-value-bind (tree header tree-buffer)
3836 (ebrowse-choose-tree)
3838 (error "No class tree"))
3839 ;; Get the member name NAME (class-name is ignored).
3840 (let ((name fix-name) class-name regexp)
3842 (multiple-value-setq (class-name name)
3843 (ebrowse-tags-read-name header "Find calls of: ")))
3844 ;; Set tags loop form to search for member and begin loop.
3845 (setq regexp (concat "\\<" name "[ \t]*(")
3846 ebrowse-tags-loop-form (list 're-search-forward regexp nil t))
3847 (ebrowse-tags-loop-continue 'first-time tree-buffer))))
3851 ;;; Tags position management
3853 ;;; Structures of this kind are the elements of the position stack.
3855 (defstruct (ebrowse-position (:type vector) :named)
3856 file-name ; in which file
3857 point ; point in file
3858 target ; t if target of a jump
3859 info) ; (CLASS FUNC MEMBER) jumped to
3862 (defvar ebrowse-position-stack ()
3863 "Stack of `ebrowse-position' structured.")
3866 (defvar ebrowse-position-index 0
3867 "Current position in position stack.")
3870 (defun ebrowse-position-name (position)
3871 "Return an identifying string for POSITION.
3872 The string is printed in the electric position list buffer."
3873 (let ((info (ebrowse-position-info position)))
3874 (concat (if (ebrowse-position-target position) "at " "to ")
3875 (ebrowse-cs-name (ebrowse-ts-class (first info)))
3876 "::" (ebrowse-ms-name (third info)))))
3879 (defun ebrowse-view/find-position (position &optional view)
3880 "Position point on POSITION.
3881 If VIEW is non-nil, view the position, otherwise find it."
3883 (find-file (ebrowse-position-file-name position))
3884 (goto-char (ebrowse-position-point position)))
3890 (goto-char (ebrowse-position-point position))))
3892 (view-file (ebrowse-position-file-name position)))
3893 (pop view-mode-hook)))))
3896 (defun ebrowse-push-position (marker info &optional target)
3897 "Push current position on position stack.
3898 MARKER is the marker to remember as position.
3899 INFO is a list (CLASS FUNC MEMBER) specifying what we jumped to.
3900 TARGET non-nil means we performed a jump.
3901 Positions in buffers that have no file names are not saved."
3902 (when (buffer-file-name (marker-buffer marker))
3903 (let ((too-much (- (length ebrowse-position-stack)
3904 ebrowse-max-positions)))
3905 ;; Do not let the stack grow to infinity.
3906 (when (plusp too-much)
3907 (setq ebrowse-position-stack
3908 (butlast ebrowse-position-stack too-much)))
3909 ;; Push the position.
3910 (push (make-ebrowse-position
3911 :file-name (buffer-file-name (marker-buffer marker))
3912 :point (marker-position marker)
3915 ebrowse-position-stack))))
3918 (defun ebrowse-move-in-position-stack (increment)
3919 "Move by INCREMENT in the position stack."
3920 (let ((length (length ebrowse-position-stack)))
3921 (when (zerop length)
3922 (error "No positions remembered"))
3923 (setq ebrowse-position-index
3924 (mod (+ increment ebrowse-position-index) length))
3925 (message "Position %d of %d " ebrowse-position-index length)
3926 (ebrowse-view/find-position (nth ebrowse-position-index
3927 ebrowse-position-stack))))
3931 (defun ebrowse-back-in-position-stack (arg)
3932 "Move backward in the position stack.
3933 Prefix arg ARG says how much."
3935 (ebrowse-move-in-position-stack (max 1 arg)))
3939 (defun ebrowse-forward-in-position-stack (arg)
3940 "Move forward in the position stack.
3941 Prefix arg ARG says how much."
3943 (ebrowse-move-in-position-stack (min -1 (- arg))))
3947 ;;; Electric position list
3949 (defvar ebrowse-electric-position-mode-map ()
3950 "Keymap used in electric position stack window.")
3953 (defvar ebrowse-electric-position-mode-hook nil
3954 "If non-nil, its value is called by `ebrowse-electric-position-mode'.")
3957 (unless ebrowse-electric-position-mode-map
3958 (let ((map (make-keymap))
3959 (submap (make-keymap)))
3960 (setq ebrowse-electric-position-mode-map map)
3961 (fillarray (car (cdr map)) 'ebrowse-electric-position-undefined)
3962 (fillarray (car (cdr submap)) 'ebrowse-electric-position-undefined)
3963 (define-key map "\e" submap)
3964 (define-key map "\C-z" 'suspend-emacs)
3965 (define-key map "\C-h" 'Helper-help)
3966 (define-key map "?" 'Helper-describe-bindings)
3967 (define-key map "\C-c" nil)
3968 (define-key map "\C-c\C-c" 'ebrowse-electric-position-quit)
3969 (define-key map "q" 'ebrowse-electric-position-quit)
3970 (define-key map " " 'ebrowse-electric-select-position)
3971 (define-key map "\C-l" 'recenter)
3972 (define-key map "\C-u" 'universal-argument)
3973 (define-key map "\C-p" 'previous-line)
3974 (define-key map "\C-n" 'next-line)
3975 (define-key map "p" 'previous-line)
3976 (define-key map "n" 'next-line)
3977 (define-key map "v" 'ebrowse-electric-view-position)
3978 (define-key map "\C-v" 'scroll-up)
3979 (define-key map "\ev" 'scroll-down)
3980 (define-key map "\e\C-v" 'scroll-other-window)
3981 (define-key map "\e>" 'end-of-buffer)
3982 (define-key map "\e<" 'beginning-of-buffer)
3983 (define-key map "\e>" 'end-of-buffer)))
3985 (put 'ebrowse-electric-position-mode 'mode-class 'special)
3986 (put 'ebrowse-electric-position-undefined 'suppress-keymap t)
3989 (defun ebrowse-electric-position-mode ()
3990 "Mode for electric position buffers.
3991 Runs the hook `ebrowse-electric-position-mode-hook'."
3992 (kill-all-local-variables)
3993 (use-local-map ebrowse-electric-position-mode-map)
3994 (setq mode-name "Electric Position Menu"
3995 mode-line-buffer-identification "Electric Position Menu")
3996 (when (memq 'mode-name mode-line-format)
3997 (setq mode-line-format (copy-sequence mode-line-format))
3998 (setcar (memq 'mode-name mode-line-format) "Positions"))
3999 (make-local-variable 'Helper-return-blurb)
4000 (setq Helper-return-blurb "return to buffer editing"
4003 major-mode 'ebrowse-electric-position-mode)
4004 (run-mode-hooks 'ebrowse-electric-position-mode-hook))
4007 (defun ebrowse-draw-position-buffer ()
4008 "Display positions in buffer *Positions*."
4009 (set-buffer (get-buffer-create "*Positions*"))
4010 (setq buffer-read-only nil)
4012 (insert "File Point Description\n"
4013 "---- ----- -----------\n")
4014 (dolist (position ebrowse-position-stack)
4015 (insert (file-name-nondirectory (ebrowse-position-file-name position)))
4017 (insert (int-to-string (ebrowse-position-point position)))
4019 (insert (ebrowse-position-name position) "\n"))
4020 (setq buffer-read-only t))
4024 (defun ebrowse-electric-position-menu ()
4025 "List positions in the position stack in an electric buffer."
4027 (unless ebrowse-position-stack
4028 (error "No positions remembered"))
4029 (let (select buffer window)
4030 (save-window-excursion
4031 (save-window-excursion (ebrowse-draw-position-buffer))
4032 (setq window (Electric-pop-up-window "*Positions*")
4033 buffer (window-buffer window))
4034 (shrink-window-if-larger-than-buffer window)
4038 (ebrowse-electric-position-mode)
4040 (catch 'ebrowse-electric-select-position
4041 (message "<<< Press Space to bury the list >>>")
4042 (let ((first (progn (goto-char (point-min))
4045 (last (progn (goto-char (point-max))
4050 (Electric-command-loop 'ebrowse-electric-select-position
4052 'ebrowse-electric-position-looper
4053 (cons first last))))))
4055 (bury-buffer buffer)
4059 (ebrowse-electric-find-position select))
4060 (kill-buffer buffer)))
4063 (defun ebrowse-electric-position-looper (state condition)
4064 "Prevent moving point on invalid lines.
4065 Called from `Electric-command-loop'. See there for the meaning
4066 of STATE and CONDITION."
4067 (cond ((and condition
4068 (not (memq (car condition) '(buffer-read-only
4070 beginning-of-buffer))))
4071 (signal (car condition) (cdr condition)))
4072 ((< (point) (car state))
4073 (goto-char (point-min))
4075 ((> (point) (cdr state))
4076 (goto-char (point-max))
4078 (if (pos-visible-in-window-p (point-max))
4082 (defun ebrowse-electric-position-undefined ()
4083 "Function called for undefined keys."
4085 (message "Type C-h for help, ? for commands, q to quit, Space to execute")
4089 (defun ebrowse-electric-position-quit ()
4090 "Leave the electric position list."
4092 (throw 'ebrowse-electric-select-position nil))
4095 (defun ebrowse-electric-select-position ()
4096 "Select a position from the list."
4098 (throw 'ebrowse-electric-select-position (point)))
4101 (defun ebrowse-electric-find-position (point &optional view)
4102 "View/find what is described by the line at POINT.
4103 If VIEW is non-nil, view else find source files."
4104 (let ((index (- (count-lines (point-min) point) 2)))
4105 (ebrowse-view/find-position (nth index
4106 ebrowse-position-stack) view)))
4109 (defun ebrowse-electric-view-position ()
4110 "View the position described by the line point is in."
4112 (ebrowse-electric-find-position (point) t))
4116 ;;; Saving trees to disk
4118 (defun ebrowse-write-file-hook-fn ()
4119 "Write current buffer as a class tree.
4120 Installed on `local-write-file-hooks'."
4126 (defun ebrowse-save-tree ()
4127 "Save current tree in same file it was loaded from."
4129 (ebrowse-save-tree-as (or buffer-file-name ebrowse--tags-file-name)))
4133 (defun ebrowse-save-tree-as (&optional file-name)
4134 "Write the current tree data structure to a file.
4135 Read the file name from the minibuffer if interactive.
4136 Otherwise, FILE-NAME specifies the file to save the tree in."
4137 (interactive "FSave tree as: ")
4138 (let ((temp-buffer (get-buffer-create "*Tree Output"))
4139 (old-standard-output standard-output)
4140 (header (copy-ebrowse-hs ebrowse--header))
4141 (tree ebrowse--tree))
4144 (set-buffer (setq standard-output temp-buffer))
4146 (setf (ebrowse-hs-member-table header) nil)
4147 (insert (prin1-to-string header) " ")
4148 (mapcar 'ebrowse-save-class tree)
4149 (write-file file-name)
4150 (message "Tree written to file `%s'" file-name))
4151 (kill-buffer temp-buffer)
4152 (set-buffer-modified-p nil)
4153 (ebrowse-update-tree-buffer-mode-line)
4154 (setq standard-output old-standard-output))))
4157 (defun ebrowse-save-class (class)
4158 "Write single class CLASS to current buffer."
4159 (message "%s..." (ebrowse-cs-name (ebrowse-ts-class class)))
4160 (insert "[ebrowse-ts ")
4161 (prin1 (ebrowse-ts-class class)) ;class name
4162 (insert "(") ;list of subclasses
4163 (mapcar 'ebrowse-save-class (ebrowse-ts-subclasses class))
4165 (dolist (func ebrowse-member-list-accessors)
4166 (prin1 (funcall func class))
4168 (insert "()") ;base-classes slot
4169 (prin1 (ebrowse-ts-mark class))
4177 (defun ebrowse-statistics ()
4178 "Display statistics for a class tree."
4180 (let ((tree-file (buffer-file-name))
4181 temp-buffer-setup-hook)
4182 (with-output-to-temp-buffer "*Tree Statistics*"
4183 (multiple-value-bind (classes member-functions member-variables
4184 static-functions static-variables)
4185 (ebrowse-gather-statistics)
4186 (set-buffer standard-output)
4188 (insert "STATISTICS FOR TREE " (or tree-file "unknown") ":\n\n")
4189 (ebrowse-print-statistics-line "Number of classes:" classes)
4190 (ebrowse-print-statistics-line "Number of member functions:"
4192 (ebrowse-print-statistics-line "Number of member variables:"
4194 (ebrowse-print-statistics-line "Number of static functions:"
4196 (ebrowse-print-statistics-line "Number of static variables:"
4197 static-variables)))))
4200 (defun ebrowse-print-statistics-line (title value)
4201 "Print a line in the statistics buffer.
4202 TITLE is the title of the line, VALUE is a number to be printed
4206 (insert (format "%d\n" value)))
4209 (defun ebrowse-gather-statistics ()
4210 "Return statistics for a class tree.
4211 The result is a list (NUMBER-OF-CLASSES NUMBER-OF-MEMBER-FUNCTIONS
4212 NUMBER-OF-INSTANCE-VARIABLES NUMBER-OF-STATIC-FUNCTIONS
4213 NUMBER-OF-STATIC-VARIABLES:"
4214 (let ((classes 0) (member-functions 0) (member-variables 0)
4215 (static-functions 0) (static-variables 0))
4216 (ebrowse-for-all-trees (tree ebrowse--tree-obarray)
4218 (incf member-functions (length (ebrowse-ts-member-functions tree)))
4219 (incf member-variables (length (ebrowse-ts-member-variables tree)))
4220 (incf static-functions (length (ebrowse-ts-static-functions tree)))
4221 (incf static-variables (length (ebrowse-ts-static-variables tree))))
4222 (list classes member-functions member-variables
4223 static-functions static-variables)))
4227 ;;; Global key bindings
4229 ;;; The following can be used to bind key sequences starting with
4230 ;;; prefix `\C-cb' to browse commands.
4232 (defvar ebrowse-global-map nil
4233 "*Keymap for Ebrowse commands.")
4236 (defvar ebrowse-global-prefix-key "\C-cb"
4237 "Prefix key for Ebrowse commands.")
4240 (defvar ebrowse-global-submap-4 nil
4241 "Keymap used for `ebrowse-global-prefix' followed by `4'.")
4244 (defvar ebrowse-global-submap-5 nil
4245 "Keymap used for `ebrowse-global-prefix' followed by `5'.")
4248 (unless ebrowse-global-map
4249 (setq ebrowse-global-map (make-sparse-keymap))
4250 (setq ebrowse-global-submap-4 (make-sparse-keymap))
4251 (setq ebrowse-global-submap-5 (make-sparse-keymap))
4252 (define-key ebrowse-global-map "a" 'ebrowse-tags-apropos)
4253 (define-key ebrowse-global-map "b" 'ebrowse-pop-to-browser-buffer)
4254 (define-key ebrowse-global-map "-" 'ebrowse-back-in-position-stack)
4255 (define-key ebrowse-global-map "+" 'ebrowse-forward-in-position-stack)
4256 (define-key ebrowse-global-map "l" 'ebrowse-tags-list-members-in-file)
4257 (define-key ebrowse-global-map "m" 'ebrowse-tags-display-member-buffer)
4258 (define-key ebrowse-global-map "n" 'ebrowse-tags-next-file)
4259 (define-key ebrowse-global-map "p" 'ebrowse-electric-position-menu)
4260 (define-key ebrowse-global-map "s" 'ebrowse-tags-search)
4261 (define-key ebrowse-global-map "u" 'ebrowse-tags-search-member-use)
4262 (define-key ebrowse-global-map "v" 'ebrowse-tags-view-definition)
4263 (define-key ebrowse-global-map "V" 'ebrowse-tags-view-declaration)
4264 (define-key ebrowse-global-map "%" 'ebrowse-tags-query-replace)
4265 (define-key ebrowse-global-map "." 'ebrowse-tags-find-definition)
4266 (define-key ebrowse-global-map "f" 'ebrowse-tags-find-definition)
4267 (define-key ebrowse-global-map "F" 'ebrowse-tags-find-declaration)
4268 (define-key ebrowse-global-map "," 'ebrowse-tags-loop-continue)
4269 (define-key ebrowse-global-map " " 'ebrowse-electric-buffer-list)
4270 (define-key ebrowse-global-map "\t" 'ebrowse-tags-complete-symbol)
4271 (define-key ebrowse-global-map "4" ebrowse-global-submap-4)
4272 (define-key ebrowse-global-submap-4 "." 'ebrowse-tags-find-definition-other-window)
4273 (define-key ebrowse-global-submap-4 "f" 'ebrowse-tags-find-definition-other-window)
4274 (define-key ebrowse-global-submap-4 "v" 'ebrowse-tags-find-declaration-other-window)
4275 (define-key ebrowse-global-submap-4 "F" 'ebrowse-tags-view-definition-other-window)
4276 (define-key ebrowse-global-submap-4 "V" 'ebrowse-tags-view-declaration-other-window)
4277 (define-key ebrowse-global-map "5" ebrowse-global-submap-5)
4278 (define-key ebrowse-global-submap-5 "." 'ebrowse-tags-find-definition-other-frame)
4279 (define-key ebrowse-global-submap-5 "f" 'ebrowse-tags-find-definition-other-frame)
4280 (define-key ebrowse-global-submap-5 "v" 'ebrowse-tags-find-declaration-other-frame)
4281 (define-key ebrowse-global-submap-5 "F" 'ebrowse-tags-view-definition-other-frame)
4282 (define-key ebrowse-global-submap-5 "V" 'ebrowse-tags-view-declaration-other-frame)
4283 (define-key global-map ebrowse-global-prefix-key ebrowse-global-map))
4287 ;;; Electric C++ browser buffer menu
4289 ;;; Electric buffer menu customization to display only some buffers
4290 ;;; (in this case Tree buffers). There is only one problem with this:
4291 ;;; If the very first character typed in the buffer menu is a space,
4292 ;;; this will select the buffer from which the buffer menu was
4293 ;;; invoked. But this buffer is not displayed in the buffer list if
4294 ;;; it isn't a tree buffer. I therefore let the buffer menu command
4295 ;;; loop read the command `p' via `unread-command-char'. This command
4296 ;;; has no effect since we are on the first line of the buffer.
4298 (defvar electric-buffer-menu-mode-hook nil)
4301 (defun ebrowse-hack-electric-buffer-menu ()
4302 "Hack the electric buffer menu to display browser buffers."
4306 (setq buffer-read-only nil)
4310 (let ((b (Buffer-menu-buffer nil)))
4311 (if (or (ebrowse-buffer-p b)
4312 (string= (buffer-name b) "*Apropos Members*"))
4313 (progn (forward-line 1)
4315 (delete-region (point)
4316 (save-excursion (end-of-line)
4320 (error "No tree buffers"))
4321 (setf unread-command-events (listify-key-sequence "p"))
4322 (shrink-window-if-larger-than-buffer (selected-window))
4323 (setq buffer-read-only t))))
4326 (defun ebrowse-select-1st-to-9nth ()
4327 "Select the nth entry in the list by the keys 1..9."
4329 (let* ((maxlin (count-lines (point-min) (point-max)))
4330 (n (min maxlin (+ 2 (string-to-number (this-command-keys))))))
4332 (throw 'electric-buffer-menu-select (point))))
4335 (defun ebrowse-install-1-to-9-keys ()
4336 "Define keys 1..9 to select the 1st to 9nth entry in the list."
4338 (define-key (current-local-map) (char-to-string (+ i ?1))
4339 'ebrowse-select-1st-to-9nth)))
4342 (defun ebrowse-electric-buffer-list ()
4343 "Display an electric list of Ebrowse buffers."
4347 (add-hook 'electric-buffer-menu-mode-hook
4348 'ebrowse-hack-electric-buffer-menu)
4349 (add-hook 'electric-buffer-menu-mode-hook
4350 'ebrowse-install-1-to-9-keys)
4351 (call-interactively 'electric-buffer-list))
4352 (remove-hook 'electric-buffer-menu-mode-hook
4353 'ebrowse-hack-electric-buffer-menu)))
4358 (defun ebrowse-mouse-find-member (event)
4359 "Find the member clicked on in another frame.
4360 EVENT is a mouse button event."
4362 (mouse-set-point event)
4365 (skip-chars-backward "a-zA-Z0-9_")
4366 (setq start (point))
4367 (skip-chars-forward "a-zA-Z0-9_")
4368 (setq name (buffer-substring start (point))))
4369 (ebrowse-tags-view/find-member-decl/defn
4370 5 :view nil :definition t :member-name name)))
4373 (defun ebrowse-popup-menu (menu event)
4374 "Pop up MENU and perform an action if something was selected.
4375 EVENT is the mouse event."
4376 (save-selected-window
4377 (select-window (posn-window (event-start event)))
4378 (let ((selection (x-popup-menu event menu)) binding)
4380 (setq binding (lookup-key (or binding menu) (vector (car selection)))
4381 selection (cdr selection)))
4383 (call-interactively binding)))))
4387 ebrowse-tree-buffer-class-object-menu ebrowse-tree-mode-map
4388 "Object menu for classes in the tree buffer"
4390 ["Functions" ebrowse-tree-command:show-member-functions
4391 :help "Display a list of member functions"
4393 ["Variables" ebrowse-tree-command:show-member-variables
4394 :help "Display a list of member variables"
4396 ["Static Functions" ebrowse-tree-command:show-static-member-functions
4397 :help "Display a list of static member functions"
4399 ["Static Variables" ebrowse-tree-command:show-static-member-variables
4400 :help "Display a list of static member variables"
4402 ["Friends/ Defines" ebrowse-tree-command:show-friends
4403 :help "Display a list of friends of a class"
4405 ["Types" ebrowse-tree-command:show-types
4406 :help "Display a list of types defined in a class"
4409 ["View" ebrowse-view-class-declaration
4410 :help "View class declaration"
4411 :active (eq (get-text-property (point) 'ebrowse-what) 'class-name)]
4412 ["Find" ebrowse-find-class-declaration
4413 :help "Find class declaration in file"
4414 :active (eq (get-text-property (point) 'ebrowse-what) 'class-name)]
4416 ["Mark" ebrowse-toggle-mark-at-point
4417 :help "Mark class point is on"
4418 :active (eq (get-text-property (point) 'ebrowse-what) 'class-name)]
4420 ["Collapse" ebrowse-collapse-branch
4421 :help "Collapse subtree under class point is on"
4422 :active (eq (get-text-property (point) 'ebrowse-what) 'class-name)]
4423 ["Expand" ebrowse-expand-branch
4424 :help "Expand subtree under class point is on"
4425 :active (eq (get-text-property (point) 'ebrowse-what) 'class-name)]))
4429 ebrowse-tree-buffer-object-menu ebrowse-tree-mode-map
4430 "Object menu for tree buffers"
4432 ["Filename Display" ebrowse-toggle-file-name-display
4433 :help "Toggle display of source files names"
4435 :selected ebrowse--show-file-names-flag
4437 ["Tree Indentation" ebrowse-set-tree-indentation
4438 :help "Set the tree's indentation"
4440 ["Unmark All Classes" ebrowse-mark-all-classes
4441 :help "Unmark all classes in the class tree"
4443 ["Expand All" ebrowse-expand-all
4444 :help "Expand all subtrees in the class tree"
4446 ["Statistics" ebrowse-statistics
4447 :help "Show a buffer with class hierarchy statistics"
4449 ["Find Class" ebrowse-read-class-name-and-go
4450 :help "Find a class in the tree"
4452 ["Member Buffer" ebrowse-pop/switch-to-member-buffer-for-same-tree
4453 :help "Show a member buffer for this class tree"
4457 (defun ebrowse-mouse-3-in-tree-buffer (event)
4458 "Perform mouse actions in tree buffers.
4459 EVENT is the mouse event."
4461 (mouse-set-point event)
4462 (let* ((where (posn-point (event-start event)))
4463 (property (get-text-property where 'ebrowse-what)))
4464 (case (event-click-count event)
4468 (ebrowse-popup-menu ebrowse-tree-buffer-class-object-menu event))
4470 (ebrowse-popup-menu ebrowse-tree-buffer-object-menu event)))))))
4473 (defun ebrowse-mouse-2-in-tree-buffer (event)
4474 "Perform mouse actions in tree buffers.
4475 EVENT is the mouse event."
4477 (mouse-set-point event)
4478 (let* ((where (posn-point (event-start event)))
4479 (property (get-text-property where 'ebrowse-what)))
4480 (case (event-click-count event)
4483 (ebrowse-tree-command:show-member-functions)))))))
4486 (defun ebrowse-mouse-1-in-tree-buffer (event)
4487 "Perform mouse actions in tree buffers.
4488 EVENT is the mouse event."
4490 (mouse-set-point event)
4491 (let* ((where (posn-point (event-start event)))
4492 (property (get-text-property where 'ebrowse-what)))
4493 (case (event-click-count event)
4496 (let ((collapsed (save-excursion (skip-chars-forward "^\r\n")
4497 (looking-at "\r"))))
4498 (ebrowse-collapse-fn (not collapsed))))
4500 (ebrowse-toggle-mark-at-point 1)))))))
4506 ;;; Local variables:
4507 ;;; eval:(put 'ebrowse-output 'lisp-indent-hook 0)
4508 ;;; eval:(put 'ebrowse-ignoring-completion-case 'lisp-indent-hook 0)
4509 ;;; eval:(put 'ebrowse-save-selective 'lisp-indent-hook 0)
4510 ;;; eval:(put 'ebrowse-for-all-trees 'lisp-indent-hook 1)
4513 ;;; arch-tag: 4fa3c8bf-1771-479b-bcd7-b029c7c9677b
4514 ;;; ebrowse.el ends here