Add 2012 to FSF copyright years for Emacs files
[bpt/emacs.git] / lisp / progmodes / ebrowse.el
CommitLineData
be0dbdab
GM
1;;; ebrowse.el --- Emacs C++ class browser & tags facility
2
acaf905b 3;; Copyright (C) 1992-2012 Free Software Foundation, Inc.
be0dbdab
GM
4
5;; Author: Gerd Moellmann <gerd@gnu.org>
6;; Maintainer: FSF
7;; Keywords: C++ tags tools
8
9;; This file is part of GNU Emacs.
10
b1fc2b50 11;; GNU Emacs is free software: you can redistribute it and/or modify
be0dbdab 12;; it under the terms of the GNU General Public License as published by
b1fc2b50
GM
13;; the Free Software Foundation, either version 3 of the License, or
14;; (at your option) any later version.
be0dbdab
GM
15
16;; GNU Emacs is distributed in the hope that it will be useful,
17;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19;; GNU General Public License for more details.
20
21;; You should have received a copy of the GNU General Public License
b1fc2b50 22;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
be0dbdab
GM
23
24;;; Commentary:
25
26;; This package implements
27
28;; - A class browser for C++
29;; - A complete set of tags-like functions working on class trees
30;; - An electric buffer list showing class browser buffers only
31
106ba1bb 32;; Documentation is found in a separate Info file.
be0dbdab
GM
33
34;;; Code:
35
36(require 'easymenu)
37(require 'view)
38(require 'ebuff-menu)
39
40(eval-when-compile
41 (require 'cl)
42 (require 'helper))
43
44\f
45;;; User-options
46
47(defgroup ebrowse nil
48 "Settings for the C++ class browser."
49 :group 'tools)
50
51
52(defcustom ebrowse-search-path nil
53 "*List of directories to search for source files in a class tree.
54Elements should be directory names; nil as an element means to try
183c2d42 55to find source files relative to the location of the BROWSE file loaded."
be0dbdab
GM
56 :group 'ebrowse
57 :type '(repeat (choice (const :tag "Default" nil)
58 (string :tag "Directory"))))
59
60
61(defcustom ebrowse-view/find-hook nil
62 "*Hooks run after finding or viewing a member or class."
63 :group 'ebrowse
64 :type 'hook)
65
66
67(defcustom ebrowse-not-found-hook nil
68 "*Hooks run when finding or viewing a member or class was not successful."
69 :group 'ebrowse
70 :type 'hook)
71
72
73(defcustom ebrowse-electric-list-mode-hook nil
74 "*Hook called by `ebrowse-electric-position-mode'."
75 :group 'ebrowse
76 :type 'hook)
77
78
79(defcustom ebrowse-max-positions 50
80 "*Number of markers saved on electric position stack."
81 :group 'ebrowse
82 :type 'integer)
83
84
85\f
86(defgroup ebrowse-tree nil
87 "Settings for class tree buffers."
88 :group 'ebrowse)
89
90
91(defcustom ebrowse-tree-mode-hook nil
92 "*Hook run in each new tree buffer."
93 :group 'ebrowse-tree
94 :type 'hook)
95
96
97(defcustom ebrowse-tree-buffer-name "*Tree*"
98 "*The default name of class tree buffers."
99 :group 'ebrowse-tree
100 :type 'string)
101
102
103(defcustom ebrowse--indentation 4
104 "*The amount by which subclasses are indented in the tree."
105 :group 'ebrowse-tree
106 :type 'integer)
107
108
109(defcustom ebrowse-source-file-column 40
110 "*The column in which source file names are displayed in the tree."
111 :group 'ebrowse-tree
112 :type 'integer)
113
114
115(defcustom ebrowse-tree-left-margin 2
116 "*Amount of space left at the left side of the tree display.
117This space is used to display markers."
118 :group 'ebrowse-tree
119 :type 'integer)
120
121
122\f
123(defgroup ebrowse-member nil
124 "Settings for member buffers."
125 :group 'ebrowse)
126
127
128(defcustom ebrowse-default-declaration-column 25
129 "*The column in which member declarations are displayed in member buffers."
130 :group 'ebrowse-member
131 :type 'integer)
132
133
134(defcustom ebrowse-default-column-width 25
135 "*The width of the columns in member buffers (short display form)."
136 :group 'ebrowse-member
137 :type 'integer)
138
139
140(defcustom ebrowse-member-buffer-name "*Members*"
141 "*The name of the buffer for member display."
142 :group 'ebrowse-member
143 :type 'string)
144
145
146(defcustom ebrowse-member-mode-hook nil
147 "*Run in each new member buffer."
148 :group 'ebrowse-member
149 :type 'hook)
150
151
152\f
153(defgroup ebrowse-faces nil
154 "Faces used by Ebrowse."
155 :group 'ebrowse)
156
157
4f2d55da 158(defface ebrowse-tree-mark
ea81d57e
DN
159 '((((min-colors 88)) (:foreground "red1"))
160 (t (:foreground "red")))
be0dbdab
GM
161 "*The face used for the mark character in the tree."
162 :group 'ebrowse-faces)
c4f6e489 163(define-obsolete-face-alias 'ebrowse-tree-mark-face 'ebrowse-tree-mark "22.1")
be0dbdab
GM
164
165
4f2d55da 166(defface ebrowse-root-class
ea81d57e
DN
167 '((((min-colors 88)) (:weight bold :foreground "blue1"))
168 (t (:weight bold :foreground "blue")))
be0dbdab
GM
169 "*The face used for root classes in the tree."
170 :group 'ebrowse-faces)
c4f6e489 171(define-obsolete-face-alias 'ebrowse-root-class-face 'ebrowse-root-class "22.1")
be0dbdab
GM
172
173
4f2d55da 174(defface ebrowse-file-name
be0dbdab
GM
175 '((t (:italic t)))
176 "*The face for filenames displayed in the tree."
177 :group 'ebrowse-faces)
c4f6e489 178(define-obsolete-face-alias 'ebrowse-file-name-face 'ebrowse-file-name "22.1")
be0dbdab
GM
179
180
4f2d55da 181(defface ebrowse-default
be0dbdab
GM
182 '((t nil))
183 "*Face for everything else in the tree not having other faces."
184 :group 'ebrowse-faces)
c4f6e489 185(define-obsolete-face-alias 'ebrowse-default-face 'ebrowse-default "22.1")
be0dbdab
GM
186
187
4f2d55da 188(defface ebrowse-member-attribute
ea81d57e
DN
189 '((((min-colors 88)) (:foreground "red1"))
190 (t (:foreground "red")))
be0dbdab
GM
191 "*Face used to display member attributes."
192 :group 'ebrowse-faces)
c4f6e489
GM
193(define-obsolete-face-alias 'ebrowse-member-attribute-face
194 'ebrowse-member-attribute "22.1")
be0dbdab
GM
195
196
4f2d55da 197(defface ebrowse-member-class
be0dbdab
GM
198 '((t (:foreground "purple")))
199 "*Face used to display the class title in member buffers."
200 :group 'ebrowse-faces)
c4f6e489
GM
201(define-obsolete-face-alias 'ebrowse-member-class-face
202 'ebrowse-member-class "22.1")
be0dbdab
GM
203
204
4f2d55da 205(defface ebrowse-progress
ea81d57e
DN
206 '((((min-colors 88)) (:background "blue1"))
207 (t (:background "blue")))
be0dbdab
GM
208 "*Face for progress indicator."
209 :group 'ebrowse-faces)
c4f6e489 210(define-obsolete-face-alias 'ebrowse-progress-face 'ebrowse-progress "22.1")
be0dbdab
GM
211
212
213\f
214;;; Utilities.
215
216(defun ebrowse-some (predicate vector)
217 "Return true if PREDICATE is true of some element of VECTOR.
218If so, return the value returned by PREDICATE."
219 (let ((length (length vector))
220 (i 0)
221 result)
222 (while (and (< i length) (not result))
223 (setq result (funcall predicate (aref vector i))
224 i (1+ i)))
225 result))
226
227
228(defun ebrowse-every (predicate vector)
229 "Return true if PREDICATE is true of every element of VECTOR."
230 (let ((length (length vector))
231 (i 0)
232 (result t))
233 (while (and (< i length) result)
234 (setq result (funcall predicate (aref vector i))
235 i (1+ i)))
236 result))
237
238
239(defun ebrowse-position (item list &optional test)
240 "Return the position of ITEM in LIST or nil if not found.
241Compare items with `eq' or TEST if specified."
242 (let ((i 0) found)
243 (cond (test
244 (while list
245 (when (funcall test item (car list))
246 (setq found i list nil))
247 (setq list (cdr list) i (1+ i))))
248 (t
249 (while list
250 (when (eq item (car list))
251 (setq found i list nil))
252 (setq list (cdr list) i (1+ i)))))
253 found))
254
255
256(defun ebrowse-delete-if-not (predicate list)
257 "Remove elements not satisfying PREDICATE from LIST and return the result.
258This is a destructive operation."
259 (let (result)
260 (while list
261 (let ((next (cdr list)))
262 (when (funcall predicate (car list))
263 (setq result (nconc result list))
264 (setf (cdr list) nil))
265 (setq list next)))
266 result))
267
268
be0dbdab
GM
269(defmacro ebrowse-output (&rest body)
270 "Eval BODY with a writable current buffer.
271Preserve buffer's modified state."
6f4070e0 272 (let ((modified (make-symbol "--ebrowse-output--")))
be0dbdab
GM
273 `(let (buffer-read-only (,modified (buffer-modified-p)))
274 (unwind-protect
275 (progn ,@body)
276 (set-buffer-modified-p ,modified)))))
277
278
279(defmacro ebrowse-ignoring-completion-case (&rest body)
280 "Eval BODY with `completion-ignore-case' bound to t."
281 `(let ((completion-ignore-case t))
282 ,@body))
283
284
285(defmacro ebrowse-save-selective (&rest body)
286 "Eval BODY with `selective-display' restored at the end."
287 (let ((var (make-symbol "var")))
288 `(let ((,var selective-display))
289 (unwind-protect
290 (progn ,@body)
291 (setq selective-display ,var)))))
292
293
294(defmacro ebrowse-for-all-trees (spec &rest body)
295 "For all trees in SPEC, eval BODY."
296 (let ((var (make-symbol "var"))
297 (spec-var (car spec))
298 (array (cadr spec)))
299 `(loop for ,var being the symbols of ,array
300 as ,spec-var = (get ,var 'ebrowse-root) do
301 (when (vectorp ,spec-var)
302 ,@body))))
303
304;;; Set indentation for macros above.
305
306(put 'ebrowse-output 'lisp-indent-hook 0)
307(put 'ebrowse-ignoring-completion-case 'lisp-indent-hook 0)
308(put 'ebrowse-save-selective 'lisp-indent-hook 0)
309(put 'ebrowse-for-all-trees 'lisp-indent-hook 1)
310
311
312(defsubst ebrowse-set-face (start end face)
313 "Set face of a region START END to FACE."
314 (overlay-put (make-overlay start end) 'face face))
315
316
317(defun ebrowse-completing-read-value (prompt table initial-input)
318 "Read a string in the minibuffer, with completion.
319Case is ignored in completions.
320
321PROMPT is a string to prompt with; normally it ends in a colon and a space.
322TABLE is an alist whose elements' cars are strings, or an obarray.
323TABLE can also be a function to do the completion itself.
324If INITIAL-INPUT is non-nil, insert it in the minibuffer initially.
325If it is (STRING . POSITION), the initial input
326is STRING, but point is placed POSITION characters into the string."
327 (ebrowse-ignoring-completion-case
328 (completing-read prompt table nil t initial-input)))
329
330
331(defun ebrowse-value-in-buffer (sym buffer)
332 "Return the value of SYM in BUFFER."
333 (let ((old-buffer (current-buffer)))
334 (unwind-protect
335 (progn
336 (set-buffer buffer)
337 (symbol-value sym))
338 (set-buffer old-buffer))))
339
340
341(defun ebrowse-rename-buffer (new-name)
342 "Rename current buffer to NEW-NAME.
343If a buffer with name NEW-NAME already exists, delete it first."
344 (let ((old-buffer (get-buffer new-name)))
345 (unless (eq old-buffer (current-buffer))
346 (when old-buffer
347 (save-excursion (kill-buffer old-buffer)))
348 (rename-buffer new-name))))
349
350
351(defun ebrowse-trim-string (string)
352 "Return a copy of STRING with leading white space removed.
353Replace sequences of newlines with a single space."
354 (when (string-match "^[ \t\n\r]+" string)
355 (setq string (substring string (match-end 0))))
356 (loop while (string-match "[\n]+" string)
357 finally return string do
358 (setq string (replace-match " " nil t string))))
359
360
361(defun ebrowse-width-of-drawable-area ()
362 "Return the width of the display area for the current buffer.
363If buffer is displayed in a window, use that window's width,
364otherwise use the current frame's width."
365 (let ((window (get-buffer-window (current-buffer))))
366 (if window
367 (window-width window)
368 (frame-width))))
369
370\f
371;;; Structure definitions
372
373(defstruct (ebrowse-hs (:type vector) :named)
183c2d42 374 "Header structure found at the head of BROWSE files."
be0dbdab
GM
375 ;; A version string that is compared against the version number of
376 ;; the Lisp package when the file is loaded. This is done to
377 ;; detect file format changes.
378 version
183c2d42 379 ;; Command line options used for producing the BROWSE file.
be0dbdab
GM
380 command-line-options
381 ;; The following slot is currently not used. It's kept to keep
382 ;; the file format compatible.
383 unused
384 ;; A slot that is filled out after the tree is loaded. This slot is
385 ;; set to a hash table mapping members to lists of classes in which
386 ;; they are defined.
387 member-table)
388
106ba1bb 389
be0dbdab
GM
390(defstruct (ebrowse-ts (:type vector) :named)
391 "Tree structure.
106ba1bb 392Following the header structure, a BROWSE file contains a number
be0dbdab
GM
393of `ebrowse-ts' structures, each one describing one root class of
394the class hierarchy with all its subclasses."
395 ;; A `ebrowse-cs' structure describing the root class.
396 class
397 ;; A list of `ebrowse-ts' structures for all subclasses.
398 subclasses
399 ;; Lists of `ebrowse-ms' structures for each member in a group of
400 ;; members.
401 member-variables member-functions static-variables static-functions
402 friends types
403 ;; List of `ebrowse-ts' structures for base classes. This slot is
404 ;; filled at load time.
405 base-classes
406 ;; A marker slot used in the tree buffer (can be saved back to disk.
407 mark)
408
409
410(defstruct (ebrowse-bs (:type vector) :named)
411 "Common sub-structure.
412A common structure defining an occurrence of some name in the
413source files."
414 ;; The class or member name as a string constant
415 name
416 ;; An optional string for the scope of nested classes or for
417 ;; namespaces.
418 scope
419 ;; Various flags describing properties of classes/members, e.g. is
420 ;; template, is const etc.
421 flags
422 ;; File in which the entity is found. If this is part of a
423 ;; `ebrowse-ms' member description structure, and FILE is nil, then
424 ;; search for the name in the SOURCE-FILE of the members class.
425 file
426 ;; Regular expression to search for. This slot can be a number in
427 ;; which case the number is the file position at which the regular
428 ;; expression is found in a separate regexp file (see the header
429 ;; structure). This slot can be nil in which case the regular
430 ;; expression will be generated from the class/member name.
431 pattern
432 ;; The buffer position at which the search for the class or member
433 ;; will start.
434 point)
435
436
437(defstruct (ebrowse-cs (:include ebrowse-bs) (:type vector) :named)
438 "Class structure.
439This is the structure stored in the CLASS slot of a `ebrowse-ts'
440structure. It describes the location of the class declaration."
441 source-file)
442
443
444(defstruct (ebrowse-ms (:include ebrowse-bs) (:type vector) :named)
445 "Member structure.
446This is the structure describing a single member. The `ebrowse-ts'
447structure contains various lists for the different types of
448members."
449 ;; Public, protected, private
450 visibility
451 ;; The file in which the member's definition can be found.
452 definition-file
453 ;; Same as PATTERN above, but for the member definition.
454 definition-pattern
455 ;; Same as POINT above but for member definition.
456 definition-point)
457
458
459\f
460;;; Some macros to access the FLAGS slot of a MEMBER.
461
462(defsubst ebrowse-member-bit-set-p (member bit)
463 "Value is non-nil if MEMBER's bit BIT is set."
464 (/= 0 (logand (ebrowse-bs-flags member) bit)))
465
466
467(defsubst ebrowse-virtual-p (member)
468 "Value is non-nil if MEMBER is virtual."
469 (ebrowse-member-bit-set-p member 1))
470
471
472(defsubst ebrowse-inline-p (member)
473 "Value is non-nil if MEMBER is inline."
474 (ebrowse-member-bit-set-p member 2))
475
476
477(defsubst ebrowse-const-p (member)
478 "Value is non-nil if MEMBER is const."
479 (ebrowse-member-bit-set-p member 4))
480
481
482(defsubst ebrowse-pure-virtual-p (member)
483 "Value is non-nil if MEMBER is a pure virtual function."
484 (ebrowse-member-bit-set-p member 8))
485
486
487(defsubst ebrowse-mutable-p (member)
488 "Value is non-nil if MEMBER is mutable."
489 (ebrowse-member-bit-set-p member 16))
490
491
492(defsubst ebrowse-template-p (member)
493 "Value is non-nil if MEMBER is a template."
494 (ebrowse-member-bit-set-p member 32))
495
496
497(defsubst ebrowse-explicit-p (member)
498 "Value is non-nil if MEMBER is explicit."
499 (ebrowse-member-bit-set-p member 64))
500
501
502(defsubst ebrowse-throw-list-p (member)
503 "Value is non-nil if MEMBER has a throw specification."
504 (ebrowse-member-bit-set-p member 128))
505
506
507(defsubst ebrowse-extern-c-p (member)
508 "Value is non-nil if MEMBER.is `extern \"C\"'."
509 (ebrowse-member-bit-set-p member 256))
510
511
512(defsubst ebrowse-define-p (member)
513 "Value is non-nil if MEMBER is a define."
514 (ebrowse-member-bit-set-p member 512))
515
516
517(defconst ebrowse-version-string "ebrowse 5.0"
183c2d42 518 "Version string expected in BROWSE files.")
be0dbdab
GM
519
520
521(defconst ebrowse-globals-name "*Globals*"
522 "The name used for the surrogate class.containing global entities.
523This must be the same that `ebrowse' uses.")
524
525
526(defvar ebrowse--last-regexp nil
527 "Last regular expression searched for in tree and member buffers.
52dcc114 528Each tree and member buffer maintains its own search history.")
be0dbdab
GM
529(make-variable-buffer-local 'ebrowse--last-regexp)
530
531
532(defconst ebrowse-member-list-accessors
533 '(ebrowse-ts-member-variables
534 ebrowse-ts-member-functions
535 ebrowse-ts-static-variables
536 ebrowse-ts-static-functions
537 ebrowse-ts-friends
538 ebrowse-ts-types)
539 "List of accessors for member lists.
540Each element is the symbol of an accessor function.
541The nth element must be the accessor for the nth member list
542in an `ebrowse-ts' structure.")
543
544
545;;; FIXME: Add more doc strings for the buffer-local variables below.
546
547(defvar ebrowse--tree-obarray nil
548 "Obarray holding all `ebrowse-ts' structures of a class tree.
549Buffer-local in Ebrowse buffers.")
550
551
552(defvar ebrowse--tags-file-name nil
183c2d42 553 "File from which BROWSE file was loaded.
be0dbdab
GM
554Buffer-local in Ebrowse buffers.")
555
556
557(defvar ebrowse--header nil
558 "Header structure of type `ebrowse-hs' of a class tree.
559Buffer-local in Ebrowse buffers.")
560
561
562(defvar ebrowse--frozen-flag nil
563 "Non-nil means an Ebrowse buffer won't be reused.
564Buffer-local in Ebrowse buffers.")
106ba1bb 565
be0dbdab
GM
566
567(defvar ebrowse--show-file-names-flag nil
568 "Non-nil means show file names in a tree buffer.
569Buffer-local in Ebrowse tree buffers.")
570
571
572(defvar ebrowse--long-display-flag nil
573 "Non-nil means show members in long display form.
574Buffer-local in Ebrowse member buffers.")
575
576
577(defvar ebrowse--n-columns nil
578 "Number of columns to display for short member display form.
579Buffer-local in Ebrowse member buffers.")
580
581
582(defvar ebrowse--column-width nil
583 "Width of a columns to display for short member display form.
584Buffer-local in Ebrowse member buffers.")
585
106ba1bb 586
be0dbdab
GM
587(defvar ebrowse--virtual-display-flag nil
588 "Non-nil means display virtual members in a member buffer.
589Buffer-local in Ebrowse member buffers.")
590
591
592(defvar ebrowse--inline-display-flag nil
593 "Non-nil means display inline members in a member buffer.
594Buffer-local in Ebrowse member buffers.")
595
596
597(defvar ebrowse--const-display-flag nil
598 "Non-nil means display const members in a member buffer.
599Buffer-local in Ebrowse member buffers.")
600
601
602(defvar ebrowse--pure-display-flag nil
603 "Non-nil means display pure virtual members in a member buffer.
604Buffer-local in Ebrowse member buffers.")
605
606
607(defvar ebrowse--filters nil
608 "Filter for display of public, protected, and private members.
609This is a vector of three elements. An element nil means the
610corresponding members are not shown.
611Buffer-local in Ebrowse member buffers.")
612
613
614(defvar ebrowse--show-inherited-flag nil
615 "Non-nil means display inherited members in a member buffer.
616Buffer-local in Ebrowse member buffers.")
617
618
619(defvar ebrowse--attributes-flag nil
620 "Non-nil means display member attributes in a member buffer.
621Buffer-local in Ebrowse member buffers.")
622
623
624(defvar ebrowse--source-regexp-flag nil
625 "Non-nil means display member regexps in a member buffer.
626Buffer-local in Ebrowse member buffers.")
627
628
629(defvar ebrowse--displayed-class nil
630 "Class displayed in a member buffer, a `ebrowse-ts' structure.
631Buffer-local in Ebrowse member buffers.")
632
633
634(defvar ebrowse--accessor nil
635 "Member list displayed in a member buffer.
636This is a symbol whose function definition is an accessor for the
637member list in `ebrowse-cs' structures.
638Buffer-local in Ebrowse member buffers.")
639
640
641(defvar ebrowse--member-list nil
642 "The list of `ebrowse-ms' structures displayed in a member buffer.
643Buffer-local in Ebrowse member buffers.")
644
645
646(defvar ebrowse--decl-column nil
647 "Column in which declarations are displayed in member buffers.
648Buffer-local in Ebrowse member buffers.")
649
650
be0dbdab
GM
651(defvar ebrowse--frame-configuration nil
652 "Frame configuration saved when viewing a class/member in another frame.
653Buffer-local in Ebrowse buffers.")
654
655
656(defvar ebrowse--view-exit-action nil
657 "Action to perform after viewing a class/member.
658Either `kill-buffer' or nil.
659Buffer-local in Ebrowse buffers.")
660
661
662(defvar ebrowse--tree nil
663 "Class tree.
664Buffer-local in Ebrowse buffers.")
665
666
be0dbdab
GM
667;;; Temporaries used to communicate with `ebrowse-find-pattern'.
668
669(defvar ebrowse-temp-position-to-view nil)
670(defvar ebrowse-temp-info-to-view nil)
671
672
673(defvar ebrowse-tree-mode-map ()
674 "The keymap used in tree mode buffers.")
675
676
677(defvar ebrowse--member-mode-strings nil
678 "Strings displayed in the mode line of member buffers.")
679
680
681(defvar ebrowse-member-mode-map ()
682 "The keymap used in the member buffers.")
683
684
685;;; Define mode line titles for each member list.
686
687(put 'ebrowse-ts-member-variables 'ebrowse-title "Member Variables")
688(put 'ebrowse-ts-member-functions 'ebrowse-title "Member Functions")
689(put 'ebrowse-ts-static-variables 'ebrowse-title "Static Variables")
690(put 'ebrowse-ts-static-functions 'ebrowse-title "Static Functions")
691(put 'ebrowse-ts-friends 'ebrowse-title "Friends")
692(put 'ebrowse-ts-types 'ebrowse-title "Types")
693
694(put 'ebrowse-ts-member-variables 'ebrowse-global-title "Global Variables")
695(put 'ebrowse-ts-member-functions 'ebrowse-global-title "Global Functions")
696(put 'ebrowse-ts-static-variables 'ebrowse-global-title "Static Variables")
697(put 'ebrowse-ts-static-functions 'ebrowse-global-title "Static Functions")
698(put 'ebrowse-ts-friends 'ebrowse-global-title "Defines")
699(put 'ebrowse-ts-types 'ebrowse-global-title "Types")
700
701
702\f
703;;; Operations on `ebrowse-ts' structures
704
705(defun ebrowse-files-table (&optional marked-only)
706 "Return an obarray containing all files mentioned in the current tree.
707The tree is expected in the buffer-local variable `ebrowse--tree-obarray'.
708MARKED-ONLY non-nil means include marked classes only."
709 (let ((files (make-hash-table :test 'equal))
710 (i -1))
711 (ebrowse-for-all-trees (tree ebrowse--tree-obarray)
712 (when (or (not marked-only) (ebrowse-ts-mark tree))
713 (let ((class (ebrowse-ts-class tree)))
714 (when (zerop (% (incf i) 20))
715 (ebrowse-show-progress "Preparing file list" (zerop i)))
716 ;; Add files mentioned in class description
717 (let ((source-file (ebrowse-cs-source-file class))
718 (file (ebrowse-cs-file class)))
719 (when source-file
720 (puthash source-file source-file files))
721 (when file
722 (puthash file file files))
723 ;; For all member lists in this class
724 (loop for accessor in ebrowse-member-list-accessors do
725 (loop for m in (funcall accessor tree)
726 for file = (ebrowse-ms-file m)
727 for def-file = (ebrowse-ms-definition-file m) do
728 (when file
729 (puthash file file files))
730 (when def-file
731 (puthash def-file def-file files))))))))
732 files))
733
734
735(defun ebrowse-files-list (&optional marked-only)
736 "Return a list containing all files mentioned in a tree.
737MARKED-ONLY non-nil means include marked classes only."
738 (let (list)
e02f48d7 739 (maphash (lambda (file _dummy) (setq list (cons file list)))
be0dbdab
GM
740 (ebrowse-files-table marked-only))
741 list))
742
743
744(defun* ebrowse-marked-classes-p ()
745 "Value is non-nil if any class in the current class tree is marked."
746 (ebrowse-for-all-trees (tree ebrowse--tree-obarray)
747 (when (ebrowse-ts-mark tree)
748 (return-from ebrowse-marked-classes-p tree))))
749
750
751(defsubst ebrowse-globals-tree-p (tree)
752 "Return t if TREE is the one for global entities."
753 (string= (ebrowse-bs-name (ebrowse-ts-class tree))
754 ebrowse-globals-name))
755
756
757(defsubst ebrowse-qualified-class-name (class)
758 "Return the name of CLASS with scope prepended, if any."
759 (if (ebrowse-cs-scope class)
760 (concat (ebrowse-cs-scope class) "::" (ebrowse-cs-name class))
761 (ebrowse-cs-name class)))
762
763
764(defun ebrowse-tree-obarray-as-alist (&optional qualified-names-p)
765 "Return an alist describing all classes in a tree.
766Each elements in the list has the form (CLASS-NAME . TREE).
767CLASS-NAME is the name of the class. TREE is the
768class tree whose root is QUALIFIED-CLASS-NAME.
769QUALIFIED-NAMES-P non-nil means return qualified names as CLASS-NAME.
770The class tree is found in the buffer-local variable `ebrowse--tree-obarray'."
771 (let (alist)
772 (if qualified-names-p
773 (ebrowse-for-all-trees (tree ebrowse--tree-obarray)
774 (setq alist
775 (acons (ebrowse-qualified-class-name (ebrowse-ts-class tree))
776 tree alist)))
777 (ebrowse-for-all-trees (tree ebrowse--tree-obarray)
778 (setq alist
779 (acons (ebrowse-cs-name (ebrowse-ts-class tree))
780 tree alist))))
781 alist))
782
783
784(defun ebrowse-sort-tree-list (list)
785 "Sort a LIST of `ebrowse-ts' structures by qualified class names."
786 (sort list
e02f48d7
JB
787 (lambda (a b)
788 (string< (ebrowse-qualified-class-name (ebrowse-ts-class a))
789 (ebrowse-qualified-class-name (ebrowse-ts-class b))))))
be0dbdab
GM
790
791
792(defun ebrowse-class-in-tree (class tree)
793 "Search for a class with name CLASS in TREE.
8b3a75ac
EZ
794If CLASS is found, return the tail of TREE starting at CLASS. This function
795is used during the load phase where classes appended to a file replace older
796class information."
be0dbdab
GM
797 (let ((tclass (ebrowse-ts-class class))
798 found)
799 (while (and tree (not found))
8b3a75ac
EZ
800 (let ((root-ptr tree))
801 (when (string= (ebrowse-qualified-class-name (ebrowse-ts-class (car root-ptr)))
be0dbdab 802 (ebrowse-qualified-class-name tclass))
8b3a75ac 803 (setq found root-ptr))
be0dbdab
GM
804 (setq tree (cdr tree))))
805 found))
806
807
808(defun ebrowse-base-classes (tree)
809 "Return list of base-classes of TREE by searching subclass lists.
106ba1bb 810This function must be used instead of the struct slot
be0dbdab
GM
811`base-classes' to access the base-class list directly because it
812computes this information lazily."
813 (or (ebrowse-ts-base-classes tree)
814 (setf (ebrowse-ts-base-classes tree)
815 (loop with to-search = (list tree)
816 with result = nil
817 as search = (pop to-search)
818 while search finally return result
819 do (ebrowse-for-all-trees (ti ebrowse--tree-obarray)
820 (when (memq search (ebrowse-ts-subclasses ti))
821 (unless (memq ti result)
822 (setq result (nconc result (list ti))))
823 (push ti to-search)))))))
824
825
826(defun ebrowse-direct-base-classes (tree)
827 "Return the list of direct super classes of TREE."
828 (let (result)
829 (dolist (s (ebrowse-base-classes tree))
830 (when (memq tree (ebrowse-ts-subclasses s))
831 (setq result (cons s result))))
832 result))
833
834
835\f
836;;; Operations on MEMBER structures/lists
837
838(defun ebrowse-name/accessor-alist (tree accessor)
839 "Return an alist containing all members of TREE in group ACCESSOR.
840ACCESSOR is the accessor function for the member list.
841Elements of the result have the form (NAME . ACCESSOR), where NAME
842is the member name."
843 (loop for member in (funcall accessor tree)
844 collect (cons (ebrowse-ms-name member) accessor)))
845
846
847(defun ebrowse-name/accessor-alist-for-visible-members ()
848 "Return an alist describing all members visible in the current buffer.
849Each element of the list has the form (MEMBER-NAME . ACCESSOR),
850where MEMBER-NAME is the member's name, and ACCESSOR is the struct
851accessor with which the member's list can be accessed in an `ebrowse-ts'
852structure. The list includes inherited members if these are visible."
853 (let* ((list (ebrowse-name/accessor-alist ebrowse--displayed-class
854 ebrowse--accessor)))
855 (if ebrowse--show-inherited-flag
856 (nconc list
857 (loop for tree in (ebrowse-base-classes
858 ebrowse--displayed-class)
859 nconc (ebrowse-name/accessor-alist
860 tree ebrowse--accessor)))
861 list)))
862
863
864(defun ebrowse-name/accessor-alist-for-class-members ()
865 "Like `ebrowse-name/accessor-alist-for-visible-members'.
866This function includes members of base classes if base class members
867are visible in the buffer."
868 (let (list)
869 (dolist (func ebrowse-member-list-accessors list)
870 (setq list (nconc list (ebrowse-name/accessor-alist
871 ebrowse--displayed-class func)))
872 (when ebrowse--show-inherited-flag
873 (dolist (class (ebrowse-base-classes ebrowse--displayed-class))
874 (setq list
875 (nconc list (ebrowse-name/accessor-alist class func))))))))
876
877\f
878;;; Progress indication
879
880(defvar ebrowse-n-boxes 0)
881(defconst ebrowse-max-boxes 60)
882
883(defun ebrowse-show-progress (title &optional start)
884 "Display a progress indicator.
885TITLE is the title of the progress message. START non-nil means
886this is the first progress message displayed."
887 (let (message-log-max)
888 (when start (setq ebrowse-n-boxes 0))
889 (setq ebrowse-n-boxes (mod (1+ ebrowse-n-boxes) ebrowse-max-boxes))
274f1353
DK
890 (message "%s: %s" title
891 (propertize (make-string ebrowse-n-boxes
892 (if (display-color-p) ?\ ?+))
893 'face 'ebrowse-progress))))
be0dbdab
GM
894
895\f
896;;; Reading a tree from disk
897
be0dbdab 898(defun ebrowse-read ()
106ba1bb 899 "Read `ebrowse-hs' and `ebrowse-ts' structures in the current buffer.
be0dbdab
GM
900Return a list (HEADER TREE) where HEADER is the file header read
901and TREE is a list of `ebrowse-ts' structures forming the class tree."
902 (let ((header (condition-case nil
903 (read (current-buffer))
904 (error (error "No Ebrowse file header found"))))
905 tree)
906 ;; Check file format.
907 (unless (ebrowse-hs-p header)
908 (error "No Ebrowse file header found"))
909 (unless (string= (ebrowse-hs-version header) ebrowse-version-string)
910 (error "File has wrong version `%s' (`%s' expected)"
911 (ebrowse-hs-version header) ebrowse-version-string))
912 ;; Read Lisp objects. Temporarily increase `gc-cons-threshold' to
913 ;; prevent a GC that would not free any memory.
914 (let ((gc-cons-threshold 2000000))
86b58346 915 (while (not (progn (skip-chars-forward " \t\n\r") (eobp)))
be0dbdab 916 (let* ((root (read (current-buffer)))
8b3a75ac 917 (old-root-ptr (ebrowse-class-in-tree root tree)))
be0dbdab 918 (ebrowse-show-progress "Reading data" (null tree))
8b3a75ac
EZ
919 (if old-root-ptr
920 (setcar old-root-ptr root)
be0dbdab
GM
921 (push root tree)))))
922 (garbage-collect)
923 (list header tree)))
924
925
e02f48d7 926(defun ebrowse-revert-tree-buffer-from-file (_ignore-auto-save noconfirm)
be0dbdab
GM
927 "Function installed as `revert-buffer-function' in tree buffers.
928See that variable's documentation for the meaning of IGNORE-AUTO-SAVE and
929NOCONFIRM."
86b58346
GM
930 (when (or noconfirm (yes-or-no-p "Revert tree from disk? "))
931 (loop for member-buffer in (ebrowse-same-tree-member-buffer-list)
932 do (kill-buffer member-buffer))
933 (erase-buffer)
55def742
RS
934 (with-no-warnings
935 (insert-file (or buffer-file-name ebrowse--tags-file-name)))
86b58346
GM
936 (ebrowse-tree-mode)
937 (current-buffer)))
be0dbdab 938
106ba1bb 939
e02f48d7 940(defun ebrowse-create-tree-buffer (tree tags-file header classes pop)
be0dbdab
GM
941 "Create a new tree buffer for tree TREE.
942The tree was loaded from file TAGS-FILE.
943HEADER is the header structure of the file.
e02f48d7 944CLASSES is an obarray with a symbol for each class in the tree.
be0dbdab 945POP non-nil means popup the buffer up at the end.
be0dbdab 946Return the buffer created."
86b58346
GM
947 (let ((name ebrowse-tree-buffer-name))
948 (set-buffer (get-buffer-create name))
be0dbdab 949 (ebrowse-tree-mode)
86b58346 950 (setq ebrowse--tree tree
be0dbdab 951 ebrowse--tags-file-name tags-file
e02f48d7 952 ebrowse--tree-obarray classes
86b58346
GM
953 ebrowse--header header
954 ebrowse--frozen-flag nil)
be0dbdab
GM
955 (ebrowse-redraw-tree)
956 (set-buffer-modified-p nil)
86b58346
GM
957 (case pop
958 (switch (switch-to-buffer name))
959 (pop (pop-to-buffer name)))
be0dbdab
GM
960 (current-buffer)))
961
962
963\f
964;;; Operations for member obarrays
965
966(defun ebrowse-fill-member-table ()
967 "Return an obarray holding all members of all classes in the current tree.
968
969For each member, a symbol is added to the obarray. Members are
970extracted from the buffer-local tree `ebrowse--tree-obarray'.
971
972Each symbol has its property `ebrowse-info' set to a list (TREE MEMBER-LIST
973MEMBER) where TREE is the tree in which the member is defined,
974MEMBER-LIST is a symbol describing the member list in which the member
975is found, and MEMBER is a MEMBER structure describing the member.
976
977The slot `member-table' of the buffer-local header structure of
978type `ebrowse-hs' is set to the resulting obarray."
979 (let ((members (make-hash-table :test 'equal))
980 (i -1))
981 (setf (ebrowse-hs-member-table ebrowse--header) nil)
982 (garbage-collect)
983 ;; For all classes...
984 (ebrowse-for-all-trees (c ebrowse--tree-obarray)
985 (when (zerop (% (incf i) 10))
986 (ebrowse-show-progress "Preparing member lookup" (zerop i)))
987 (loop for f in ebrowse-member-list-accessors do
988 (loop for m in (funcall f c) do
989 (let* ((member-name (ebrowse-ms-name m))
990 (value (gethash member-name members)))
991 (push (list c f m) value)
992 (puthash member-name value members)))))
993 (setf (ebrowse-hs-member-table ebrowse--header) members)))
994
995
996(defun ebrowse-member-table (header)
69bfc6c0 997 "Return the member obarray. Build it if it hasn't been set up yet.
be0dbdab
GM
998HEADER is the tree header structure of the class tree."
999 (when (null (ebrowse-hs-member-table header))
1000 (loop for buffer in (ebrowse-browser-buffer-list)
1001 until (eq header (ebrowse-value-in-buffer 'ebrowse--header buffer))
1002 finally do
9a529312 1003 (with-current-buffer buffer
be0dbdab
GM
1004 (ebrowse-fill-member-table))))
1005 (ebrowse-hs-member-table header))
1006
1007
1008\f
1009;;; Operations on TREE obarrays
1010
1011(defun ebrowse-build-tree-obarray (tree)
1012 "Make sure every class in TREE is represented by a unique object.
1013Build obarray of all classes in TREE."
1014 (let ((classes (make-vector 127 0)))
1015 ;; Add root classes...
1016 (loop for root in tree
1017 as sym =
1018 (intern (ebrowse-qualified-class-name (ebrowse-ts-class root)) classes)
1019 do (unless (get sym 'ebrowse-root)
1020 (setf (get sym 'ebrowse-root) root)))
1021 ;; Process subclasses
1022 (ebrowse-insert-supers tree classes)
1023 classes))
1024
1025
1026(defun ebrowse-insert-supers (tree classes)
1027 "Build base class lists in class tree TREE.
1028CLASSES is an obarray used to collect classes.
1029
1030Helper function for `ebrowse-build-tree-obarray'. Base classes should
1031be ordered so that immediate base classes come first, then the base
1032class of the immediate base class and so on. This means that we must
1033construct the base-class list top down with adding each level at the
1034beginning of the base-class list.
1035
1036We have to be cautious here not to end up in an infinite recursion
1037if for some reason a circle is in the inheritance graph."
1038 (loop for class in tree
1039 as subclasses = (ebrowse-ts-subclasses class) do
1040 ;; Make sure every class is represented by a unique object
1041 (loop for subclass on subclasses
1042 as sym = (intern
1043 (ebrowse-qualified-class-name (ebrowse-ts-class (car subclass)))
1044 classes)
1045 as next = nil
1046 do
1047 ;; Replace the subclass tree with the one found in
1048 ;; CLASSES if there is already an entry for that class
1049 ;; in it. Otherwise make a new entry.
1050 ;;
1051 ;; CAVEAT: If by some means (e.g., use of the
1052 ;; preprocessor in class declarations, a name is marked
1053 ;; as a subclass of itself on some path, we would end up
1054 ;; in an endless loop. We have to omit subclasses from
1055 ;; the recursion that already have been processed.
1056 (if (get sym 'ebrowse-root)
1057 (setf (car subclass) (get sym 'ebrowse-root))
1058 (setf (get sym 'ebrowse-root) (car subclass))))
1059 ;; Process subclasses
1060 (ebrowse-insert-supers subclasses classes)))
1061
1062\f
1063;;; Tree buffers
1064
1065(unless ebrowse-tree-mode-map
1066 (let ((map (make-keymap)))
1067 (setf ebrowse-tree-mode-map map)
1068 (suppress-keymap map)
1069
f4a2b0a4 1070 (when (display-mouse-p)
be0dbdab
GM
1071 (define-key map [down-mouse-3] 'ebrowse-mouse-3-in-tree-buffer)
1072 (define-key map [mouse-2] 'ebrowse-mouse-2-in-tree-buffer)
1073 (define-key map [down-mouse-1] 'ebrowse-mouse-1-in-tree-buffer))
106ba1bb 1074
be0dbdab
GM
1075 (let ((map1 (make-sparse-keymap)))
1076 (suppress-keymap map1 t)
1077 (define-key map "L" map1)
1078 (define-key map1 "d" 'ebrowse-tree-command:show-friends)
1079 (define-key map1 "f" 'ebrowse-tree-command:show-member-functions)
1080 (define-key map1 "F" 'ebrowse-tree-command:show-static-member-functions)
1081 (define-key map1 "t" 'ebrowse-tree-command:show-types)
1082 (define-key map1 "v" 'ebrowse-tree-command:show-member-variables)
1083 (define-key map1 "V" 'ebrowse-tree-command:show-static-member-variables))
1084
1085 (let ((map1 (make-sparse-keymap)))
1086 (suppress-keymap map1 t)
1087 (define-key map "M" map1)
1088 (define-key map1 "a" 'ebrowse-mark-all-classes)
1089 (define-key map1 "t" 'ebrowse-toggle-mark-at-point))
1090
1091 (let ((map1 (make-sparse-keymap)))
1092 (suppress-keymap map1 t)
1093 (define-key map "T" map1)
1094 (define-key map1 "f" 'ebrowse-toggle-file-name-display)
1095 (define-key map1 "s" 'ebrowse-show-file-name-at-point)
1096 (define-key map1 "w" 'ebrowse-set-tree-indentation)
1097 (define-key map "x" 'ebrowse-statistics))
1098
1099 (define-key map "n" 'ebrowse-repeat-member-search)
1100 (define-key map "q" 'bury-buffer)
1101 (define-key map "*" 'ebrowse-expand-all)
1102 (define-key map "+" 'ebrowse-expand-branch)
1103 (define-key map "-" 'ebrowse-collapse-branch)
1104 (define-key map "/" 'ebrowse-read-class-name-and-go)
1105 (define-key map " " 'ebrowse-view-class-declaration)
1106 (define-key map "?" 'describe-mode)
1107 (define-key map "\C-i" 'ebrowse-pop/switch-to-member-buffer-for-same-tree)
1108 (define-key map "\C-k" 'ebrowse-remove-class-at-point)
1109 (define-key map "\C-l" 'ebrowse-redraw-tree)
1110 (define-key map "\C-m" 'ebrowse-find-class-declaration)))
1111
1112
1113\f
1114;;; Tree-mode - mode for tree buffers
1115
1116;;;###autoload
175069ef 1117(define-derived-mode ebrowse-tree-mode special-mode "Ebrowse-Tree"
be0dbdab
GM
1118 "Major mode for Ebrowse class tree buffers.
1119Each line corresponds to a class in a class tree.
1120Letters do not insert themselves, they are commands.
1121File operations in the tree buffer work on class tree data structures.
1122E.g.\\[save-buffer] writes the tree to the file it was loaded from.
1123
1124Tree mode key bindings:
1125\\{ebrowse-tree-mode-map}"
8b2affc5 1126 (let* ((ident (propertized-buffer-identification "C++ Tree"))
175069ef
SM
1127 (inhibit-read-only t)
1128 header tree)
106ba1bb 1129
a4382f98 1130 (buffer-disable-undo)
106ba1bb 1131
86b58346
GM
1132 (unless (zerop (buffer-size))
1133 (goto-char (point-min))
3c2fbb99 1134 (multiple-value-setq (header tree) (values-list (ebrowse-read)))
86b58346
GM
1135 (message "Sorting. Please be patient...")
1136 (setq tree (ebrowse-sort-tree-list tree))
1137 (erase-buffer)
1138 (message nil))
106ba1bb 1139
175069ef
SM
1140 (set (make-local-variable 'ebrowse--show-file-names-flag) nil)
1141 (set (make-local-variable 'ebrowse--tree-obarray) (make-vector 127 0))
1142 (set (make-local-variable 'ebrowse--frozen-flag) nil)
1143 (setq mode-line-buffer-identification ident)
1144 (setq buffer-read-only t)
1145 (setq selective-display t)
1146 (setq selective-display-ellipses t)
1147 (set (make-local-variable 'revert-buffer-function)
1148 #'ebrowse-revert-tree-buffer-from-file)
1149 (set (make-local-variable 'ebrowse--header) header)
1150 (set (make-local-variable 'ebrowse--tree) tree)
1151 (set (make-local-variable 'ebrowse--tags-file-name) buffer-file-name)
1152 (set (make-local-variable 'ebrowse--tree-obarray)
1153 (and tree (ebrowse-build-tree-obarray tree)))
1154 (set (make-local-variable 'ebrowse--frozen-flag) nil)
1155
1156 (add-hook 'local-write-file-hooks 'ebrowse-write-file-hook-fn nil t)
86b58346
GM
1157 (modify-syntax-entry ?_ (char-to-string (char-syntax ?a)))
1158 (when tree
1159 (ebrowse-redraw-tree)
175069ef 1160 (set-buffer-modified-p nil))))
106ba1bb 1161
be0dbdab
GM
1162
1163
1164(defun ebrowse-update-tree-buffer-mode-line ()
1165 "Update the tree buffer mode line."
be0dbdab
GM
1166 (ebrowse-rename-buffer (if ebrowse--frozen-flag
1167 (ebrowse-frozen-tree-buffer-name
1168 ebrowse--tags-file-name)
1169 ebrowse-tree-buffer-name))
1170 (force-mode-line-update))
1171
1172
1173\f
1174;;; Removing classes from trees
1175
1176(defun ebrowse-remove-class-and-kill-member-buffers (tree class)
1177 "Remove from TREE class CLASS.
1178Kill all member buffers still containing a reference to the class."
1179 (let ((sym (intern-soft (ebrowse-cs-name (ebrowse-ts-class class))
1180 ebrowse--tree-obarray)))
1181 (setf tree (delq class tree)
1182 (get sym 'ebrowse-root) nil)
1183 (dolist (root tree)
1184 (setf (ebrowse-ts-subclasses root)
1185 (delq class (ebrowse-ts-subclasses root))
1186 (ebrowse-ts-base-classes root) nil)
1187 (ebrowse-remove-class-and-kill-member-buffers
1188 (ebrowse-ts-subclasses root) class))
1189 (ebrowse-kill-member-buffers-displaying class)
1190 tree))
1191
1192
1193(defun ebrowse-remove-class-at-point (forced)
1194 "Remove the class point is on from the class tree.
1195Do not ask for confirmation if FORCED is non-nil."
1196 (interactive "P")
1197 (let* ((class (ebrowse-tree-at-point))
1198 (class-name (ebrowse-cs-name (ebrowse-ts-class class)))
1199 (subclasses (ebrowse-ts-subclasses class)))
1200 (cond ((or forced
1201 (y-or-n-p (concat "Delete class " class-name "? ")))
1202 (setf ebrowse--tree (ebrowse-remove-class-and-kill-member-buffers
1203 ebrowse--tree class))
1204 (set-buffer-modified-p t)
1205 (message "%s %sdeleted." class-name
1206 (if subclasses "and derived classes " ""))
1207 (ebrowse-redraw-tree))
1208 (t (message "Aborted")))))
1209
1210
1211\f
1212;;; Marking classes in the tree buffer
1213
1214(defun ebrowse-toggle-mark-at-point (&optional n-times)
1215 "Toggle mark for class cursor is on.
1216If given a numeric N-TIMES argument, mark that many classes."
1217 (interactive "p")
e02f48d7 1218 (let (to-change)
be0dbdab
GM
1219 ;; Get the classes whose mark must be toggled. Note that
1220 ;; ebrowse-tree-at-point might issue an error.
e02f48d7
JB
1221 (ignore-errors
1222 (loop repeat (or n-times 1)
1223 as tree = (ebrowse-tree-at-point)
1224 do (progn
1225 (setf (ebrowse-ts-mark tree) (not (ebrowse-ts-mark tree)))
1226 (forward-line 1)
1227 (push tree to-change))))
be0dbdab
GM
1228 (save-excursion
1229 ;; For all these classes, reverse the mark char in the display
1230 ;; by a regexp replace over the whole buffer. The reason for this
1231 ;; is that classes might have multiple base classes. If this is
1232 ;; the case, they are displayed more than once in the tree.
1233 (ebrowse-output
1234 (loop for tree in to-change
1235 as regexp = (concat "^.*\\b"
1236 (regexp-quote
1237 (ebrowse-cs-name (ebrowse-ts-class tree)))
1238 "\\b")
1239 do
1240 (goto-char (point-min))
1241 (loop while (re-search-forward regexp nil t)
1242 do (progn
1243 (goto-char (match-beginning 0))
1244 (delete-char 1)
1245 (insert-char (if (ebrowse-ts-mark tree) ?> ? ) 1)
1246 (ebrowse-set-mark-props (1- (point)) (point) tree)
1247 (goto-char (match-end 0)))))))))
1248
1249
1250(defun ebrowse-mark-all-classes (prefix)
1251 "Unmark, with PREFIX mark, all classes in the tree."
1252 (interactive "P")
1253 (ebrowse-for-all-trees (tree ebrowse--tree-obarray)
1254 (setf (ebrowse-ts-mark tree) prefix))
1255 (ebrowse-redraw-marks (point-min) (point-max)))
1256
1257
1258(defun ebrowse-redraw-marks (start end)
1259 "Display class marker signs in the tree between START and END."
1260 (interactive)
1261 (save-excursion
1262 (ebrowse-output
1263 (catch 'end
1264 (goto-char (point-min))
1265 (dolist (root ebrowse--tree)
1266 (ebrowse-draw-marks-fn root start end))))
1267 (ebrowse-update-tree-buffer-mode-line)))
1268
1269
1270(defun ebrowse-draw-marks-fn (tree start end)
1271 "Display class marker signs in TREE between START and END."
1272 (when (>= (point) start)
1273 (delete-char 1)
1274 (insert (if (ebrowse-ts-mark tree) ?> ? ))
1275 (ebrowse-set-mark-props (1- (point)) (point) tree))
1276 (forward-line 1)
1277 (when (> (point) end)
1278 (throw 'end nil))
1279 (dolist (sub (ebrowse-ts-subclasses tree))
1280 (ebrowse-draw-marks-fn sub start end)))
1281
1282
1283\f
1284;;; File name display in tree buffers
1285
1286(defun ebrowse-show-file-name-at-point (prefix)
1287 "Show filename in the line point is in.
1288With PREFIX, insert that many filenames."
1289 (interactive "p")
1290 (unless ebrowse--show-file-names-flag
1291 (ebrowse-output
1292 (dotimes (i prefix)
1293 (let ((tree (ebrowse-tree-at-point))
1294 start
1295 file-name-existing)
be0dbdab
GM
1296 (beginning-of-line)
1297 (skip-chars-forward " \t*a-zA-Z0-9_")
1298 (setq start (point)
1299 file-name-existing (looking-at "("))
5ed619e0 1300 (delete-region start (line-end-position))
be0dbdab
GM
1301 (unless file-name-existing
1302 (indent-to ebrowse-source-file-column)
1303 (insert "(" (or (ebrowse-cs-file
1304 (ebrowse-ts-class tree))
1305 "unknown")
1306 ")"))
4f2d55da 1307 (ebrowse-set-face start (point) 'ebrowse-file-name)
be0dbdab
GM
1308 (beginning-of-line)
1309 (forward-line 1))))))
1310
1311
1312(defun ebrowse-toggle-file-name-display ()
1313 "Toggle display of filenames in tree buffer."
1314 (interactive)
1315 (setf ebrowse--show-file-names-flag (not ebrowse--show-file-names-flag))
1316 (let ((old-line (count-lines (point-min) (point))))
1317 (ebrowse-redraw-tree)
e6ce8c42
GM
1318 (goto-char (point-min))
1319 (forward-line (1- old-line))))
be0dbdab
GM
1320
1321
1322\f
1323;;; General member and tree buffer functions
1324
1325(defun ebrowse-member-buffer-p (buffer)
1326 "Value is non-nil if BUFFER is a member buffer."
175069ef 1327 ;; FIXME: Why not (buffer-local-value 'major-mode buffer)?
be0dbdab
GM
1328 (eq (cdr (assoc 'major-mode (buffer-local-variables buffer)))
1329 'ebrowse-member-mode))
1330
1331
1332(defun ebrowse-tree-buffer-p (buffer)
1333 "Value is non-nil if BUFFER is a class tree buffer."
1334 (eq (cdr (assoc 'major-mode (buffer-local-variables buffer)))
1335 'ebrowse-tree-mode))
1336
1337
1338(defun ebrowse-buffer-p (buffer)
1339 "Value is non-nil if BUFFER is a tree or member buffer."
1340 (memq (cdr (assoc 'major-mode (buffer-local-variables buffer)))
1341 '(ebrowse-tree-mode ebrowse-member-mode)))
1342
1343
1344(defun ebrowse-browser-buffer-list ()
1345 "Return a list of all tree or member buffers."
1346 (ebrowse-delete-if-not 'ebrowse-buffer-p (buffer-list)))
1347
1348
1349(defun ebrowse-member-buffer-list ()
1350 "Return a list of all member buffers."
1351 (ebrowse-delete-if-not 'ebrowse-member-buffer-p (buffer-list)))
1352
1353
1354(defun ebrowse-tree-buffer-list ()
1355 "Return a list of all tree buffers."
1356 (ebrowse-delete-if-not 'ebrowse-tree-buffer-p (buffer-list)))
1357
1358
1359(defun ebrowse-known-class-trees-buffer-list ()
1360 "Return a list of buffers containing class trees.
1361The list will contain, for each class tree loaded,
1362one buffer. Prefer tree buffers over member buffers."
1363 (let ((buffers (nconc (ebrowse-tree-buffer-list)
1364 (ebrowse-member-buffer-list)))
1365 (set (make-hash-table))
1366 result)
1367 (dolist (buffer buffers)
1368 (let ((tree (ebrowse-value-in-buffer 'ebrowse--tree buffer)))
1369 (unless (gethash tree set)
1370 (push buffer result))
1371 (puthash tree t set)))
1372 result))
1373
1374
1375(defun ebrowse-same-tree-member-buffer-list ()
1376 "Return a list of members buffers with same tree as current buffer."
1377 (ebrowse-delete-if-not
e02f48d7
JB
1378 (lambda (buffer)
1379 (eq (ebrowse-value-in-buffer 'ebrowse--tree buffer)
1380 ebrowse--tree))
be0dbdab
GM
1381 (ebrowse-member-buffer-list)))
1382
1383
1384\f
1385(defun ebrowse-pop/switch-to-member-buffer-for-same-tree (arg)
1386 "Pop to the buffer displaying members.
1387Switch to buffer if prefix ARG.
1388If no member buffer exists, make one."
1389 (interactive "P")
1390 (let ((buf (or (first (ebrowse-same-tree-member-buffer-list))
1391 (get-buffer ebrowse-member-buffer-name)
1392 (ebrowse-tree-command:show-member-functions))))
1393 (when buf
1394 (if arg
1395 (switch-to-buffer buf)
1396 (pop-to-buffer buf)))
1397 buf))
1398
1399
1400(defun ebrowse-switch-to-next-member-buffer ()
1401 "Switch to next member buffer."
1402 (interactive)
1403 (let* ((list (ebrowse-member-buffer-list))
1404 (next-list (cdr (memq (current-buffer) list)))
1405 (next-buffer (if next-list (car next-list) (car list))))
1406 (if (eq next-buffer (current-buffer))
1407 (error "No next buffer")
1408 (bury-buffer)
1409 (switch-to-buffer next-buffer))))
1410
1411
1412(defun ebrowse-kill-member-buffers-displaying (tree)
1413 "Kill all member buffers displaying TREE."
1414 (loop for buffer in (ebrowse-member-buffer-list)
1415 as class = (ebrowse-value-in-buffer 'ebrowse--displayed-class buffer)
1416 when (eq class tree) do (kill-buffer buffer)))
1417
1418
e02f48d7
JB
1419(defun ebrowse-frozen-tree-buffer-name (tags-file)
1420 "Return the buffer name of a tree which is associated TAGS-FILE."
1421 (concat ebrowse-tree-buffer-name " (" tags-file ")"))
be0dbdab
GM
1422
1423
1424(defun ebrowse-pop-to-browser-buffer (arg)
1425 "Pop to a browser buffer from any other buffer.
1426Pop to member buffer if no prefix ARG, to tree buffer otherwise."
1427 (interactive "P")
106ba1bb 1428 (let ((buffer (get-buffer (if arg
be0dbdab
GM
1429 ebrowse-tree-buffer-name
1430 ebrowse-member-buffer-name))))
1431 (unless buffer
106ba1bb 1432 (setq buffer
be0dbdab
GM
1433 (get-buffer (if arg
1434 ebrowse-member-buffer-name
1435 ebrowse-tree-buffer-name))))
1436 (unless buffer
1437 (error "No browser buffer found"))
1438 (pop-to-buffer buffer)))
1439
1440
1441\f
1442;;; Misc tree buffer commands
1443
1444(defun ebrowse-set-tree-indentation ()
1445 "Set the indentation width of the tree display."
1446 (interactive)
175069ef
SM
1447 (let ((width (string-to-number (read-string
1448 (concat "Indentation (default "
027a4b6b 1449 (int-to-string ebrowse--indentation)
175069ef
SM
1450 "): ")
1451 nil nil ebrowse--indentation))))
be0dbdab 1452 (when (plusp width)
175069ef 1453 (set (make-local-variable 'ebrowse--indentation) width)
be0dbdab
GM
1454 (ebrowse-redraw-tree))))
1455
1456
1457(defun ebrowse-read-class-name-and-go (&optional class)
1458 "Position cursor on CLASS.
1459Read a class name from the minibuffer if CLASS is nil."
1460 (interactive)
1461 (ebrowse-ignoring-completion-case
1462 ;; If no class specified, read the class name from mini-buffer
1463 (unless class
1464 (setf class
1465 (completing-read "Goto class: "
1466 (ebrowse-tree-obarray-as-alist) nil t)))
1467 (ebrowse-save-selective
1468 (goto-char (point-min))
1469 (widen)
1470 (setf selective-display nil)
1471 (setq ebrowse--last-regexp (concat "\\b" class "\\b"))
1472 (if (re-search-forward ebrowse--last-regexp nil t)
1473 (progn
1474 (goto-char (match-beginning 0))
1475 (ebrowse-unhide-base-classes))
1476 (error "Not found")))))
1477
1478
1479\f
1480;;; Showing various kinds of member buffers
1481
1482(defun ebrowse-tree-command:show-member-variables (arg)
1483 "Display member variables; with prefix ARG in frozen member buffer."
1484 (interactive "P")
1485 (ebrowse-display-member-buffer 'ebrowse-ts-member-variables arg))
1486
1487
1488(defun ebrowse-tree-command:show-member-functions (&optional arg)
1489 "Display member functions; with prefix ARG in frozen member buffer."
1490 (interactive "P")
1491 (ebrowse-display-member-buffer 'ebrowse-ts-member-functions arg))
1492
1493
1494(defun ebrowse-tree-command:show-static-member-variables (arg)
1495 "Display static member variables; with prefix ARG in frozen member buffer."
1496 (interactive "P")
1497 (ebrowse-display-member-buffer 'ebrowse-ts-static-variables arg))
1498
1499
1500(defun ebrowse-tree-command:show-static-member-functions (arg)
1501 "Display static member functions; with prefix ARG in frozen member buffer."
1502 (interactive "P")
1503 (ebrowse-display-member-buffer 'ebrowse-ts-static-functions arg))
1504
1505
1506(defun ebrowse-tree-command:show-friends (arg)
1507 "Display friend functions; with prefix ARG in frozen member buffer."
1508 (interactive "P")
1509 (ebrowse-display-member-buffer 'ebrowse-ts-friends arg))
1510
1511
1512(defun ebrowse-tree-command:show-types (arg)
1513 "Display types defined in a class; with prefix ARG in frozen member buffer."
1514 (interactive "P")
1515 (ebrowse-display-member-buffer 'ebrowse-ts-types arg))
1516
1517
1518\f
1519;;; Viewing or finding a class declaration
1520
1521(defun ebrowse-tree-at-point ()
1522 "Return the class structure for the class point is on."
1523 (or (get-text-property (point) 'ebrowse-tree)
1524 (error "Not on a class")))
1525
1526
1527(defun* ebrowse-view/find-class-declaration (&key view where)
1528 "View or find the declarator of the class point is on.
1529VIEW non-nil means view it. WHERE is additional position info."
1530 (let* ((class (ebrowse-ts-class (ebrowse-tree-at-point)))
1531 (file (ebrowse-cs-file class))
1532 (browse-struct (make-ebrowse-bs
1533 :name (ebrowse-cs-name class)
1534 :pattern (ebrowse-cs-pattern class)
1535 :flags (ebrowse-cs-flags class)
1536 :file (ebrowse-cs-file class)
1537 :point (ebrowse-cs-point class))))
1538 (ebrowse-view/find-file-and-search-pattern
106ba1bb 1539 browse-struct
be0dbdab
GM
1540 (list ebrowse--header class nil)
1541 file
1542 ebrowse--tags-file-name
1543 view
1544 where)))
1545
1546
e02f48d7 1547(defun ebrowse-find-class-declaration (prefix)
be0dbdab 1548 "Find a class declaration and position cursor on it.
e02f48d7
JB
1549PREFIX 4 means find it in another window.
1550PREFIX 5 means find it in another frame."
be0dbdab
GM
1551 (interactive "p")
1552 (ebrowse-view/find-class-declaration
1553 :view nil
e02f48d7
JB
1554 :where (cond ((= prefix 4) 'other-window)
1555 ((= prefix 5) 'other-frame)
1556 (t 'this-window))))
be0dbdab
GM
1557
1558
e02f48d7 1559(defun ebrowse-view-class-declaration (prefix)
be0dbdab 1560 "View class declaration and position cursor on it.
e02f48d7
JB
1561PREFIX 4 means view it in another window.
1562PREFIX 5 means view it in another frame."
be0dbdab
GM
1563 (interactive "p")
1564 (ebrowse-view/find-class-declaration
1565 :view 'view
e02f48d7
JB
1566 :where (cond ((= prefix 4) 'other-window)
1567 ((= prefix 5) 'other-frame)
1568 (t 'this-window))))
be0dbdab
GM
1569
1570
1571\f
1572;;; The FIND engine
1573
e02f48d7 1574(defun ebrowse-find-source-file (file tags-file)
be0dbdab 1575 "Find source file FILE.
e02f48d7 1576Source files are searched for (a) relative to TAGS-FILE
be0dbdab
GM
1577which is the path of the BROWSE file from which the class tree was loaded,
1578and (b) in the directories named in `ebrowse-search-path'."
1579 (let (file-name
1580 (try-file (expand-file-name file
e02f48d7 1581 (file-name-directory tags-file))))
be0dbdab
GM
1582 (if (file-readable-p try-file)
1583 (setq file-name try-file)
1584 (let ((search-in ebrowse-search-path))
1585 (while (and search-in
1586 (null file-name))
1587 (let ((try-file (expand-file-name file (car search-in))))
1588 (if (file-readable-p try-file)
1589 (setq file-name try-file))
1590 (setq search-in (cdr search-in))))))
1591 (unless file-name
1592 (error "File `%s' not found" file))
1593 file-name))
1594
1595
be0dbdab
GM
1596(defun ebrowse-view-exit-fn (buffer)
1597 "Function called when exiting View mode in BUFFER.
1598Restore frame configuration active before viewing the file,
1599and possibly kill the viewed buffer."
1600 (let (exit-action original-frame-configuration)
9a529312 1601 (with-current-buffer buffer
be0dbdab
GM
1602 (setq original-frame-configuration ebrowse--frame-configuration
1603 exit-action ebrowse--view-exit-action))
1604 ;; Delete the frame in which we viewed.
2d97d6dc
JB
1605 (mapc 'delete-frame
1606 (loop for frame in (frame-list)
1607 when (not (assq frame original-frame-configuration))
1608 collect frame))
be0dbdab
GM
1609 (when exit-action
1610 (funcall exit-action buffer))))
1611
1612
1613(defun ebrowse-view-file-other-frame (file)
1614 "View a file FILE in another frame.
26a30fea 1615The new frame is deleted when you quit viewing the file in that frame."
be0dbdab
GM
1616 (interactive)
1617 (let ((old-frame-configuration (current-frame-configuration))
be0dbdab
GM
1618 (had-a-buf (get-file-buffer file))
1619 (buf-to-view (find-file-noselect file)))
1620 (switch-to-buffer-other-frame buf-to-view)
175069ef
SM
1621 (set (make-local-variable 'ebrowse--frame-configuration)
1622 old-frame-configuration)
1623 (set (make-local-variable 'ebrowse--view-exit-action)
1624 (and (not had-a-buf)
1625 (not (buffer-modified-p buf-to-view))
1626 'kill-buffer))
26a30fea
EZ
1627 (view-mode-enter (cons (selected-window) (cons (selected-window) t))
1628 'ebrowse-view-exit-fn)))
be0dbdab
GM
1629
1630(defun ebrowse-view/find-file-and-search-pattern
e02f48d7 1631 (struc info file tags-file &optional view where)
be0dbdab
GM
1632 "Find or view a member or class.
1633STRUC is an `ebrowse-bs' structure (or a structure including that)
1634describing what to search.
1635INFO is a list (HEADER MEMBER-OR-CLASS ACCESSOR). HEADER is the
1636header structure of a class tree. MEMBER-OR-CLASS is either an
1637`ebrowse-ms' or `ebrowse-cs' structure depending on what is searched.
106ba1bb 1638ACCESSOR is an accessor function for the member list of a member
be0dbdab
GM
1639if MEMBER-OR-CLASS is an `ebrowse-ms'.
1640FILE is the file to search the member in.
1641FILE is not taken out of STRUC here because the filename in STRUC
1642may be nil in which case the filename of the class description is used.
e02f48d7 1643TAGS-FILE is the name of the BROWSE file from which the
be0dbdab
GM
1644tree was loaded.
1645If VIEW is non-nil, view file else find the file.
1646WHERE is either `other-window', `other-frame' or `this-window' and
1647specifies where to find/view the result."
1648 (unless file
1649 (error "Sorry, no file information available for %s"
1650 (ebrowse-bs-name struc)))
1651 ;; Get the source file to view or find.
e02f48d7 1652 (setf file (ebrowse-find-source-file file tags-file))
be0dbdab
GM
1653 ;; If current window is dedicated, use another frame.
1654 (when (window-dedicated-p (selected-window))
5bc2ca83 1655 (setf where 'other-window))
be0dbdab
GM
1656 (cond (view
1657 (setf ebrowse-temp-position-to-view struc
1658 ebrowse-temp-info-to-view info)
1659 (unless (boundp 'view-mode-hook)
1660 (setq view-mode-hook nil))
1661 (push 'ebrowse-find-pattern view-mode-hook)
1662 (case where
26a30fea 1663 (other-window (view-file-other-window file))
be0dbdab
GM
1664 (other-frame (ebrowse-view-file-other-frame file))
1665 (t (view-file file))))
1666 (t
1667 (case where
1668 (other-window (find-file-other-window file))
1669 (other-frame (find-file-other-frame file))
1670 (t (find-file file)))
1671 (ebrowse-find-pattern struc info))))
1672
1673
1674(defun ebrowse-symbol-regexp (name)
1675 "Generate a suitable regular expression for a member or class NAME.
1676This is `regexp-quote' for most symbols, except for operator names
1677which may contain whitespace. For these symbols, replace white
183c2d42 1678space in the symbol name (generated by BROWSE) with a regular
be0dbdab
GM
1679expression matching any number of whitespace characters."
1680 (loop with regexp = (regexp-quote name)
1681 with start = 0
1682 finally return regexp
1683 while (string-match "[ \t]+" regexp start)
47932cf8
SM
1684 do (setq regexp (concat (substring regexp 0 (match-beginning 0))
1685 "[ \t]*"
1686 (substring regexp (match-end 0)))
be0dbdab
GM
1687 start (+ (match-beginning 0) 5))))
1688
1689
1690(defun ebrowse-class-declaration-regexp (name)
106ba1bb 1691 "Construct a regexp for a declaration of class NAME."
be0dbdab
GM
1692 (concat "^[ \t]*\\(template[ \t\n]*<.*>\\)?"
1693 "[ \t\n]*\\(class\\|struct\\|union\\).*\\S_"
1694 (ebrowse-symbol-regexp name)
1695 "\\S_"))
1696
1697
1698(defun ebrowse-variable-declaration-regexp (name)
1699 "Construct a regexp for matching a variable NAME."
1700 (concat "\\S_" (ebrowse-symbol-regexp name) "\\S_"))
1701
1702
1703(defun ebrowse-function-declaration/definition-regexp (name)
1704 "Construct a regexp for matching a function NAME."
1705 (concat "^[a-zA-Z0-9_:*&<>, \t]*\\S_"
1706 (ebrowse-symbol-regexp name)
1707 "[ \t\n]*("))
1708
1709
1710(defun ebrowse-pp-define-regexp (name)
1711 "Construct a regexp matching a define of NAME."
1712 (concat "^[ \t]*#[ \t]*define[ \t]+" (regexp-quote name)))
1713
1714
1715(defun* ebrowse-find-pattern (&optional position info &aux viewing)
1716 "Find a pattern.
1717
1718This is a kluge: Ebrowse allows you to find or view a file containing
1719a pattern. To be able to do a search in a viewed buffer,
1720`view-mode-hook' is temporarily set to this function;
1721`ebrowse-temp-position-to-view' holds what to search for.
1722
1723INFO is a list (TREE-HEADER TREE-OR-MEMBER MEMBER-LIST)."
1724 (unless position
1725 (pop view-mode-hook)
1726 (setf viewing t
1727 position ebrowse-temp-position-to-view
1728 info ebrowse-temp-info-to-view))
1729 (widen)
1730 (let* ((pattern (ebrowse-bs-pattern position))
1731 (start (ebrowse-bs-point position))
1732 (offset 100)
1733 found)
1734 (destructuring-bind (header class-or-member member-list) info
1735 ;; If no pattern is specified, construct one from the member name.
1736 (when (stringp pattern)
1737 (setq pattern (concat "^.*" (regexp-quote pattern))))
1738 ;; Construct a regular expression if none given.
1739 (unless pattern
1740 (typecase class-or-member
1741 (ebrowse-ms
1742 (case member-list
1743 ((ebrowse-ts-member-variables
1744 ebrowse-ts-static-variables
1745 ebrowse-ts-types)
1746 (setf pattern (ebrowse-variable-declaration-regexp
1747 (ebrowse-bs-name position))))
1748 (otherwise
1749 (if (ebrowse-define-p class-or-member)
1750 (setf pattern (ebrowse-pp-define-regexp (ebrowse-bs-name position)))
1751 (setf pattern (ebrowse-function-declaration/definition-regexp
1752 (ebrowse-bs-name position)))))))
1753 (ebrowse-cs
1754 (setf pattern (ebrowse-class-declaration-regexp
1755 (ebrowse-bs-name position))))))
1756 ;; Begin searching some OFFSET from the original point where the
1757 ;; regular expression was found by the parse, and step forward.
1758 ;; When there is no regular expression in the database and a
1759 ;; member definition/declaration was not seen by the parser,
1760 ;; START will be 0.
1761 (when (and (boundp 'ebrowse-debug)
1762 (symbol-value 'ebrowse-debug))
ce5a3ac0 1763 (y-or-n-p (format "start = %d? " start))
be0dbdab
GM
1764 (y-or-n-p pattern))
1765 (setf found
1766 (loop do (goto-char (max (point-min) (- start offset)))
1767 when (re-search-forward pattern (+ start offset) t) return t
1768 never (bobp)
1769 do (incf offset offset)))
1770 (cond (found
1771 (beginning-of-line)
1772 (run-hooks 'ebrowse-view/find-hook))
1773 ((numberp (ebrowse-bs-pattern position))
1774 (goto-char start)
1775 (if ebrowse-not-found-hook
1776 (run-hooks 'ebrowse-not-found-hook)
1777 (message "Not found")
1778 (sit-for 2)))
1779 (t
1780 (if ebrowse-not-found-hook
1781 (run-hooks 'ebrowse-not-found-hook)
1782 (unless viewing
1783 (error "Not found"))
1784 (message "Not found")
1785 (sit-for 2)))))))
1786
1787\f
1788;;; Drawing the tree
1789
1790(defun ebrowse-redraw-tree (&optional quietly)
1791 "Redisplay the complete tree.
1792QUIETLY non-nil means don't display progress messages."
1793 (interactive)
1794 (or quietly (message "Displaying..."))
1795 (save-excursion
1796 (ebrowse-output
1797 (erase-buffer)
1798 (ebrowse-draw-tree-fn)))
1799 (ebrowse-update-tree-buffer-mode-line)
1800 (or quietly (message nil)))
1801
1802
1803(defun ebrowse-set-mark-props (start end tree)
1804 "Set text properties for class marker signs between START and END.
1805TREE denotes the class shown."
1806 (add-text-properties
1807 start end
1808 `(mouse-face highlight ebrowse-what mark ebrowse-tree ,tree
1809 help-echo "double-mouse-1: mark/unmark"))
4f2d55da 1810 (ebrowse-set-face start end 'ebrowse-tree-mark))
be0dbdab
GM
1811
1812
1813(defun* ebrowse-draw-tree-fn (&aux stack1 stack2 start)
b2f6a2ab 1814 "Display a single class and recursively its subclasses.
be0dbdab
GM
1815This function may look weird, but this is faster than recursion."
1816 (setq stack1 (make-list (length ebrowse--tree) 0)
658397fb 1817 stack2 (copy-sequence ebrowse--tree))
be0dbdab
GM
1818 (loop while stack2
1819 as level = (pop stack1)
1820 as tree = (pop stack2)
1821 as class = (ebrowse-ts-class tree) do
1822 (let ((start-of-line (point))
1823 start-of-class-name end-of-class-name)
1824 ;; Insert mark
1825 (insert (if (ebrowse-ts-mark tree) ">" " "))
106ba1bb 1826
be0dbdab
GM
1827 ;; Indent and insert class name
1828 (indent-to (+ (* level ebrowse--indentation)
1829 ebrowse-tree-left-margin))
1830 (setq start (point))
1831 (insert (ebrowse-qualified-class-name class))
106ba1bb 1832
be0dbdab
GM
1833 ;; If template class, add <>
1834 (when (ebrowse-template-p class)
1835 (insert "<>"))
1836 (ebrowse-set-face start (point) (if (zerop level)
4f2d55da
MB
1837 'ebrowse-root-class
1838 'ebrowse-default))
be0dbdab
GM
1839 (setf start-of-class-name start
1840 end-of-class-name (point))
1841 ;; If filenames are to be displayed...
1842 (when ebrowse--show-file-names-flag
1843 (indent-to ebrowse-source-file-column)
1844 (setq start (point))
1845 (insert "("
1846 (or (ebrowse-cs-file class)
1847 "unknown")
1848 ")")
4f2d55da 1849 (ebrowse-set-face start (point) 'ebrowse-file-name))
be0dbdab
GM
1850 (ebrowse-set-mark-props start-of-line (1+ start-of-line) tree)
1851 (add-text-properties
1852 start-of-class-name end-of-class-name
1853 `(mouse-face highlight ebrowse-what class-name
1854 ebrowse-tree ,tree
1855 help-echo "double-mouse-1: (un)expand tree; mouse-2: member functions, mouse-3: menu"))
1856 (insert "\n"))
1857 ;; Push subclasses, if any.
1858 (when (ebrowse-ts-subclasses tree)
1859 (setq stack2
658397fb 1860 (nconc (copy-sequence (ebrowse-ts-subclasses tree)) stack2)
be0dbdab
GM
1861 stack1
1862 (nconc (make-list (length (ebrowse-ts-subclasses tree))
1863 (1+ level)) stack1)))))
1864
1865
1866\f
1867;;; Expanding/ collapsing tree branches
1868
1869(defun ebrowse-expand-branch (arg)
1870 "Expand a sub-tree that has been previously collapsed.
1871With prefix ARG, expand all sub-trees."
1872 (interactive "P")
1873 (if arg
1874 (ebrowse-expand-all arg)
1875 (ebrowse-collapse-fn nil)))
1876
1877
1878(defun ebrowse-collapse-branch (arg)
1879 "Fold (do no longer display) the subclasses of the current class.
1880\(The class cursor is on.) With prefix ARG, fold all trees in the buffer."
1881 (interactive "P")
1882 (if arg
1883 (ebrowse-expand-all (not arg))
1884 (ebrowse-collapse-fn t)))
1885
1886
1887(defun ebrowse-expand-all (collapse)
1888 "Expand or fold all trees in the buffer.
1889COLLAPSE non-nil means fold them."
1890 (interactive "P")
1891 (let ((line-end (if collapse "^\n" "^\r"))
1892 (insertion (if collapse "\r" "\n")))
1893 (ebrowse-output
1894 (save-excursion
1895 (goto-char (point-min))
1896 (while (not (progn (skip-chars-forward line-end) (eobp)))
1897 (when (or (not collapse)
1898 (looking-at "\n "))
1899 (delete-char 1)
1900 (insert insertion))
1901 (when collapse
1902 (skip-chars-forward "\n ")))))))
1903
1904
1905(defun ebrowse-unhide-base-classes ()
1906 "Unhide the line the cursor is on and all base classes."
1907 (ebrowse-output
1908 (save-excursion
1909 (let (indent last-indent)
1910 (skip-chars-backward "^\r\n")
1911 (when (not (looking-at "[\r\n][^ \t]"))
1912 (skip-chars-forward "\r\n \t")
1913 (while (and (or (null last-indent) ;first time
1914 (> indent 1)) ;not root class
1915 (re-search-backward "[\r\n][ \t]*" nil t))
1916 (setf indent (- (match-end 0)
1917 (match-beginning 0)))
1918 (when (or (null last-indent)
1919 (< indent last-indent))
1920 (setf last-indent indent)
1921 (when (looking-at "\r")
1922 (delete-char 1)
1923 (insert 10)))
1924 (backward-char 1)))))))
1925
1926
1927(defun ebrowse-hide-line (collapse)
1928 "Hide/show a single line in the tree.
1929COLLAPSE non-nil means hide."
1930 (save-excursion
1931 (ebrowse-output
1932 (skip-chars-forward "^\r\n")
1933 (delete-char 1)
1934 (insert (if collapse 13 10)))))
1935
1936
1937(defun ebrowse-collapse-fn (collapse)
1938 "Collapse or expand a branch of the tree.
1939COLLAPSE non-nil means collapse the branch."
1940 (ebrowse-output
1941 (save-excursion
1942 (beginning-of-line)
1943 (skip-chars-forward "> \t")
1944 (let ((indentation (current-column)))
1945 (while (and (not (eobp))
1946 (save-excursion
1947 (skip-chars-forward "^\r\n")
1948 (goto-char (1+ (point)))
1949 (skip-chars-forward "> \t")
1950 (> (current-column) indentation)))
1951 (ebrowse-hide-line collapse)
1952 (skip-chars-forward "^\r\n")
1953 (goto-char (1+ (point))))))))
1954
1955\f
1956;;; Electric tree selection
1957
1958(defvar ebrowse-electric-list-mode-map ()
1959 "Keymap used in electric Ebrowse buffer list window.")
1960
1961
1962(unless ebrowse-electric-list-mode-map
1963 (let ((map (make-keymap))
1964 (submap (make-keymap)))
1965 (setq ebrowse-electric-list-mode-map map)
1966 (fillarray (car (cdr map)) 'ebrowse-electric-list-undefined)
1967 (fillarray (car (cdr submap)) 'ebrowse-electric-list-undefined)
1968 (define-key map "\e" submap)
f35ca2fe 1969 (define-key map "\C-z" 'suspend-frame)
be0dbdab
GM
1970 (define-key map "\C-h" 'Helper-help)
1971 (define-key map "?" 'Helper-describe-bindings)
1972 (define-key map "\C-c" nil)
1973 (define-key map "\C-c\C-c" 'ebrowse-electric-list-quit)
1974 (define-key map "q" 'ebrowse-electric-list-quit)
1975 (define-key map " " 'ebrowse-electric-list-select)
1976 (define-key map "\C-l" 'recenter)
1977 (define-key map "\C-u" 'universal-argument)
1978 (define-key map "\C-p" 'previous-line)
1979 (define-key map "\C-n" 'next-line)
1980 (define-key map "p" 'previous-line)
1981 (define-key map "n" 'next-line)
1982 (define-key map "v" 'ebrowse-electric-view-buffer)
ce3cefcc
CY
1983 (define-key map "\C-v" 'scroll-up-command)
1984 (define-key map "\ev" 'scroll-down-command)
be0dbdab
GM
1985 (define-key map "\e\C-v" 'scroll-other-window)
1986 (define-key map "\e>" 'end-of-buffer)
1987 (define-key map "\e<" 'beginning-of-buffer)
1988 (define-key map "\e>" 'end-of-buffer)))
1989
1990(put 'ebrowse-electric-list-mode 'mode-class 'special)
1991(put 'ebrowse-electric-list-undefined 'suppress-keymap t)
1992
1993
175069ef
SM
1994(define-derived-mode ebrowse-electric-list-mode
1995 fundamental-mode "Electric Position Menu"
be0dbdab 1996 "Mode for electric tree list mode."
175069ef 1997 (setq mode-line-buffer-identification "Electric Tree Menu")
be0dbdab
GM
1998 (when (memq 'mode-name mode-line-format)
1999 (setq mode-line-format (copy-sequence mode-line-format))
2000 (setcar (memq 'mode-name mode-line-format) "Tree Buffers"))
175069ef
SM
2001 (set (make-local-variable 'Helper-return-blurb) "return to buffer editing")
2002 (setq truncate-lines t
2003 buffer-read-only t))
be0dbdab
GM
2004
2005
2006(defun ebrowse-list-tree-buffers ()
2007 "Display a list of all tree buffers."
2008 (set-buffer (get-buffer-create "*Tree Buffers*"))
2009 (setq buffer-read-only nil)
2010 (erase-buffer)
2011 (insert "Tree\n" "----\n")
2012 (dolist (buffer (ebrowse-known-class-trees-buffer-list))
2013 (insert (buffer-name buffer) "\n"))
2014 (setq buffer-read-only t))
2015
2016
2017;;;###autoload
2018(defun ebrowse-electric-choose-tree ()
2019 "Return a buffer containing a tree or nil if no tree found or canceled."
2020 (interactive)
2021 (unless (car (ebrowse-known-class-trees-buffer-list))
2022 (error "No tree buffers"))
2023 (let (select buffer window)
2024 (save-window-excursion
2025 (save-window-excursion (ebrowse-list-tree-buffers))
2026 (setq window (Electric-pop-up-window "*Tree Buffers*")
2027 buffer (window-buffer window))
2028 (shrink-window-if-larger-than-buffer window)
2029 (unwind-protect
2030 (progn
2031 (set-buffer buffer)
2032 (ebrowse-electric-list-mode)
2033 (setq select
2034 (catch 'ebrowse-electric-list-select
2035 (message "<<< Press Space to bury the list >>>")
2036 (let ((first (progn (goto-char (point-min))
2037 (forward-line 2)
2038 (point)))
2039 (last (progn (goto-char (point-max))
2040 (forward-line -1)
2041 (point)))
2042 (goal-column 0))
2043 (goto-char first)
2044 (Electric-command-loop 'ebrowse-electric-list-select
2045 nil
2046 t
2047 'ebrowse-electric-list-looper
2048 (cons first last))))))
2049 (set-buffer buffer)
2050 (bury-buffer buffer)
2051 (message nil)))
2052 (when select
2053 (set-buffer buffer)
2054 (setq select (ebrowse-electric-get-buffer select)))
2055 (kill-buffer buffer)
2056 select))
2057
2058
2059(defun ebrowse-electric-list-looper (state condition)
2060 "Prevent cursor from moving beyond the buffer end.
2061Don't let it move into the title lines.
2062See 'Electric-command-loop' for a description of STATE and CONDITION."
2063 (cond ((and condition
2064 (not (memq (car condition)
2065 '(buffer-read-only end-of-buffer
2066 beginning-of-buffer))))
2067 (signal (car condition) (cdr condition)))
2068 ((< (point) (car state))
2069 (goto-char (point-min))
2070 (forward-line 2))
2071 ((> (point) (cdr state))
2072 (goto-char (point-max))
2073 (forward-line -1)
2074 (if (pos-visible-in-window-p (point-max))
2075 (recenter -1)))))
2076
2077
2078(defun ebrowse-electric-list-undefined ()
2079 "Function called for keys that are undefined."
2080 (interactive)
2081 (message "Type C-h for help, ? for commands, q to quit, Space to select.")
2082 (sit-for 4))
2083
2084
2085(defun ebrowse-electric-list-quit ()
2086 "Discard the buffer list."
2087 (interactive)
2088 (throw 'ebrowse-electric-list-select nil))
2089
2090
2091(defun ebrowse-electric-list-select ()
2092 "Select a buffer from the buffer list."
2093 (interactive)
2094 (throw 'ebrowse-electric-list-select (point)))
2095
2096
2097(defun ebrowse-electric-get-buffer (point)
2098 "Get a buffer corresponding to the line POINT is in."
2099 (let ((index (- (count-lines (point-min) point) 2)))
2100 (nth index (ebrowse-known-class-trees-buffer-list))))
2101
2102
2103;;; View a buffer for a tree.
2104
2105(defun ebrowse-electric-view-buffer ()
2106 "View buffer point is on."
2107 (interactive)
2108 (let ((buffer (ebrowse-electric-get-buffer (point))))
2109 (cond (buffer
2110 (view-buffer buffer))
2111 (t
2112 (error "Buffer no longer exists")))))
2113
2114
2115(defun ebrowse-choose-from-browser-buffers ()
2116 "Read a browser buffer name from the minibuffer and return that buffer."
2117 (let* ((buffers (ebrowse-known-class-trees-buffer-list)))
2118 (if buffers
2119 (if (not (second buffers))
2120 (first buffers)
2121 (or (ebrowse-electric-choose-tree) (error "No tree buffer")))
2122 (let* ((insert-default-directory t)
2123 (file (read-file-name "Find tree: " nil nil t)))
2124 (save-excursion
2125 (find-file file))
2126 (find-buffer-visiting file)))))
2127
2128\f
2129;;; Member buffers
2130
2131(unless ebrowse-member-mode-map
2132 (let ((map (make-keymap)))
2133 (setf ebrowse-member-mode-map map)
2134 (suppress-keymap map)
2135
f4a2b0a4 2136 (when (display-mouse-p)
be0dbdab
GM
2137 (define-key map [down-mouse-3] 'ebrowse-member-mouse-3)
2138 (define-key map [mouse-2] 'ebrowse-member-mouse-2))
2139
2140 (let ((map1 (make-sparse-keymap)))
2141 (suppress-keymap map1 t)
2142 (define-key map "C" map1)
2143 (define-key map1 "b" 'ebrowse-switch-member-buffer-to-base-class)
2144 (define-key map1 "c" 'ebrowse-switch-member-buffer-to-any-class)
2145 (define-key map1 "d" 'ebrowse-switch-member-buffer-to-derived-class)
2146 (define-key map1 "n" 'ebrowse-switch-member-buffer-to-next-sibling-class)
2147 (define-key map1 "p" 'ebrowse-switch-member-buffer-to-previous-sibling-class))
106ba1bb 2148
be0dbdab
GM
2149 (let ((map1 (make-sparse-keymap)))
2150 (suppress-keymap map1 t)
2151 (define-key map "D" map1)
2152 (define-key map1 "a" 'ebrowse-toggle-member-attributes-display)
2153 (define-key map1 "b" 'ebrowse-toggle-base-class-display)
2154 (define-key map1 "f" 'ebrowse-freeze-member-buffer)
2155 (define-key map1 "l" 'ebrowse-toggle-long-short-display)
2156 (define-key map1 "r" 'ebrowse-toggle-regexp-display)
2157 (define-key map1 "w" 'ebrowse-set-member-buffer-column-width))
106ba1bb 2158
be0dbdab
GM
2159 (let ((map1 (make-sparse-keymap)))
2160 (suppress-keymap map1 t)
2161 (define-key map "F" map1)
2162 (let ((map2 (make-sparse-keymap)))
2163 (suppress-keymap map2 t)
2164 (define-key map1 "a" map2)
2165 (define-key map2 "i" 'ebrowse-toggle-private-member-filter)
2166 (define-key map2 "o" 'ebrowse-toggle-protected-member-filter)
2167 (define-key map2 "u" 'ebrowse-toggle-public-member-filter))
2168 (define-key map1 "c" 'ebrowse-toggle-const-member-filter)
2169 (define-key map1 "i" 'ebrowse-toggle-inline-member-filter)
2170 (define-key map1 "p" 'ebrowse-toggle-pure-member-filter)
2171 (define-key map1 "r" 'ebrowse-remove-all-member-filters)
2172 (define-key map1 "v" 'ebrowse-toggle-virtual-member-filter))
106ba1bb 2173
be0dbdab
GM
2174 (let ((map1 (make-sparse-keymap)))
2175 (suppress-keymap map1 t)
2176 (define-key map "L" map1)
2177 (define-key map1 "d" 'ebrowse-display-friends-member-list)
2178 (define-key map1 "f" 'ebrowse-display-function-member-list)
2179 (define-key map1 "F" 'ebrowse-display-static-functions-member-list)
2180 (define-key map1 "n" 'ebrowse-display-next-member-list)
2181 (define-key map1 "p" 'ebrowse-display-previous-member-list)
2182 (define-key map1 "t" 'ebrowse-display-types-member-list)
2183 (define-key map1 "v" 'ebrowse-display-variables-member-list)
2184 (define-key map1 "V" 'ebrowse-display-static-variables-member-list))
106ba1bb 2185
be0dbdab
GM
2186 (let ((map1 (make-sparse-keymap)))
2187 (suppress-keymap map1 t)
2188 (define-key map "G" map1)
2189 (define-key map1 "m" 'ebrowse-goto-visible-member/all-member-lists)
2190 (define-key map1 "n" 'ebrowse-repeat-member-search)
2191 (define-key map1 "v" 'ebrowse-goto-visible-member))
106ba1bb 2192
be0dbdab
GM
2193 (define-key map "f" 'ebrowse-find-member-declaration)
2194 (define-key map "m" 'ebrowse-switch-to-next-member-buffer)
2195 (define-key map "q" 'bury-buffer)
2196 (define-key map "t" 'ebrowse-show-displayed-class-in-tree)
2197 (define-key map "v" 'ebrowse-view-member-declaration)
2198 (define-key map " " 'ebrowse-view-member-definition)
2199 (define-key map "?" 'describe-mode)
2200 (define-key map "\C-i" 'ebrowse-pop-from-member-to-tree-buffer)
2201 (define-key map "\C-l" 'ebrowse-redisplay-member-buffer)
2202 (define-key map "\C-m" 'ebrowse-find-member-definition)))
2203
2204
2205\f
2206;;; Member mode
2207
8cbb7c61 2208;;;###autoload
175069ef
SM
2209(define-derived-mode ebrowse-member-mode special-mode "Ebrowse-Members"
2210 "Major mode for Ebrowse member buffers."
2d97d6dc
JB
2211 (mapc 'make-local-variable
2212 '(ebrowse--decl-column ;display column
2213 ebrowse--n-columns ;number of short columns
2214 ebrowse--column-width ;width of columns above
2215 ebrowse--show-inherited-flag ;include inherited members?
2216 ebrowse--filters ;public, protected, private
2217 ebrowse--accessor ;vars, functions, friends
2218 ebrowse--displayed-class ;class displayed
2219 ebrowse--long-display-flag ;display with regexps?
2220 ebrowse--source-regexp-flag ;show source regexp?
2221 ebrowse--attributes-flag ;show `virtual' and `inline'
2222 ebrowse--member-list ;list of members displayed
2223 ebrowse--tree ;the class tree
2224 ebrowse--member-mode-strings ;part of mode line
2225 ebrowse--tags-file-name ;
2226 ebrowse--header
2227 ebrowse--tree-obarray
2228 ebrowse--virtual-display-flag
2229 ebrowse--inline-display-flag
2230 ebrowse--const-display-flag
2231 ebrowse--pure-display-flag
2232 ebrowse--frozen-flag)) ;buffer not automagically reused
175069ef 2233 (setq mode-line-buffer-identification
8b2affc5 2234 (propertized-buffer-identification "C++ Members")
be0dbdab
GM
2235 buffer-read-only t
2236 ebrowse--long-display-flag nil
2237 ebrowse--attributes-flag t
2238 ebrowse--show-inherited-flag t
2239 ebrowse--source-regexp-flag nil
2240 ebrowse--filters [0 1 2]
2241 ebrowse--decl-column ebrowse-default-declaration-column
2242 ebrowse--column-width ebrowse-default-column-width
2243 ebrowse--virtual-display-flag nil
2244 ebrowse--inline-display-flag nil
2245 ebrowse--const-display-flag nil
2246 ebrowse--pure-display-flag nil)
175069ef 2247 (modify-syntax-entry ?_ (char-to-string (char-syntax ?a))))
be0dbdab
GM
2248
2249
2250\f
2251;;; Member mode mode line
2252
2253(defsubst ebrowse-class-name-displayed-in-member-buffer ()
2254 "Return the name of the class displayed in the member buffer."
2255 (ebrowse-cs-name (ebrowse-ts-class ebrowse--displayed-class)))
2256
2257
2258(defsubst ebrowse-member-list-name ()
2259 "Return a string describing what is displayed in the member buffer."
2260 (get ebrowse--accessor (if (ebrowse-globals-tree-p ebrowse--displayed-class)
2261 'ebrowse-global-title
2262 'ebrowse-title)))
2263
2264
2265(defun ebrowse-update-member-buffer-mode-line ()
2266 "Update the mode line of member buffers."
2267 (let* ((name (when ebrowse--frozen-flag
2268 (concat (ebrowse-class-name-displayed-in-member-buffer)
2269 " ")))
2270 (ident (concat name (ebrowse-member-list-name))))
8b2affc5
GM
2271 (setq mode-line-buffer-identification
2272 (propertized-buffer-identification ident))
be0dbdab
GM
2273 (ebrowse-rename-buffer (if name ident ebrowse-member-buffer-name))
2274 (force-mode-line-update)))
2275
2276
2277;;; Misc member buffer commands
2278
2279(defun ebrowse-freeze-member-buffer ()
2280 "Toggle frozen status of current buffer."
2281 (interactive)
2282 (setq ebrowse--frozen-flag (not ebrowse--frozen-flag))
2283 (ebrowse-redisplay-member-buffer))
2284
2285
2286(defun ebrowse-show-displayed-class-in-tree (arg)
2287 "Show the currently displayed class in the tree window.
2288With prefix ARG, switch to the tree buffer else pop to it."
2289 (interactive "P")
2290 (let ((class-name (ebrowse-class-name-displayed-in-member-buffer)))
2291 (when (ebrowse-pop-from-member-to-tree-buffer arg)
2292 (ebrowse-read-class-name-and-go class-name))))
2293
2294
2295(defun ebrowse-set-member-buffer-column-width ()
2296 "Set the column width of the member display.
2297The new width is read from the minibuffer."
2298 (interactive)
027a4b6b 2299 (let ((width (string-to-number
be0dbdab
GM
2300 (read-from-minibuffer
2301 (concat "Column width ("
2302 (int-to-string (if ebrowse--long-display-flag
2303 ebrowse--decl-column
2304 ebrowse--column-width))
2305 "): ")))))
2306 (when (plusp width)
2307 (if ebrowse--long-display-flag
2308 (setq ebrowse--decl-column width)
2309 (setq ebrowse--column-width width))
2310 (ebrowse-redisplay-member-buffer))))
2311
2312
2313(defun ebrowse-pop-from-member-to-tree-buffer (arg)
2314 "Pop from a member buffer to the matching tree buffer.
2315Switch to the buffer if prefix ARG. If no tree buffer exists,
2316make one."
2317 (interactive "P")
2318 (let ((buf (or (get-buffer (ebrowse-frozen-tree-buffer-name
2319 ebrowse--tags-file-name))
2320 (get-buffer ebrowse-tree-buffer-name)
2321 (ebrowse-create-tree-buffer ebrowse--tree
2322 ebrowse--tags-file-name
2323 ebrowse--header
2324 ebrowse--tree-obarray
2325 'pop))))
2326 (and buf
2327 (funcall (if arg 'switch-to-buffer 'pop-to-buffer) buf))
2328 buf))
2329
2330
2331\f
2332;;; Switching between member lists
2333
2334(defun ebrowse-display-member-list-for-accessor (accessor)
2335 "Switch the member buffer to display the member list for ACCESSOR."
2336 (setf ebrowse--accessor accessor
2337 ebrowse--member-list (funcall accessor ebrowse--displayed-class))
2338 (ebrowse-redisplay-member-buffer))
2339
2340
2341(defun ebrowse-cyclic-display-next/previous-member-list (incr)
2342 "Switch buffer to INCR'th next/previous list of members."
2343 (let ((index (ebrowse-position ebrowse--accessor
2344 ebrowse-member-list-accessors)))
2345 (setf ebrowse--accessor
2346 (cond ((plusp incr)
2347 (or (nth (1+ index)
2348 ebrowse-member-list-accessors)
2349 (first ebrowse-member-list-accessors)))
2350 ((minusp incr)
2351 (or (and (>= (decf index) 0)
2352 (nth index
2353 ebrowse-member-list-accessors))
2354 (first (last ebrowse-member-list-accessors))))))
2355 (ebrowse-display-member-list-for-accessor ebrowse--accessor)))
2356
2357
2358(defun ebrowse-display-next-member-list ()
2359 "Switch buffer to next member list."
2360 (interactive)
2361 (ebrowse-cyclic-display-next/previous-member-list 1))
2362
2363
2364(defun ebrowse-display-previous-member-list ()
2365 "Switch buffer to previous member list."
2366 (interactive)
2367 (ebrowse-cyclic-display-next/previous-member-list -1))
2368
2369
2370(defun ebrowse-display-function-member-list ()
2371 "Display the list of member functions."
2372 (interactive)
2373 (ebrowse-display-member-list-for-accessor 'ebrowse-ts-member-functions))
2374
2375
2376(defun ebrowse-display-variables-member-list ()
2377 "Display the list of member variables."
2378 (interactive)
2379 (ebrowse-display-member-list-for-accessor 'ebrowse-ts-member-variables))
2380
2381
2382(defun ebrowse-display-static-variables-member-list ()
2383 "Display the list of static member variables."
2384 (interactive)
2385 (ebrowse-display-member-list-for-accessor 'ebrowse-ts-static-variables))
2386
2387
2388(defun ebrowse-display-static-functions-member-list ()
2389 "Display the list of static member functions."
2390 (interactive)
2391 (ebrowse-display-member-list-for-accessor 'ebrowse-ts-static-functions))
2392
2393
2394(defun ebrowse-display-friends-member-list ()
2395 "Display the list of friends."
2396 (interactive)
2397 (ebrowse-display-member-list-for-accessor 'ebrowse-ts-friends))
2398
2399
2400(defun ebrowse-display-types-member-list ()
2401 "Display the list of types."
2402 (interactive)
2403 (ebrowse-display-member-list-for-accessor 'ebrowse-ts-types))
2404
2405
2406\f
2407;;; Filters and other display attributes
2408
2409(defun ebrowse-toggle-member-attributes-display ()
2410 "Toggle display of `virtual', `inline', `const' etc."
2411 (interactive)
2412 (setq ebrowse--attributes-flag (not ebrowse--attributes-flag))
2413 (ebrowse-redisplay-member-buffer))
2414
2415
2416(defun ebrowse-toggle-base-class-display ()
2417 "Toggle the display of members inherited from base classes."
2418 (interactive)
2419 (setf ebrowse--show-inherited-flag (not ebrowse--show-inherited-flag))
2420 (ebrowse-redisplay-member-buffer))
2421
2422
2423(defun ebrowse-toggle-pure-member-filter ()
2424 "Toggle display of pure virtual members."
2425 (interactive)
2426 (setf ebrowse--pure-display-flag (not ebrowse--pure-display-flag))
2427 (ebrowse-redisplay-member-buffer))
2428
2429
2430(defun ebrowse-toggle-const-member-filter ()
2431 "Toggle display of const members."
2432 (interactive)
2433 (setf ebrowse--const-display-flag (not ebrowse--const-display-flag))
2434 (ebrowse-redisplay-member-buffer))
2435
2436
2437(defun ebrowse-toggle-inline-member-filter ()
2438 "Toggle display of inline members."
2439 (interactive)
2440 (setf ebrowse--inline-display-flag (not ebrowse--inline-display-flag))
2441 (ebrowse-redisplay-member-buffer))
2442
2443
2444(defun ebrowse-toggle-virtual-member-filter ()
2445 "Toggle display of virtual members."
2446 (interactive)
2447 (setf ebrowse--virtual-display-flag (not ebrowse--virtual-display-flag))
2448 (ebrowse-redisplay-member-buffer))
2449
2450
2451(defun ebrowse-remove-all-member-filters ()
2452 "Remove all filters."
2453 (interactive)
2454 (dotimes (i 3)
2455 (aset ebrowse--filters i i))
2456 (setq ebrowse--pure-display-flag nil
2457 ebrowse--const-display-flag nil
2458 ebrowse--virtual-display-flag nil
2459 ebrowse--inline-display-flag nil)
2460 (ebrowse-redisplay-member-buffer))
2461
2462
2463(defun ebrowse-toggle-public-member-filter ()
2464 "Toggle visibility of public members."
2465 (interactive)
2466 (ebrowse-set-member-access-visibility 0)
2467 (ebrowse-redisplay-member-buffer))
2468
2469
2470(defun ebrowse-toggle-protected-member-filter ()
2471 "Toggle visibility of protected members."
2472 (interactive)
2473 (ebrowse-set-member-access-visibility 1)
2474 (ebrowse-redisplay-member-buffer))
2475
2476
2477(defun ebrowse-toggle-private-member-filter ()
2478 "Toggle visibility of private members."
2479 (interactive)
2480 (ebrowse-set-member-access-visibility 2)
2481 (ebrowse-redisplay-member-buffer))
2482
2483
2484(defun ebrowse-set-member-access-visibility (vis)
2485 (setf (aref ebrowse--filters vis)
2486 (if (aref ebrowse--filters vis) nil vis)))
2487
2488
2489(defun ebrowse-toggle-long-short-display ()
2490 "Toggle between long and short display form of member buffers."
2491 (interactive)
2492 (setf ebrowse--long-display-flag (not ebrowse--long-display-flag))
2493 (ebrowse-redisplay-member-buffer))
2494
2495
2496(defun ebrowse-toggle-regexp-display ()
2497 "Toggle declaration/definition regular expression display.
2498Used in member buffers showing the long display form."
2499 (interactive)
2500 (setf ebrowse--source-regexp-flag (not ebrowse--source-regexp-flag))
2501 (ebrowse-redisplay-member-buffer))
2502
2503
2504\f
2505;;; Viewing/finding members
2506
2507(defun ebrowse-find-member-definition (&optional prefix)
2508 "Find the file containing a member definition.
2509With PREFIX 4. find file in another window, with prefix 5
2510find file in another frame."
2511 (interactive "p")
2512 (ebrowse-view/find-member-declaration/definition prefix nil t))
2513
2514
2515(defun ebrowse-view-member-definition (prefix)
2516 "View the file containing a member definition.
2517With PREFIX 4. find file in another window, with prefix 5
2518find file in another frame."
2519 (interactive "p")
2520 (ebrowse-view/find-member-declaration/definition prefix t t))
2521
2522
2523(defun ebrowse-find-member-declaration (prefix)
2524 "Find the file containing a member's declaration.
2525With PREFIX 4. find file in another window, with prefix 5
2526find file in another frame."
2527 (interactive "p")
2528 (ebrowse-view/find-member-declaration/definition prefix nil))
2529
2530
2531(defun ebrowse-view-member-declaration (prefix)
2532 "View the file containing a member's declaration.
2533With PREFIX 4. find file in another window, with prefix 5
2534find file in another frame."
2535 (interactive "p")
2536 (ebrowse-view/find-member-declaration/definition prefix t))
2537
2538
2539(defun* ebrowse-view/find-member-declaration/definition
e02f48d7 2540 (prefix view &optional definition info header tags-file)
be0dbdab
GM
2541 "Find or view a member declaration or definition.
2542With PREFIX 4. find file in another window, with prefix 5
2543find file in another frame.
2544DEFINITION non-nil means find the definition, otherwise find the
2545declaration.
2546INFO is a list (TREE ACCESSOR MEMBER) describing the member to
2547search.
e02f48d7 2548TAGS-FILE is the file name of the BROWSE file."
be0dbdab
GM
2549 (unless header
2550 (setq header ebrowse--header))
e02f48d7
JB
2551 (unless tags-file
2552 (setq tags-file ebrowse--tags-file-name))
be0dbdab
GM
2553 (let (tree member accessor file on-class
2554 (where (if (= prefix 4) 'other-window
2555 (if (= prefix 5) 'other-frame 'this-window))))
2556 ;; If not given as parameters, get the necessary information
2557 ;; out of the member buffer.
2558 (if info
2559 (setq tree (first info)
2560 accessor (second info)
2561 member (third info))
2562 (multiple-value-setq (tree member on-class)
3c2fbb99 2563 (values-list (ebrowse-member-info-from-point)))
be0dbdab
GM
2564 (setq accessor ebrowse--accessor))
2565 ;; View/find class if on a line containing a class name.
2566 (when on-class
2567 (return-from ebrowse-view/find-member-declaration/definition
2568 (ebrowse-view/find-file-and-search-pattern
2569 (ebrowse-ts-class tree)
2570 (list ebrowse--header (ebrowse-ts-class tree) nil)
2571 (ebrowse-cs-file (ebrowse-ts-class tree))
e02f48d7 2572 tags-file view where)))
be0dbdab
GM
2573 ;; For some member lists, it doesn't make sense to search for
2574 ;; a definition. If this is requested, silently search for the
2575 ;; declaration.
2576 (when (and definition
2577 (eq accessor 'ebrowse-ts-member-variables))
2578 (setq definition nil))
2579 ;; Construct a suitable `browse' struct for definitions.
2580 (when definition
2581 (setf member (make-ebrowse-ms
2582 :name (ebrowse-ms-name member)
2583 :file (ebrowse-ms-definition-file member)
2584 :pattern (ebrowse-ms-definition-pattern
2585 member)
2586 :flags (ebrowse-ms-flags member)
2587 :point (ebrowse-ms-definition-point
2588 member))))
2589 ;; When no file information in member, use that of the class
2590 (setf file (or (ebrowse-ms-file member)
2591 (if definition
2592 (ebrowse-cs-source-file (ebrowse-ts-class tree))
2593 (ebrowse-cs-file (ebrowse-ts-class tree)))))
2594 ;; When we have no regular expressions in the database the only
2595 ;; indication that the parser hasn't seen a definition/declaration
2596 ;; is that the search start point will be zero.
2597 (if (or (null file) (zerop (ebrowse-ms-point member)))
2598 (if (y-or-n-p (concat "No information about "
2599 (if definition "definition" "declaration")
2600 ". Search for "
2601 (if definition "declaration" "definition")
2602 " of `"
2603 (ebrowse-ms-name member)
2604 "'? "))
2605 (progn
2606 (message nil)
2607 ;; Recurse with new info.
2608 (ebrowse-view/find-member-declaration/definition
e02f48d7 2609 prefix view (not definition) info header tags-file))
be0dbdab
GM
2610 (error "Search canceled"))
2611 ;; Find that thing.
2612 (ebrowse-view/find-file-and-search-pattern
2613 (make-ebrowse-bs :name (ebrowse-ms-name member)
2614 :pattern (ebrowse-ms-pattern member)
2615 :file (ebrowse-ms-file member)
2616 :flags (ebrowse-ms-flags member)
2617 :point (ebrowse-ms-point member))
2618 (list header member accessor)
2619 file
e02f48d7 2620 tags-file
be0dbdab
GM
2621 view
2622 where))))
2623
2624
2625\f
2626;;; Drawing the member buffer
2627
2628(defun ebrowse-redisplay-member-buffer ()
2629 "Force buffer redisplay."
2630 (interactive)
2631 (let ((display-fn (if ebrowse--long-display-flag
2632 'ebrowse-draw-member-long-fn
2633 'ebrowse-draw-member-short-fn)))
2634 (ebrowse-output
2635 (erase-buffer)
2636 ;; Show this class
2637 (ebrowse-draw-member-buffer-class-line)
2638 (funcall display-fn ebrowse--member-list ebrowse--displayed-class)
2639 ;; Show inherited members if corresponding switch is on
2640 (when ebrowse--show-inherited-flag
2641 (dolist (super (ebrowse-base-classes ebrowse--displayed-class))
2642 (goto-char (point-max))
2643 (insert (if (bolp) "\n\n" "\n"))
2644 (ebrowse-draw-member-buffer-class-line super)
2645 (funcall display-fn (funcall ebrowse--accessor super) super)))
2646 (ebrowse-update-member-buffer-mode-line))))
2647
2648
2649(defun ebrowse-draw-member-buffer-class-line (&optional class)
2650 "Display the title line for a class section in the member buffer.
2651CLASS non-nil means display that class' title. Otherwise use
2652the class cursor is on."
2653 (let ((start (point))
2654 (tree (or class ebrowse--displayed-class))
106ba1bb 2655 class-name-start
be0dbdab
GM
2656 class-name-end)
2657 (insert "class ")
2658 (setq class-name-start (point))
2659 (insert (ebrowse-qualified-class-name (ebrowse-ts-class tree)))
2660 (when (ebrowse-template-p (ebrowse-ts-class tree))
2661 (insert "<>"))
2662 (setq class-name-end (point))
2663 (insert ":\n\n")
4f2d55da 2664 (ebrowse-set-face start (point) 'ebrowse-member-class)
be0dbdab
GM
2665 (add-text-properties
2666 class-name-start class-name-end
2667 '(ebrowse-what class-name
2668 mouse-face highlight
2669 help-echo "mouse-3: menu"))
2670 (put-text-property start class-name-end 'ebrowse-tree tree)))
2671
2672
2673(defun ebrowse-display-member-buffer (list &optional stand-alone class)
2674 "Start point for member buffer creation.
2675LIST is the member list to display. STAND-ALONE non-nil
2676means the member buffer is standalone. CLASS is its class."
2677 (let* ((classes ebrowse--tree-obarray)
2678 (tree ebrowse--tree)
e02f48d7 2679 (tags-file ebrowse--tags-file-name)
be0dbdab
GM
2680 (header ebrowse--header)
2681 temp-buffer-setup-hook
2682 (temp-buffer (get-buffer ebrowse-member-buffer-name)))
2683 ;; Get the class description from the name the cursor
2684 ;; is on if not specified as an argument.
2685 (unless class
2686 (setq class (ebrowse-tree-at-point)))
ce4746a3
CY
2687 (save-selected-window
2688 (if temp-buffer
2689 (pop-to-buffer temp-buffer)
2690 (pop-to-buffer (get-buffer-create ebrowse-member-buffer-name))
be0dbdab 2691 ;; If new buffer, set the mode and initial values of locals
ce4746a3
CY
2692 (ebrowse-member-mode))
2693 ;; Set local variables
2694 (setq ebrowse--member-list (funcall list class)
2695 ebrowse--displayed-class class
2696 ebrowse--accessor list
2697 ebrowse--tree-obarray classes
2698 ebrowse--frozen-flag stand-alone
e02f48d7 2699 ebrowse--tags-file-name tags-file
ce4746a3
CY
2700 ebrowse--header header
2701 ebrowse--tree tree
2702 buffer-read-only t)
2703 (ebrowse-redisplay-member-buffer)
2704 (current-buffer))))
be0dbdab
GM
2705
2706
2707(defun ebrowse-member-display-p (member)
2708 "Return t if MEMBER must be displayed under the current filter settings."
2709 (if (and (aref ebrowse--filters (ebrowse-ms-visibility member))
2710 (or (null ebrowse--const-display-flag)
2711 (ebrowse-const-p member))
2712 (or (null ebrowse--inline-display-flag)
2713 (ebrowse-inline-p member))
2714 (or (null ebrowse--pure-display-flag)
2715 (ebrowse-bs-p member))
2716 (or (null ebrowse--virtual-display-flag)
2717 (ebrowse-virtual-p member)))
2718 member))
2719
2720
2721(defun ebrowse-draw-member-attributes (member)
2722 "Insert a string for the attributes of MEMBER."
2723 (insert (if (ebrowse-template-p member) "T" "-")
2724 (if (ebrowse-extern-c-p member) "C" "-")
2725 (if (ebrowse-virtual-p member) "v" "-")
2726 (if (ebrowse-inline-p member) "i" "-")
2727 (if (ebrowse-const-p member) "c" "-")
2728 (if (ebrowse-pure-virtual-p member) "0" "-")
2729 (if (ebrowse-mutable-p member) "m" "-")
2730 (if (ebrowse-explicit-p member) "e" "-")
2731 (if (ebrowse-throw-list-p member) "t" "-")))
2732
2733
2734(defun ebrowse-draw-member-regexp (member-struc)
2735 "Insert a string for the regular expression matching MEMBER-STRUC."
2736 (let ((pattern (if ebrowse--source-regexp-flag
2737 (ebrowse-ms-definition-pattern
2738 member-struc)
2739 (ebrowse-ms-pattern member-struc))))
2740 (cond ((stringp pattern)
2741 (insert (ebrowse-trim-string pattern) "...\n")
2742 (beginning-of-line 0)
2743 (move-to-column (+ 4 ebrowse--decl-column))
2744 (while (re-search-forward "[ \t]+" nil t)
2745 (delete-region (match-beginning 0) (match-end 0))
2746 (insert " "))
2747 (beginning-of-line 2))
2748 (t
2749 (insert "[not recorded or unknown]\n")))))
2750
2751
2752(defun ebrowse-draw-member-long-fn (member-list tree)
2753 "Display member buffer for MEMBER-LIST in long form.
2754TREE is the class tree of MEMBER-LIST."
2755 (dolist (member-struc (mapcar 'ebrowse-member-display-p member-list))
2756 (when member-struc
2757 (let ((name (ebrowse-ms-name member-struc))
2758 (start (point)))
2759 ;; Insert member name truncated to the right length
2760 (insert (substring name
2761 0
2762 (min (length name)
2763 (1- ebrowse--decl-column))))
2764 (add-text-properties
2765 start (point)
2766 `(mouse-face highlight ebrowse-what member-name
2767 ebrowse-member ,member-struc
2768 ebrowse-tree ,tree
2769 help-echo "mouse-2: view definition; mouse-3: menu"))
2770 ;; Display virtual, inline, and const status
2771 (setf start (point))
2772 (indent-to ebrowse--decl-column)
2773 (put-text-property start (point) 'mouse-face nil)
2774 (when ebrowse--attributes-flag
2775 (let ((start (point)))
2776 (insert "<")
2777 (ebrowse-draw-member-attributes member-struc)
2778 (insert ">")
2779 (ebrowse-set-face start (point)
4f2d55da 2780 'ebrowse-member-attribute)))
be0dbdab
GM
2781 (insert " ")
2782 (ebrowse-draw-member-regexp member-struc))))
2783 (insert "\n")
2784 (goto-char (point-min)))
2785
2786
2787(defun ebrowse-draw-member-short-fn (member-list tree)
2788 "Display MEMBER-LIST in short form.
2789TREE is the class tree in which the members are found."
2790 (let ((i 0)
2791 (column-width (+ ebrowse--column-width
2792 (if ebrowse--attributes-flag 12 0))))
2793 ;; Get the number of columns to draw.
2794 (setq ebrowse--n-columns
2795 (max 1 (/ (ebrowse-width-of-drawable-area) column-width)))
2796 (dolist (member (mapcar #'ebrowse-member-display-p member-list))
2797 (when member
2798 (let ((name (ebrowse-ms-name member))
2799 start-of-entry
2800 (start-of-column (point))
2801 start-of-name)
2802 (indent-to (* i column-width))
2803 (put-text-property start-of-column (point) 'mouse-face nil)
2804 (setq start-of-entry (point))
106ba1bb 2805 ;; Show various attributes
be0dbdab
GM
2806 (when ebrowse--attributes-flag
2807 (insert "<")
2808 (ebrowse-draw-member-attributes member)
2809 (insert "> ")
2810 (ebrowse-set-face start-of-entry (point)
4f2d55da 2811 'ebrowse-member-attribute))
be0dbdab
GM
2812 ;; insert member name truncated to column width
2813 (setq start-of-name (point))
2814 (insert (substring name 0
2815 (min (length name)
2816 (1- ebrowse--column-width))))
2817 ;; set text properties
2818 (add-text-properties
2819 start-of-name (point)
2820 `(ebrowse-what member-name
2821 ebrowse-member ,member
2822 mouse-face highlight
2823 ebrowse-tree ,tree
2824 help-echo "mouse-2: view definition; mouse-3: menu"))
2825 (incf i)
2826 (when (>= i ebrowse--n-columns)
2827 (setf i 0)
2828 (insert "\n")))))
2829 (when (plusp i)
2830 (insert "\n"))
2831 (goto-char (point-min))))
2832
2833
2834\f
2835;;; Killing members from tree
2836
2837(defun ebrowse-member-info-from-point ()
2838 "Ger information about the member at point.
2839The result has the form (TREE MEMBER NULL-P). TREE is the tree
2840we're in, MEMBER is the member we're on. NULL-P is t if MEMBER
2841is nil."
2842 (let ((tree (or (get-text-property (point) 'ebrowse-tree)
2843 (error "No information at point")))
2844 (member (get-text-property (point) 'ebrowse-member)))
2845 (list tree member (null member))))
2846
2847
2848\f
2849;;; Switching member buffer to display a selected member
2850
e02f48d7 2851(defun ebrowse-goto-visible-member/all-member-lists (_prefix)
be0dbdab
GM
2852 "Position cursor on a member read from the minibuffer.
2853With PREFIX, search all members in the tree. Otherwise consider
2854only members visible in the buffer."
2855 (interactive "p")
2856 (ebrowse-ignoring-completion-case
2857 (let* ((completion-list (ebrowse-name/accessor-alist-for-class-members))
2858 (member (completing-read "Goto member: " completion-list nil t))
2859 (accessor (cdr (assoc member completion-list))))
2860 (unless accessor
2861 (error "`%s' not found" member))
2862 (unless (eq accessor ebrowse--accessor)
2863 (setf ebrowse--accessor accessor
2864 ebrowse--member-list (funcall accessor ebrowse--displayed-class))
2865 (ebrowse-redisplay-member-buffer))
2866 (ebrowse-move-point-to-member member))))
2867
2868
2869(defun ebrowse-goto-visible-member (repeat)
2870 "Position point on a member.
2871Read the member's name from the minibuffer. Consider only members
2872visible in the member buffer.
2873REPEAT non-nil means repeat the search that number of times."
2874 (interactive "p")
2875 (ebrowse-ignoring-completion-case
2876 ;; Read member name
2877 (let* ((completion-list (ebrowse-name/accessor-alist-for-visible-members))
2878 (member (completing-read "Goto member: " completion-list nil t)))
2879 (ebrowse-move-point-to-member member repeat))))
2880
2881
2882\f
2883;;; Searching a member in the member buffer
2884
2885(defun ebrowse-repeat-member-search (repeat)
2886 "Repeat the last regular expression search.
2887REPEAT, if specified, says repeat the search REPEAT times."
2888 (interactive "p")
2889 (unless ebrowse--last-regexp
2890 (error "No regular expression remembered"))
2891 ;; Skip over word the point is on
2892 (skip-chars-forward "^ \t\n")
2893 ;; Search for regexp from point
2894 (if (re-search-forward ebrowse--last-regexp nil t repeat)
2895 (progn
2896 (goto-char (match-beginning 0))
2897 (skip-chars-forward " \t\n"))
2898 ;; If not found above, repeat search from buffer start
2899 (goto-char (point-min))
2900 (if (re-search-forward ebrowse--last-regexp nil t)
2901 (progn
2902 (goto-char (match-beginning 0))
2903 (skip-chars-forward " \t\n"))
2904 (error "Not found"))))
2905
2906
2907(defun* ebrowse-move-point-to-member (name &optional count &aux member)
2908 "Set point on member NAME in the member buffer
2909COUNT, if specified, says search the COUNT'th member with the same name."
2910 (goto-char (point-min))
2911 (widen)
2912 (setq member
2913 (substring name 0 (min (length name) (1- ebrowse--column-width)))
2914 ebrowse--last-regexp
2915 (concat "[ \t\n]" (regexp-quote member) "[ \n\t]"))
2916 (if (re-search-forward ebrowse--last-regexp nil t count)
2917 (goto-char (1+ (match-beginning 0)))
2918 (error "Not found")))
2919
2920
2921\f
2922;;; Switching member buffer to another class.
2923
2924(defun ebrowse-switch-member-buffer-to-other-class (title compl-list)
2925 "Switch member buffer to a class read from the minibuffer.
2926Use TITLE as minibuffer prompt.
2927COMPL-LIST is a completion list to use."
2928 (let* ((initial (unless (second compl-list)
2929 (first (first compl-list))))
2930 (class (or (ebrowse-completing-read-value title compl-list initial)
2931 (error "Not found"))))
2932 (setf ebrowse--displayed-class class
2933 ebrowse--member-list (funcall ebrowse--accessor ebrowse--displayed-class))
2934 (ebrowse-redisplay-member-buffer)))
2935
2936
2937(defun ebrowse-switch-member-buffer-to-any-class ()
2938 "Switch member buffer to a class read from the minibuffer."
2939 (interactive)
2940 (ebrowse-switch-member-buffer-to-other-class
2941 "Goto class: " (ebrowse-tree-obarray-as-alist)))
2942
2943
2944(defun ebrowse-switch-member-buffer-to-base-class (arg)
2945 "Switch buffer to ARG'th base class."
2946 (interactive "P")
2947 (let ((supers (or (ebrowse-direct-base-classes ebrowse--displayed-class)
2948 (error "No base classes"))))
2949 (if (and arg (second supers))
2950 (let ((alist (loop for s in supers
2951 collect (cons (ebrowse-qualified-class-name
2952 (ebrowse-ts-class s))
2953 s))))
2954 (ebrowse-switch-member-buffer-to-other-class
2955 "Goto base class: " alist))
2956 (setq ebrowse--displayed-class (first supers)
2957 ebrowse--member-list
2958 (funcall ebrowse--accessor ebrowse--displayed-class))
2959 (ebrowse-redisplay-member-buffer))))
2960
2961(defun ebrowse-switch-member-buffer-to-next-sibling-class (arg)
2962 "Move to ARG'th next sibling."
2963 (interactive "p")
2964 (ebrowse-switch-member-buffer-to-sibling-class arg))
2965
2966
2967(defun ebrowse-switch-member-buffer-to-previous-sibling-class (arg)
2968 "Move to ARG'th previous sibling."
2969 (interactive "p")
2970 (ebrowse-switch-member-buffer-to-sibling-class (- arg)))
2971
2972
2973(defun ebrowse-switch-member-buffer-to-sibling-class (inc)
2974 "Switch member display to nth sibling class.
2975Prefix arg INC specifies which one."
2976 (interactive "p")
2977 (let ((containing-list ebrowse--tree)
2978 index cls
2979 (supers (ebrowse-direct-base-classes ebrowse--displayed-class)))
2980 (flet ((trees-alist (trees)
2981 (loop for tr in trees
2982 collect (cons (ebrowse-cs-name
2983 (ebrowse-ts-class tr)) tr))))
2984 (when supers
2985 (let ((tree (if (second supers)
2986 (ebrowse-completing-read-value
2987 "Relative to base class: "
2988 (trees-alist supers) nil)
2989 (first supers))))
2990 (unless tree (error "Not found"))
2991 (setq containing-list (ebrowse-ts-subclasses tree)))))
2992 (setq index (+ inc (ebrowse-position ebrowse--displayed-class
2993 containing-list)))
2994 (cond ((minusp index) (message "No previous class"))
2995 ((null (nth index containing-list)) (message "No next class")))
2996 (setq index (max 0 (min index (1- (length containing-list)))))
2997 (setq cls (nth index containing-list))
2998 (setf ebrowse--displayed-class cls
2999 ebrowse--member-list (funcall ebrowse--accessor cls))
3000 (ebrowse-redisplay-member-buffer)))
3001
3002
3003(defun ebrowse-switch-member-buffer-to-derived-class (arg)
3004 "Switch member display to nth derived class.
3005Prefix arg ARG says which class should be displayed. Default is
3006the first derived class."
3007 (interactive "P")
106ba1bb 3008 (flet ((ebrowse-tree-obarray-as-alist ()
be0dbdab
GM
3009 (loop for s in (ebrowse-ts-subclasses
3010 ebrowse--displayed-class)
3011 collect (cons (ebrowse-cs-name
3012 (ebrowse-ts-class s)) s))))
3013 (let ((subs (or (ebrowse-ts-subclasses ebrowse--displayed-class)
3014 (error "No derived classes"))))
3015 (if (and arg (second subs))
3016 (ebrowse-switch-member-buffer-to-other-class
3017 "Goto derived class: " (ebrowse-tree-obarray-as-alist))
3018 (setq ebrowse--displayed-class (first subs)
3019 ebrowse--member-list
3020 (funcall ebrowse--accessor ebrowse--displayed-class))
3021 (ebrowse-redisplay-member-buffer)))))
3022
3023
3024\f
3025;;; Member buffer mouse functions
3026
3027(defun ebrowse-displaying-functions ()
3028 (eq ebrowse--accessor 'ebrowse-ts-member-functions))
3029(defun ebrowse-displaying-variables ()
3030 (eq ebrowse--accessor 'ebrowse-ts-member-variables))
3031(defun ebrowse-displaying-static-functions ()
3032 )
3033(defun ebrowse-displaying-static-variables ()
3034 )
3035(defun ebrowse-displaying-types ()
3036 (eq ebrowse--accessor 'ebrowse-ts-types))
3037(defun ebrowse-displaying-friends ()
3038 (eq ebrowse--accessor 'ebrowse-ts-friends))
3039
3040(easy-menu-define
3041 ebrowse-member-buffer-object-menu ebrowse-member-mode-map
3042 "Object menu for the member buffer itself."
3043 '("Members"
3044 ("Members List"
3045 ["Functions" ebrowse-display-function-member-list
3046 :help "Show the list of member functions"
3047 :style radio
3048 :selected (eq ebrowse--accessor 'ebrowse-ts-member-functions)
3049 :active t]
3050 ["Variables" ebrowse-display-variables-member-list
3051 :help "Show the list of member variables"
3052 :style radio
3053 :selected (eq ebrowse--accessor 'ebrowse-ts-member-variables)
3054 :active t]
3055 ["Static Functions" ebrowse-display-static-functions-member-list
3056 :help "Show the list of static member functions"
3057 :style radio
3058 :selected (eq ebrowse--accessor 'ebrowse-ts-static-functions)
3059 :active t]
3060 ["Static Variables" ebrowse-display-static-variables-member-list
3061 :help "Show the list of static member variables"
3062 :style radio
3063 :selected (eq ebrowse--accessor 'ebrowse-ts-static-variables)
3064 :active t]
3065 ["Types" ebrowse-display-types-member-list
3066 :help "Show the list of nested types"
3067 :style radio
3068 :selected (eq ebrowse--accessor 'ebrowse-ts-types)
3069 :active t]
3070 ["Friends/Defines" ebrowse-display-friends-member-list
3071 :help "Show the list of friends or defines"
3072 :style radio
3073 :selected (eq ebrowse--accessor 'ebrowse-ts-friends)
3074 :active t])
3075 ("Class"
3076 ["Up" ebrowse-switch-member-buffer-to-base-class
3077 :help "Show the base class of this class"
3078 :active t]
3079 ["Down" ebrowse-switch-member-buffer-to-derived-class
3080 :help "Show a derived class class of this class"
3081 :active t]
3082 ["Next Sibling" ebrowse-switch-member-buffer-to-next-sibling-class
3083 :help "Show the next sibling class"
3084 :active t]
3085 ["Previous Sibling" ebrowse-switch-member-buffer-to-previous-sibling-class
3086 :help "Show the previous sibling class"
3087 :active t])
3088 ("Member"
3089 ["Show in Tree" ebrowse-show-displayed-class-in-tree
3090 :help "Show this class in the class tree"
3091 :active t]
3092 ["Find in this Class" ebrowse-goto-visible-member
3093 :help "Search for a member of this class"
3094 :active t]
3095 ["Find in Tree" ebrowse-goto-visible-member/all-member-lists
3096 :help "Search for a member in any class"
3097 :active t])
106ba1bb 3098 ("Display"
be0dbdab
GM
3099 ["Inherited" ebrowse-toggle-base-class-display
3100 :help "Toggle display of inherited members"
3101 :style toggle
3102 :selected ebrowse--show-inherited-flag
3103 :active t]
3104 ["Attributes" ebrowse-toggle-member-attributes-display
3105 :help "Show member attributes"
3106 :style toggle
3107 :selected ebrowse--attributes-flag
3108 :active t]
3109 ["Long Display" ebrowse-toggle-long-short-display
3110 :help "Toggle the member display format"
3111 :style toggle
3112 :selected ebrowse--long-display-flag
3113 :active t]
3114 ["Column Width" ebrowse-set-member-buffer-column-width
3115 :help "Set the display's column width"
3116 :active t])
3117 ("Filter"
3118 ["Public" ebrowse-toggle-public-member-filter
3119 :help "Toggle the visibility of public members"
3120 :style toggle
3121 :selected (not (aref ebrowse--filters 0))
3122 :active t]
3123 ["Protected" ebrowse-toggle-protected-member-filter
3124 :help "Toggle the visibility of protected members"
3125 :style toggle
3126 :selected (not (aref ebrowse--filters 1))
3127 :active t]
3128 ["Private" ebrowse-toggle-private-member-filter
3129 :help "Toggle the visibility of private members"
3130 :style toggle
3131 :selected (not (aref ebrowse--filters 2))
3132 :active t]
3133 ["Virtual" ebrowse-toggle-virtual-member-filter
3134 :help "Toggle the visibility of virtual members"
3135 :style toggle
3136 :selected ebrowse--virtual-display-flag
3137 :active t]
3138 ["Inline" ebrowse-toggle-inline-member-filter
3139 :help "Toggle the visibility of inline members"
3140 :style toggle
3141 :selected ebrowse--inline-display-flag
3142 :active t]
3143 ["Const" ebrowse-toggle-const-member-filter
3144 :help "Toggle the visibility of const members"
3145 :style toggle
3146 :selected ebrowse--const-display-flag
3147 :active t]
3148 ["Pure" ebrowse-toggle-pure-member-filter
3149 :help "Toggle the visibility of pure virtual members"
3150 :style toggle
3151 :selected ebrowse--pure-display-flag
3152 :active t]
3153 "-----------------"
3154 ["Show all" ebrowse-remove-all-member-filters
3155 :help "Remove any display filters"
3156 :active t])
3157 ("Buffer"
3158 ["Tree" ebrowse-pop-from-member-to-tree-buffer
3159 :help "Pop to the class tree buffer"
3160 :active t]
3161 ["Next Member Buffer" ebrowse-switch-to-next-member-buffer
3162 :help "Switch to the next member buffer of this class tree"
3163 :active t]
3164 ["Freeze" ebrowse-freeze-member-buffer
3165 :help "Freeze (do not reuse) this member buffer"
3166 :active t])))
3167
3168
3169(defun ebrowse-on-class-name ()
3170 "Value is non-nil if point is on a class name."
3171 (eq (get-text-property (point) 'ebrowse-what) 'class-name))
3172
3173
3174(defun ebrowse-on-member-name ()
3175 "Value is non-nil if point is on a member name."
3176 (eq (get-text-property (point) 'ebrowse-what) 'member-name))
3177
3178
3179(easy-menu-define
3180 ebrowse-member-class-name-object-menu ebrowse-member-mode-map
3181 "Object menu for class names in member buffer."
3182 '("Class"
3183 ["Find" ebrowse-find-member-definition
3184 :help "Find this class in the source files"
3185 :active (eq (get-text-property (point) 'ebrowse-what) 'class-name)]
3186 ["View" ebrowse-view-member-definition
3187 :help "View this class in the source files"
3188 :active (eq (get-text-property (point) 'ebrowse-what) 'class-name)]))
3189
3190
106ba1bb 3191(easy-menu-define
be0dbdab
GM
3192 ebrowse-member-name-object-menu ebrowse-member-mode-map
3193 "Object menu for member names"
3194 '("Ebrowse"
3195 ["Find Definition" ebrowse-find-member-definition
3196 :help "Find this member's definition in the source files"
3197 :active (ebrowse-on-member-name)]
3198 ["Find Declaration" ebrowse-find-member-declaration
3199 :help "Find this member's declaration in the source files"
3200 :active (ebrowse-on-member-name)]
3201 ["View Definition" ebrowse-view-member-definition
3202 :help "View this member's definition in the source files"
3203 :active (ebrowse-on-member-name)]
3204 ["View Declaration" ebrowse-view-member-declaration
3205 :help "View this member's declaration in the source files"
3206 :active (ebrowse-on-member-name)]))
3207
3208
3209(defun ebrowse-member-mouse-3 (event)
3210 "Handle `mouse-3' events in member buffers.
3211EVENT is the mouse event."
3212 (interactive "e")
3213 (mouse-set-point event)
3214 (case (event-click-count event)
3215 (2 (ebrowse-find-member-definition))
3216 (1 (case (get-text-property (posn-point (event-start event))
3217 'ebrowse-what)
3218 (member-name
3219 (ebrowse-popup-menu ebrowse-member-name-object-menu event))
3220 (class-name
3221 (ebrowse-popup-menu ebrowse-member-class-name-object-menu event))
3222 (t
3223 (ebrowse-popup-menu ebrowse-member-buffer-object-menu event))))))
3224
3225
3226(defun ebrowse-member-mouse-2 (event)
3227 "Handle `mouse-2' events in member buffers.
3228EVENT is the mouse event."
3229 (interactive "e")
3230 (mouse-set-point event)
3231 (case (event-click-count event)
3232 (2 (ebrowse-find-member-definition))
3233 (1 (case (get-text-property (posn-point (event-start event))
3234 'ebrowse-what)
3235 (member-name
3236 (ebrowse-view-member-definition 0))))))
3237
3238
3239\f
3240;;; Tags view/find
3241
3242(defun ebrowse-class-alist-for-member (tree-header name)
3243 "Return information about a member in a class tree.
3244TREE-HEADER is the header structure of the class tree.
3245NAME is the name of the member.
3246Value is an alist of elements (CLASS-NAME . (CLASS LIST NAME)),
3247where each element describes one occurrence of member NAME in the tree.
106ba1bb 3248CLASS-NAME is the qualified name of the class in which the
be0dbdab
GM
3249member was found. The CDR of the acons is described in function
3250`ebrowse-class/index/member-for-member'."
3251 (let ((table (ebrowse-member-table tree-header))
3252 known-classes
3253 alist)
3254 (when name
3255 (dolist (info (gethash name table) alist)
3256 (unless (memq (first info) known-classes)
3257 (setf alist (acons (ebrowse-qualified-class-name
3258 (ebrowse-ts-class (first info)))
3259 info alist)
3260 known-classes (cons (first info) known-classes)))))))
3261
3262
3263(defun ebrowse-choose-tree ()
3264 "Choose a class tree to use.
3265If there's more than one class tree loaded, let the user choose
3266the one he wants. Value is (TREE HEADER BUFFER), with TREE being
3267the class tree, HEADER the header structure of the tree, and BUFFER
3268being the tree or member buffer containing the tree."
3269 (let* ((buffer (ebrowse-choose-from-browser-buffers)))
3270 (if buffer (list (ebrowse-value-in-buffer 'ebrowse--tree buffer)
3271 (ebrowse-value-in-buffer 'ebrowse--header buffer)
3272 buffer))))
3273
3274
3275(defun ebrowse-tags-read-name (header prompt)
3276 "Read a C++ identifier from the minibuffer.
3277HEADER is the `ebrowse-hs' structure of the class tree.
3278Prompt with PROMPT. Insert into the minibuffer a C++ identifier read
3279from point as default. Value is a list (CLASS-NAME MEMBER-NAME)."
3280 (save-excursion
e02f48d7 3281 (let ((members (ebrowse-member-table header)))
be0dbdab 3282 (multiple-value-bind (class-name member-name)
3c2fbb99 3283 (values-list (ebrowse-tags-read-member+class-name))
be0dbdab
GM
3284 (unless member-name
3285 (error "No member name at point"))
3286 (if members
47932cf8
SM
3287 (let* ((name (ebrowse-ignoring-completion-case
3288 (completing-read prompt members nil nil member-name)))
3289 (completion-result (try-completion name members)))
0ff9b955 3290 ;; Cannot rely on `try-completion' returning t for exact
110c171f 3291 ;; matches! It returns the name as a string.
e02f48d7 3292 (unless (gethash name members)
be0dbdab 3293 (if (y-or-n-p "No exact match found. Try substrings? ")
106ba1bb
JB
3294 (setq name
3295 (or (first (ebrowse-list-of-matching-members
be0dbdab
GM
3296 members (regexp-quote name) name))
3297 (error "Sorry, nothing found")))
3298 (error "Canceled")))
3299 (list class-name name))
3300 (list class-name (read-from-minibuffer prompt member-name)))))))
3301
3302
3303(defun ebrowse-tags-read-member+class-name ()
3304 "Read a C++ identifier from point.
3305Value is (CLASS-NAME MEMBER-NAME).
3306CLASS-NAME is the name of the class if the identifier was qualified.
3307It is nil otherwise.
3308MEMBER-NAME is the name of the member found."
3309 (save-excursion
3310 (skip-chars-backward "a-zA-Z0-9_")
3311 (let* ((start (point))
3312 (name (progn (skip-chars-forward "a-zA-Z0-9_")
3313 (buffer-substring start (point))))
3314 class)
3315 (list class name))))
3316
3317
e02f48d7 3318(defun ebrowse-tags-choose-class (_tree header name initial-class-name)
be0dbdab
GM
3319 "Read a class name for a member from the minibuffer.
3320TREE is the class tree we operate on.
3321HEADER is its header structure.
3322NAME is the name of the member.
3323INITIAL-CLASS-NAME is an initial class name to insert in the minibuffer.
3324Value is a list (TREE ACCESSOR MEMBER) for the member."
3325 (let ((alist (or (ebrowse-class-alist-for-member header name)
3326 (error "No classes with member `%s' found" name))))
3327 (ebrowse-ignoring-completion-case
3328 (if (null (second alist))
3329 (cdr (first alist))
3330 (push ?\? unread-command-events)
3331 (cdr (assoc (completing-read "In class: "
3332 alist nil t initial-class-name)
3333 alist))))))
3334
3335
3336(defun* ebrowse-tags-view/find-member-decl/defn
3337 (prefix &key view definition member-name)
3338 "If VIEW is t, view, else find an occurrence of MEMBER-NAME.
3339
3340If DEFINITION is t, find or view the member definition else its
3341declaration. This function reads the member's name from the
3342current buffer like FIND-TAG. It then prepares a completion list
3343of all classes containing a member with the given name and lets
3344the user choose the class to use. As a last step, a tags search
3345is performed that positions point on the member declaration or
3346definition."
3347 (multiple-value-bind
3c2fbb99 3348 (tree header tree-buffer) (values-list (ebrowse-choose-tree))
be0dbdab
GM
3349 (unless tree (error "No class tree"))
3350 (let* ((marker (point-marker))
3351 class-name
3352 (name member-name)
3353 info)
3354 (unless name
3355 (multiple-value-setq (class-name name)
e02f48d7 3356 (values-list
3c2fbb99
DG
3357 (ebrowse-tags-read-name
3358 header
3359 (concat (if view "View" "Find") " member "
3360 (if definition "definition" "declaration") ": ")))))
be0dbdab
GM
3361 (setq info (ebrowse-tags-choose-class tree header name class-name))
3362 (ebrowse-push-position marker info)
3363 ;; Goto the occurrence of the member
3364 (ebrowse-view/find-member-declaration/definition
3365 prefix view definition info
3366 header
3367 (ebrowse-value-in-buffer 'ebrowse--tags-file-name tree-buffer))
3368 ;; Record position jumped to
3369 (ebrowse-push-position (point-marker) info t))))
3370
3371
8cbb7c61 3372;;;###autoload
be0dbdab
GM
3373(defun ebrowse-tags-view-declaration ()
3374 "View declaration of member at point."
3375 (interactive)
3376 (ebrowse-tags-view/find-member-decl/defn 0 :view t :definition nil))
3377
3378
8cbb7c61 3379;;;###autoload
be0dbdab
GM
3380(defun ebrowse-tags-find-declaration ()
3381 "Find declaration of member at point."
3382 (interactive)
3383 (ebrowse-tags-view/find-member-decl/defn 0 :view nil :definition nil))
3384
3385
8cbb7c61 3386;;;###autoload
be0dbdab
GM
3387(defun ebrowse-tags-view-definition ()
3388 "View definition of member at point."
3389 (interactive)
3390 (ebrowse-tags-view/find-member-decl/defn 0 :view t :definition t))
3391
3392
8cbb7c61 3393;;;###autoload
be0dbdab
GM
3394(defun ebrowse-tags-find-definition ()
3395 "Find definition of member at point."
3396 (interactive)
3397 (ebrowse-tags-view/find-member-decl/defn 0 :view nil :definition t))
3398
3399
3400(defun ebrowse-tags-view-declaration-other-window ()
3401 "View declaration of member at point in other window."
3402 (interactive)
3403 (ebrowse-tags-view/find-member-decl/defn 4 :view t :definition nil))
3404
3405
8cbb7c61 3406;;;###autoload
be0dbdab
GM
3407(defun ebrowse-tags-find-declaration-other-window ()
3408 "Find declaration of member at point in other window."
3409 (interactive)
3410 (ebrowse-tags-view/find-member-decl/defn 4 :view nil :definition nil))
3411
3412
8cbb7c61 3413;;;###autoload
be0dbdab
GM
3414(defun ebrowse-tags-view-definition-other-window ()
3415 "View definition of member at point in other window."
3416 (interactive)
3417 (ebrowse-tags-view/find-member-decl/defn 4 :view t :definition t))
3418
3419
8cbb7c61 3420;;;###autoload
be0dbdab
GM
3421(defun ebrowse-tags-find-definition-other-window ()
3422 "Find definition of member at point in other window."
3423 (interactive)
3424 (ebrowse-tags-view/find-member-decl/defn 4 :view nil :definition t))
3425
3426
3427(defun ebrowse-tags-view-declaration-other-frame ()
3428 "View definition of member at point in other frame."
3429 (interactive)
3430 (ebrowse-tags-view/find-member-decl/defn 5 :view t :definition nil))
3431
3432
8cbb7c61 3433;;;###autoload
be0dbdab
GM
3434(defun ebrowse-tags-find-declaration-other-frame ()
3435 "Find definition of member at point in other frame."
3436 (interactive)
3437 (ebrowse-tags-view/find-member-decl/defn 5 :view nil :definition nil))
3438
3439
8cbb7c61 3440;;;###autoload
be0dbdab
GM
3441(defun ebrowse-tags-view-definition-other-frame ()
3442 "View definition of member at point in other frame."
3443 (interactive)
3444 (ebrowse-tags-view/find-member-decl/defn 5 :view t :definition t))
3445
3446
8cbb7c61 3447;;;###autoload
be0dbdab
GM
3448(defun ebrowse-tags-find-definition-other-frame ()
3449 "Find definition of member at point in other frame."
3450 (interactive)
3451 (ebrowse-tags-view/find-member-decl/defn 5 :view nil :definition t))
3452
3453
3454(defun ebrowse-tags-select/create-member-buffer (tree-buffer info)
3455 "Select or create member buffer.
3456TREE-BUFFER specifies the tree to use. INFO describes the member.
3457It is a list (TREE ACCESSOR MEMBER)."
3458 (let ((buffer (get-buffer ebrowse-member-buffer-name)))
3459 (cond ((null buffer)
3460 (set-buffer tree-buffer)
3461 (switch-to-buffer (ebrowse-display-member-buffer
3462 (second info) nil (first info))))
3463 (t
3464 (switch-to-buffer buffer)
3465 (setq ebrowse--displayed-class (first info)
3466 ebrowse--accessor (second info)
3467 ebrowse--member-list (funcall ebrowse--accessor ebrowse--displayed-class))
3468 (ebrowse-redisplay-member-buffer)))
3469 (ebrowse-move-point-to-member (ebrowse-ms-name (third info)))))
3470
3471
3472(defun ebrowse-tags-display-member-buffer (&optional fix-name)
3473 "Display a member buffer for a member.
3474FIX-NAME non-nil means display the buffer for that member.
3475Otherwise read a member name from point."
3476 (interactive)
3477 (multiple-value-bind
3c2fbb99 3478 (tree header tree-buffer) (values-list (ebrowse-choose-tree))
be0dbdab
GM
3479 (unless tree (error "No class tree"))
3480 (let* ((marker (point-marker)) class-name (name fix-name) info)
3481 (unless name
3482 (multiple-value-setq (class-name name)
e02f48d7 3483 (values-list
3c2fbb99
DG
3484 (ebrowse-tags-read-name header
3485 (concat "Find member list of: ")))))
be0dbdab
GM
3486 (setq info (ebrowse-tags-choose-class tree header name class-name))
3487 (ebrowse-push-position marker info)
3488 (ebrowse-tags-select/create-member-buffer tree-buffer info))))
3489
3490
3491(defun ebrowse-list-of-matching-members (members regexp &optional name)
3492 "Return a list of members in table MEMBERS matching REGEXP or NAME.
3493Both NAME and REGEXP may be nil in which case exact or regexp matches
3494are not performed."
3495 (let (list)
3496 (when (or name regexp)
e02f48d7
JB
3497 (maphash (lambda (member-name _info)
3498 (when (or (and name (string= name member-name))
3499 (and regexp (string-match regexp member-name)))
3500 (setq list (cons member-name list))))
be0dbdab
GM
3501 members))
3502 list))
3503
3504
3505(defun ebrowse-tags-apropos ()
3506 "Display a list of members matching a regexp read from the minibuffer."
3507 (interactive)
3508 (let* ((buffer (or (ebrowse-choose-from-browser-buffers)
3509 (error "No tree buffer")))
3510 (header (ebrowse-value-in-buffer 'ebrowse--header buffer))
3511 (members (ebrowse-member-table header))
3512 temp-buffer-setup-hook
3513 (regexp (read-from-minibuffer "List members matching regexp: ")))
3514 (with-output-to-temp-buffer (concat "*Apropos Members*")
3515 (set-buffer standard-output)
3516 (erase-buffer)
3517 (insert "Members matching `" regexp "'\n\n")
3518 (loop for s in (ebrowse-list-of-matching-members members regexp) do
3519 (loop for info in (gethash s members) do
3520 (ebrowse-draw-file-member-info info))))))
3521
3522
3523(defun ebrowse-tags-list-members-in-file ()
3524 "Display a list of members found in a file.
3525The file name is read from the minibuffer."
3526 (interactive)
3527 (let* ((buffer (or (ebrowse-choose-from-browser-buffers)
3528 (error "No tree buffer")))
9a529312 3529 (files (with-current-buffer buffer (ebrowse-files-table)))
47932cf8 3530 (file (completing-read "List members in file: " files nil t))
be0dbdab
GM
3531 (header (ebrowse-value-in-buffer 'ebrowse--header buffer))
3532 temp-buffer-setup-hook
3533 (members (ebrowse-member-table header)))
3534 (with-output-to-temp-buffer (concat "*Members in file " file "*")
3535 (set-buffer standard-output)
3536 (maphash
e02f48d7
JB
3537 (lambda (_member-name list)
3538 (loop for info in list
3539 as member = (third info)
3540 as class = (ebrowse-ts-class (first info))
3541 when (or (and (null (ebrowse-ms-file member))
3542 (string= (ebrowse-cs-file class) file))
3543 (string= file (ebrowse-ms-file member)))
3544 do (ebrowse-draw-file-member-info info "decl.")
3545 when (or (and (null (ebrowse-ms-definition-file member))
3546 (string= (ebrowse-cs-source-file class) file))
3547 (string= file (ebrowse-ms-definition-file member)))
3548 do (ebrowse-draw-file-member-info info "defn.")))
be0dbdab
GM
3549 members))))
3550
3551
3552(defun* ebrowse-draw-file-member-info (info &optional (kind ""))
00a2367d 3553 "Display a line in the members info buffer.
be0dbdab
GM
3554INFO describes the member. It has the form (TREE ACCESSOR MEMBER).
3555TREE is the class of the member to display.
3556ACCESSOR is the accessor symbol of its member list.
3557MEMBER is the member structure.
106ba1bb 3558KIND is an additional string printed in the buffer."
be0dbdab
GM
3559 (let* ((tree (first info))
3560 (globals-p (ebrowse-globals-tree-p tree)))
3561 (unless globals-p
3562 (insert (ebrowse-cs-name (ebrowse-ts-class tree))))
3563 (insert "::" (ebrowse-ms-name (third info)))
3564 (indent-to 40)
3565 (insert kind)
3566 (indent-to 50)
3567 (insert (case (second info)
0adf5618
SM
3568 (ebrowse-ts-member-functions "member function")
3569 (ebrowse-ts-member-variables "member variable")
3570 (ebrowse-ts-static-functions "static function")
3571 (ebrowse-ts-static-variables "static variable")
3572 (ebrowse-ts-friends (if globals-p "define" "friend"))
3573 (ebrowse-ts-types "type")
be0dbdab
GM
3574 (t "unknown"))
3575 "\n")))
3576
3577(defvar ebrowse-last-completion nil
3578 "Text inserted by the last completion operation.")
3579
3580
3581(defvar ebrowse-last-completion-start nil
3582 "String which was the basis for the last completion operation.")
3583
3584
3585(defvar ebrowse-last-completion-location nil
3586 "Buffer position at which the last completion operation was initiated.")
3587
3588
3589(defvar ebrowse-last-completion-obarray nil
3590 "Member used in last completion operation.")
3591
3592
3593(make-variable-buffer-local 'ebrowse-last-completion-obarray)
3594(make-variable-buffer-local 'ebrowse-last-completion-location)
3595(make-variable-buffer-local 'ebrowse-last-completion)
3596(make-variable-buffer-local 'ebrowse-last-completion-start)
3597
3598
3599\f
3600(defun ebrowse-some-member-table ()
32fda8c9 3601 "Return a hash table containing all members of a tree.
be0dbdab
GM
3602If there's only one tree loaded, use that. Otherwise let the
3603use choose a tree."
3604 (let* ((buffers (ebrowse-known-class-trees-buffer-list))
3605 (buffer (cond ((and (first buffers) (not (second buffers)))
3606 (first buffers))
3607 (t (or (ebrowse-electric-choose-tree)
3608 (error "No tree buffer")))))
3609 (header (ebrowse-value-in-buffer 'ebrowse--header buffer)))
3610 (ebrowse-member-table header)))
3611
3612
be0dbdab
GM
3613(defun ebrowse-cyclic-successor-in-string-list (string list)
3614 "Return the item following STRING in LIST.
3615If STRING is the last element, return the first element as successor."
3616 (or (nth (1+ (ebrowse-position string list 'string=)) list)
3617 (first list)))
3618
3619\f
3620;;; Symbol completion
3621
3622;;;###autoload
3623(defun* ebrowse-tags-complete-symbol (prefix)
3624 "Perform completion on the C++ symbol preceding point.
106ba1bb 3625A second call of this function without changing point inserts the next match.
be0dbdab
GM
3626A call with prefix PREFIX reads the symbol to insert from the minibuffer with
3627completion."
3628 (interactive "P")
3629 (let* ((end (point))
3630 (begin (save-excursion (skip-chars-backward "a-zA-Z_0-9") (point)))
3631 (pattern (buffer-substring begin end))
3632 list completion)
3633 (cond
3634 ;; With prefix, read name from minibuffer with completion.
3635 (prefix
3636 (let* ((members (ebrowse-some-member-table))
be0dbdab 3637 (completion (completing-read "Insert member: "
47932cf8 3638 members nil t pattern)))
be0dbdab
GM
3639 (when completion
3640 (setf ebrowse-last-completion-location nil)
3641 (delete-region begin end)
3642 (insert completion))))
3643 ;; If this function is called at the same point the last
3644 ;; expansion ended, insert the next expansion.
3645 ((eq (point) ebrowse-last-completion-location)
3646 (setf list (all-completions ebrowse-last-completion-start
3647 ebrowse-last-completion-obarray)
3648 completion (ebrowse-cyclic-successor-in-string-list
3649 ebrowse-last-completion list))
3650 (cond ((null completion)
3651 (error "No completion"))
3652 ((string= completion pattern)
3653 (error "No further completion"))
3654 (t
3655 (delete-region begin end)
3656 (insert completion)
3657 (setf ebrowse-last-completion completion
3658 ebrowse-last-completion-location (point)))))
3659 ;; First time the function is called at some position in the
3660 ;; buffer: Start new completion.
3661 (t
3662 (let* ((members (ebrowse-some-member-table))
3663 (completion (first (all-completions pattern members nil))))
3664 (cond ((eq completion t))
3665 ((null completion)
3666 (error "Can't find completion for `%s'" pattern))
3667 (t
3668 (delete-region begin end)
3669 (insert completion)
106ba1bb 3670
be0dbdab
GM
3671 (setf ebrowse-last-completion-location (point)
3672 ebrowse-last-completion-start pattern
3673 ebrowse-last-completion completion
3674 ebrowse-last-completion-obarray members))))))))
3675
3676\f
3677;;; Tags query replace & search
3678
3679(defvar ebrowse-tags-loop-form ()
3680 "Form for `ebrowse-loop-continue'.
3681Evaluated for each file in the tree. If it returns nil, proceed
3682with the next file.")
3683
3684(defvar ebrowse-tags-next-file-list ()
3685 "A list of files to be processed.")
3686
3687
3688(defvar ebrowse-tags-next-file-path nil
3689 "The path relative to which files have to be searched.")
3690
3691
3692(defvar ebrowse-tags-loop-last-file nil
3693 "The last file visited via `ebrowse-tags-loop'.")
3694
3695
3696(defun ebrowse-tags-next-file (&optional initialize tree-buffer)
3697 "Select next file among files in current tag table.
3698Non-nil argument INITIALIZE (prefix arg, if interactive) initializes
3699to the beginning of the list of files in the tag table.
3700TREE-BUFFER specifies the class tree we operate on."
3701 (interactive "P")
3702 ;; Call with INITIALIZE non-nil initializes the files list.
3703 ;; If more than one tree buffer is loaded, let the user choose
3704 ;; on which tree (s)he wants to operate.
3705 (when initialize
3706 (let ((buffer (or tree-buffer (ebrowse-choose-from-browser-buffers))))
9a529312 3707 (with-current-buffer buffer
be0dbdab
GM
3708 (setq ebrowse-tags-next-file-list
3709 (ebrowse-files-list (ebrowse-marked-classes-p))
3710 ebrowse-tags-loop-last-file
3711 nil
3712 ebrowse-tags-next-file-path
3713 (file-name-directory ebrowse--tags-file-name)))))
3714 ;; End of the loop if the stack of files is empty.
3715 (unless ebrowse-tags-next-file-list
3716 (error "All files processed"))
3717 ;; ebrowse-tags-loop-last-file is the last file that was visited due
3718 ;; to a call to BROWSE-LOOP (see below). If that file is still
3719 ;; in memory, and it wasn't modified, throw its buffer away to
3720 ;; prevent cluttering up the buffer list.
3721 (when ebrowse-tags-loop-last-file
3722 (let ((buffer (get-file-buffer ebrowse-tags-loop-last-file)))
3723 (when (and buffer
3724 (not (buffer-modified-p buffer)))
3725 (kill-buffer buffer))))
3726 ;; Remember this buffer file name for later deletion, if it
3727 ;; wasn't visited by other means.
3728 (let ((file (expand-file-name (car ebrowse-tags-next-file-list)
3729 ebrowse-tags-next-file-path)))
3730 (setq ebrowse-tags-loop-last-file (if (get-file-buffer file) nil file))
3731 ;; Find the file and pop the file list. Pop has to be done
3732 ;; before the file is loaded because FIND-FILE might encounter
3733 ;; an error, and we want to be able to proceed with the next
3734 ;; file in this case.
3735 (pop ebrowse-tags-next-file-list)
3736 (find-file file)))
3737
3738
3739;;;###autoload
3740(defun ebrowse-tags-loop-continue (&optional first-time tree-buffer)
3741 "Repeat last operation on files in tree.
3742FIRST-TIME non-nil means this is not a repetition, but the first time.
3743TREE-BUFFER if indirectly specifies which files to loop over."
3744 (interactive)
3745 (when first-time
3746 (ebrowse-tags-next-file first-time tree-buffer)
3747 (goto-char (point-min)))
3748 (while (not (eval ebrowse-tags-loop-form))
3749 (ebrowse-tags-next-file)
3750 (message "Scanning file `%s'..." buffer-file-name)
3751 (goto-char (point-min))))
3752
3753
8cbb7c61 3754;;;###autoload
be0dbdab
GM
3755(defun ebrowse-tags-search (regexp)
3756 "Search for REGEXP in all files in a tree.
3757If marked classes exist, process marked classes, only.
3758If regular expression is nil, repeat last search."
3759 (interactive "sTree search (regexp): ")
3760 (if (and (string= regexp "")
3761 (eq (car ebrowse-tags-loop-form) 're-search-forward))
3762 (ebrowse-tags-loop-continue)
3763 (setq ebrowse-tags-loop-form (list 're-search-forward regexp nil t))
3764 (ebrowse-tags-loop-continue 'first-time)))
3765
3766
3767;;;###autoload
3768(defun ebrowse-tags-query-replace (from to)
3769 "Query replace FROM with TO in all files of a class tree.
3770With prefix arg, process files of marked classes only."
106ba1bb 3771 (interactive
be0dbdab
GM
3772 "sTree query replace (regexp): \nsTree query replace %s by: ")
3773 (setq ebrowse-tags-loop-form
3774 (list 'and (list 'save-excursion
3775 (list 're-search-forward from nil t))
8c8f9bc1 3776 (list 'not (list 'perform-replace from to t t nil))))
be0dbdab
GM
3777 (ebrowse-tags-loop-continue 'first-time))
3778
3779
23b809c2 3780;;;###autoload
be0dbdab
GM
3781(defun ebrowse-tags-search-member-use (&optional fix-name)
3782 "Search for call sites of a member.
3783If FIX-NAME is specified, search uses of that member.
3784Otherwise, read a member name from the minibuffer.
3785Searches in all files mentioned in a class tree for something that
3786looks like a function call to the member."
3787 (interactive)
3788 ;; Choose the tree to use if there is more than one.
3789 (multiple-value-bind (tree header tree-buffer)
3c2fbb99 3790 (values-list (ebrowse-choose-tree))
be0dbdab
GM
3791 (unless tree
3792 (error "No class tree"))
3793 ;; Get the member name NAME (class-name is ignored).
3794 (let ((name fix-name) class-name regexp)
3795 (unless name
3796 (multiple-value-setq (class-name name)
3c2fbb99 3797 (values-list (ebrowse-tags-read-name header "Find calls of: "))))
be0dbdab
GM
3798 ;; Set tags loop form to search for member and begin loop.
3799 (setq regexp (concat "\\<" name "[ \t]*(")
3800 ebrowse-tags-loop-form (list 're-search-forward regexp nil t))
3801 (ebrowse-tags-loop-continue 'first-time tree-buffer))))
3802
3803
3804\f
3805;;; Tags position management
3806
3807;;; Structures of this kind are the elements of the position stack.
3808
3809(defstruct (ebrowse-position (:type vector) :named)
3810 file-name ; in which file
3811 point ; point in file
3812 target ; t if target of a jump
3813 info) ; (CLASS FUNC MEMBER) jumped to
3814
3815
3816(defvar ebrowse-position-stack ()
3817 "Stack of `ebrowse-position' structured.")
3818
3819
3820(defvar ebrowse-position-index 0
3821 "Current position in position stack.")
3822
3823
3824(defun ebrowse-position-name (position)
3825 "Return an identifying string for POSITION.
3826The string is printed in the electric position list buffer."
3827 (let ((info (ebrowse-position-info position)))
3828 (concat (if (ebrowse-position-target position) "at " "to ")
3829 (ebrowse-cs-name (ebrowse-ts-class (first info)))
3830 "::" (ebrowse-ms-name (third info)))))
3831
3832
3833(defun ebrowse-view/find-position (position &optional view)
3834 "Position point on POSITION.
3835If VIEW is non-nil, view the position, otherwise find it."
3836 (cond ((not view)
3837 (find-file (ebrowse-position-file-name position))
3838 (goto-char (ebrowse-position-point position)))
3839 (t
3840 (unwind-protect
3841 (progn
106ba1bb 3842 (push (function
be0dbdab
GM
3843 (lambda ()
3844 (goto-char (ebrowse-position-point position))))
3845 view-mode-hook)
3846 (view-file (ebrowse-position-file-name position)))
3847 (pop view-mode-hook)))))
3848
3849
3850(defun ebrowse-push-position (marker info &optional target)
3851 "Push current position on position stack.
3852MARKER is the marker to remember as position.
3853INFO is a list (CLASS FUNC MEMBER) specifying what we jumped to.
3854TARGET non-nil means we performed a jump.
3855Positions in buffers that have no file names are not saved."
3856 (when (buffer-file-name (marker-buffer marker))
3857 (let ((too-much (- (length ebrowse-position-stack)
3858 ebrowse-max-positions)))
3859 ;; Do not let the stack grow to infinity.
3860 (when (plusp too-much)
3861 (setq ebrowse-position-stack
3862 (butlast ebrowse-position-stack too-much)))
3863 ;; Push the position.
3864 (push (make-ebrowse-position
3865 :file-name (buffer-file-name (marker-buffer marker))
3866 :point (marker-position marker)
3867 :target target
106ba1bb 3868 :info info)
be0dbdab
GM
3869 ebrowse-position-stack))))
3870
3871
3872(defun ebrowse-move-in-position-stack (increment)
3873 "Move by INCREMENT in the position stack."
3874 (let ((length (length ebrowse-position-stack)))
3875 (when (zerop length)
3876 (error "No positions remembered"))
3877 (setq ebrowse-position-index
3878 (mod (+ increment ebrowse-position-index) length))
3879 (message "Position %d of %d " ebrowse-position-index length)
3880 (ebrowse-view/find-position (nth ebrowse-position-index
3881 ebrowse-position-stack))))
3882
3883
23b809c2 3884;;;###autoload
be0dbdab
GM
3885(defun ebrowse-back-in-position-stack (arg)
3886 "Move backward in the position stack.
3887Prefix arg ARG says how much."
3888 (interactive "p")
3889 (ebrowse-move-in-position-stack (max 1 arg)))
3890
3891
23b809c2 3892;;;###autoload
be0dbdab
GM
3893(defun ebrowse-forward-in-position-stack (arg)
3894 "Move forward in the position stack.
3895Prefix arg ARG says how much."
3896 (interactive "p")
3897 (ebrowse-move-in-position-stack (min -1 (- arg))))
3898
3899
3900\f
3901;;; Electric position list
3902
3903(defvar ebrowse-electric-position-mode-map ()
3904 "Keymap used in electric position stack window.")
3905
3906
3907(defvar ebrowse-electric-position-mode-hook nil
1c1d2dc8 3908 "If non-nil, its value is called by `ebrowse-electric-position-mode'.")
be0dbdab
GM
3909
3910
3911(unless ebrowse-electric-position-mode-map
3912 (let ((map (make-keymap))
3913 (submap (make-keymap)))
3914 (setq ebrowse-electric-position-mode-map map)
3915 (fillarray (car (cdr map)) 'ebrowse-electric-position-undefined)
3916 (fillarray (car (cdr submap)) 'ebrowse-electric-position-undefined)
3917 (define-key map "\e" submap)
f35ca2fe 3918 (define-key map "\C-z" 'suspend-frame)
be0dbdab
GM
3919 (define-key map "\C-h" 'Helper-help)
3920 (define-key map "?" 'Helper-describe-bindings)
3921 (define-key map "\C-c" nil)
3922 (define-key map "\C-c\C-c" 'ebrowse-electric-position-quit)
3923 (define-key map "q" 'ebrowse-electric-position-quit)
3924 (define-key map " " 'ebrowse-electric-select-position)
3925 (define-key map "\C-l" 'recenter)
3926 (define-key map "\C-u" 'universal-argument)
3927 (define-key map "\C-p" 'previous-line)
3928 (define-key map "\C-n" 'next-line)
3929 (define-key map "p" 'previous-line)
3930 (define-key map "n" 'next-line)
3931 (define-key map "v" 'ebrowse-electric-view-position)
ce3cefcc
CY
3932 (define-key map "\C-v" 'scroll-up-command)
3933 (define-key map "\ev" 'scroll-down-command)
be0dbdab
GM
3934 (define-key map "\e\C-v" 'scroll-other-window)
3935 (define-key map "\e>" 'end-of-buffer)
3936 (define-key map "\e<" 'beginning-of-buffer)
3937 (define-key map "\e>" 'end-of-buffer)))
3938
3939(put 'ebrowse-electric-position-mode 'mode-class 'special)
3940(put 'ebrowse-electric-position-undefined 'suppress-keymap t)
3941
3942
175069ef
SM
3943(define-derived-mode ebrowse-electric-position-mode
3944 fundamental-mode "Electric Position Menu"
be0dbdab
GM
3945 "Mode for electric position buffers.
3946Runs the hook `ebrowse-electric-position-mode-hook'."
175069ef 3947 (setq mode-line-buffer-identification "Electric Position Menu")
be0dbdab
GM
3948 (when (memq 'mode-name mode-line-format)
3949 (setq mode-line-format (copy-sequence mode-line-format))
3950 (setcar (memq 'mode-name mode-line-format) "Positions"))
175069ef
SM
3951 (set (make-local-variable 'Helper-return-blurb) "return to buffer editing")
3952 (setq truncate-lines t
3953 buffer-read-only t))
be0dbdab
GM
3954
3955
3956(defun ebrowse-draw-position-buffer ()
3957 "Display positions in buffer *Positions*."
3958 (set-buffer (get-buffer-create "*Positions*"))
3959 (setq buffer-read-only nil)
3960 (erase-buffer)
3961 (insert "File Point Description\n"
3962 "---- ----- -----------\n")
3963 (dolist (position ebrowse-position-stack)
3964 (insert (file-name-nondirectory (ebrowse-position-file-name position)))
3965 (indent-to 15)
3966 (insert (int-to-string (ebrowse-position-point position)))
3967 (indent-to 22)
3968 (insert (ebrowse-position-name position) "\n"))
3969 (setq buffer-read-only t))
3970
3971
23b809c2 3972;;;###autoload
be0dbdab
GM
3973(defun ebrowse-electric-position-menu ()
3974 "List positions in the position stack in an electric buffer."
3975 (interactive)
3976 (unless ebrowse-position-stack
3977 (error "No positions remembered"))
3978 (let (select buffer window)
3979 (save-window-excursion
3980 (save-window-excursion (ebrowse-draw-position-buffer))
3981 (setq window (Electric-pop-up-window "*Positions*")
3982 buffer (window-buffer window))
3983 (shrink-window-if-larger-than-buffer window)
3984 (unwind-protect
3985 (progn
3986 (set-buffer buffer)
3987 (ebrowse-electric-position-mode)
3988 (setq select
3989 (catch 'ebrowse-electric-select-position
3990 (message "<<< Press Space to bury the list >>>")
3991 (let ((first (progn (goto-char (point-min))
3992 (forward-line 2)
3993 (point)))
3994 (last (progn (goto-char (point-max))
3995 (forward-line -1)
3996 (point)))
3997 (goal-column 0))
3998 (goto-char first)
3999 (Electric-command-loop 'ebrowse-electric-select-position
4000 nil t
4001 'ebrowse-electric-position-looper
4002 (cons first last))))))
4003 (set-buffer buffer)
4004 (bury-buffer buffer)
4005 (message nil)))
4006 (when select
4007 (set-buffer buffer)
4008 (ebrowse-electric-find-position select))
4009 (kill-buffer buffer)))
4010
4011
4012(defun ebrowse-electric-position-looper (state condition)
4013 "Prevent moving point on invalid lines.
4014Called from `Electric-command-loop'. See there for the meaning
4015of STATE and CONDITION."
4016 (cond ((and condition
4017 (not (memq (car condition) '(buffer-read-only
4018 end-of-buffer
4019 beginning-of-buffer))))
4020 (signal (car condition) (cdr condition)))
4021 ((< (point) (car state))
4022 (goto-char (point-min))
4023 (forward-line 2))
4024 ((> (point) (cdr state))
4025 (goto-char (point-max))
4026 (forward-line -1)
4027 (if (pos-visible-in-window-p (point-max))
4028 (recenter -1)))))
4029
4030
4031(defun ebrowse-electric-position-undefined ()
4032 "Function called for undefined keys."
4033 (interactive)
4034 (message "Type C-h for help, ? for commands, q to quit, Space to execute")
4035 (sit-for 4))
4036
4037
4038(defun ebrowse-electric-position-quit ()
4039 "Leave the electric position list."
4040 (interactive)
4041 (throw 'ebrowse-electric-select-position nil))
4042
4043
4044(defun ebrowse-electric-select-position ()
4045 "Select a position from the list."
4046 (interactive)
4047 (throw 'ebrowse-electric-select-position (point)))
4048
4049
4050(defun ebrowse-electric-find-position (point &optional view)
4051 "View/find what is described by the line at POINT.
4052If VIEW is non-nil, view else find source files."
4053 (let ((index (- (count-lines (point-min) point) 2)))
4054 (ebrowse-view/find-position (nth index
4055 ebrowse-position-stack) view)))
4056
4057
4058(defun ebrowse-electric-view-position ()
4059 "View the position described by the line point is in."
4060 (interactive)
4061 (ebrowse-electric-find-position (point) t))
4062
4063
4064\f
4065;;; Saving trees to disk
4066
4067(defun ebrowse-write-file-hook-fn ()
4068 "Write current buffer as a class tree.
4069Installed on `local-write-file-hooks'."
4070 (ebrowse-save-tree)
4071 t)
4072
4073
23b809c2 4074;;;###autoload
be0dbdab
GM
4075(defun ebrowse-save-tree ()
4076 "Save current tree in same file it was loaded from."
4077 (interactive)
4078 (ebrowse-save-tree-as (or buffer-file-name ebrowse--tags-file-name)))
4079
4080
4081;;;###autoload
4082(defun ebrowse-save-tree-as (&optional file-name)
4083 "Write the current tree data structure to a file.
4084Read the file name from the minibuffer if interactive.
4085Otherwise, FILE-NAME specifies the file to save the tree in."
4086 (interactive "FSave tree as: ")
4087 (let ((temp-buffer (get-buffer-create "*Tree Output"))
4088 (old-standard-output standard-output)
4089 (header (copy-ebrowse-hs ebrowse--header))
4090 (tree ebrowse--tree))
4091 (unwind-protect
9a529312 4092 (with-current-buffer (setq standard-output temp-buffer)
be0dbdab
GM
4093 (erase-buffer)
4094 (setf (ebrowse-hs-member-table header) nil)
4095 (insert (prin1-to-string header) " ")
2d97d6dc 4096 (mapc 'ebrowse-save-class tree)
be0dbdab
GM
4097 (write-file file-name)
4098 (message "Tree written to file `%s'" file-name))
4099 (kill-buffer temp-buffer)
4100 (set-buffer-modified-p nil)
4101 (ebrowse-update-tree-buffer-mode-line)
4102 (setq standard-output old-standard-output))))
4103
4104
4105(defun ebrowse-save-class (class)
4106 "Write single class CLASS to current buffer."
4107 (message "%s..." (ebrowse-cs-name (ebrowse-ts-class class)))
4108 (insert "[ebrowse-ts ")
4109 (prin1 (ebrowse-ts-class class)) ;class name
4110 (insert "(") ;list of subclasses
2d97d6dc 4111 (mapc 'ebrowse-save-class (ebrowse-ts-subclasses class))
be0dbdab
GM
4112 (insert ")")
4113 (dolist (func ebrowse-member-list-accessors)
4114 (prin1 (funcall func class))
4115 (insert "\n"))
4116 (insert "()") ;base-classes slot
4117 (prin1 (ebrowse-ts-mark class))
4118 (insert "]\n"))
4119
4120
4121\f
4122;;; Statistics
4123
23b809c2 4124;;;###autoload
be0dbdab
GM
4125(defun ebrowse-statistics ()
4126 "Display statistics for a class tree."
4127 (interactive)
4128 (let ((tree-file (buffer-file-name))
4129 temp-buffer-setup-hook)
4130 (with-output-to-temp-buffer "*Tree Statistics*"
4131 (multiple-value-bind (classes member-functions member-variables
4132 static-functions static-variables)
3c2fbb99 4133 (values-list (ebrowse-gather-statistics))
be0dbdab
GM
4134 (set-buffer standard-output)
4135 (erase-buffer)
4136 (insert "STATISTICS FOR TREE " (or tree-file "unknown") ":\n\n")
4137 (ebrowse-print-statistics-line "Number of classes:" classes)
4138 (ebrowse-print-statistics-line "Number of member functions:"
4139 member-functions)
4140 (ebrowse-print-statistics-line "Number of member variables:"
4141 member-variables)
4142 (ebrowse-print-statistics-line "Number of static functions:"
4143 static-functions)
4144 (ebrowse-print-statistics-line "Number of static variables:"
4145 static-variables)))))
4146
4147
4148(defun ebrowse-print-statistics-line (title value)
4149 "Print a line in the statistics buffer.
1c1d2dc8 4150TITLE is the title of the line, VALUE is a number to be printed
be0dbdab
GM
4151after that."
4152 (insert title)
4153 (indent-to 40)
4154 (insert (format "%d\n" value)))
4155
4156
4157(defun ebrowse-gather-statistics ()
4158 "Return statistics for a class tree.
4159The result is a list (NUMBER-OF-CLASSES NUMBER-OF-MEMBER-FUNCTIONS
4160NUMBER-OF-INSTANCE-VARIABLES NUMBER-OF-STATIC-FUNCTIONS
4161NUMBER-OF-STATIC-VARIABLES:"
4162 (let ((classes 0) (member-functions 0) (member-variables 0)
4163 (static-functions 0) (static-variables 0))
4164 (ebrowse-for-all-trees (tree ebrowse--tree-obarray)
4165 (incf classes)
4166 (incf member-functions (length (ebrowse-ts-member-functions tree)))
4167 (incf member-variables (length (ebrowse-ts-member-variables tree)))
4168 (incf static-functions (length (ebrowse-ts-static-functions tree)))
4169 (incf static-variables (length (ebrowse-ts-static-variables tree))))
4170 (list classes member-functions member-variables
4171 static-functions static-variables)))
4172
4173
4174\f
4175;;; Global key bindings
4176
9a529312
SM
4177;; The following can be used to bind key sequences starting with
4178;; prefix `\C-c\C-m' to browse commands.
be0dbdab
GM
4179
4180(defvar ebrowse-global-map nil
4181 "*Keymap for Ebrowse commands.")
4182
4183
3c47e17c 4184(defvar ebrowse-global-prefix-key "\C-c\C-m"
be0dbdab
GM
4185 "Prefix key for Ebrowse commands.")
4186
4187
4188(defvar ebrowse-global-submap-4 nil
4189 "Keymap used for `ebrowse-global-prefix' followed by `4'.")
4190
4191
4192(defvar ebrowse-global-submap-5 nil
4193 "Keymap used for `ebrowse-global-prefix' followed by `5'.")
4194
4195
4196(unless ebrowse-global-map
4197 (setq ebrowse-global-map (make-sparse-keymap))
4198 (setq ebrowse-global-submap-4 (make-sparse-keymap))
4199 (setq ebrowse-global-submap-5 (make-sparse-keymap))
4200 (define-key ebrowse-global-map "a" 'ebrowse-tags-apropos)
4201 (define-key ebrowse-global-map "b" 'ebrowse-pop-to-browser-buffer)
4202 (define-key ebrowse-global-map "-" 'ebrowse-back-in-position-stack)
4203 (define-key ebrowse-global-map "+" 'ebrowse-forward-in-position-stack)
4204 (define-key ebrowse-global-map "l" 'ebrowse-tags-list-members-in-file)
4205 (define-key ebrowse-global-map "m" 'ebrowse-tags-display-member-buffer)
4206 (define-key ebrowse-global-map "n" 'ebrowse-tags-next-file)
4207 (define-key ebrowse-global-map "p" 'ebrowse-electric-position-menu)
4208 (define-key ebrowse-global-map "s" 'ebrowse-tags-search)
4209 (define-key ebrowse-global-map "u" 'ebrowse-tags-search-member-use)
4210 (define-key ebrowse-global-map "v" 'ebrowse-tags-view-definition)
4211 (define-key ebrowse-global-map "V" 'ebrowse-tags-view-declaration)
4212 (define-key ebrowse-global-map "%" 'ebrowse-tags-query-replace)
4213 (define-key ebrowse-global-map "." 'ebrowse-tags-find-definition)
4214 (define-key ebrowse-global-map "f" 'ebrowse-tags-find-definition)
4215 (define-key ebrowse-global-map "F" 'ebrowse-tags-find-declaration)
4216 (define-key ebrowse-global-map "," 'ebrowse-tags-loop-continue)
4217 (define-key ebrowse-global-map " " 'ebrowse-electric-buffer-list)
4218 (define-key ebrowse-global-map "\t" 'ebrowse-tags-complete-symbol)
4219 (define-key ebrowse-global-map "4" ebrowse-global-submap-4)
4220 (define-key ebrowse-global-submap-4 "." 'ebrowse-tags-find-definition-other-window)
4221 (define-key ebrowse-global-submap-4 "f" 'ebrowse-tags-find-definition-other-window)
4222 (define-key ebrowse-global-submap-4 "v" 'ebrowse-tags-find-declaration-other-window)
4223 (define-key ebrowse-global-submap-4 "F" 'ebrowse-tags-view-definition-other-window)
4224 (define-key ebrowse-global-submap-4 "V" 'ebrowse-tags-view-declaration-other-window)
4225 (define-key ebrowse-global-map "5" ebrowse-global-submap-5)
4226 (define-key ebrowse-global-submap-5 "." 'ebrowse-tags-find-definition-other-frame)
4227 (define-key ebrowse-global-submap-5 "f" 'ebrowse-tags-find-definition-other-frame)
4228 (define-key ebrowse-global-submap-5 "v" 'ebrowse-tags-find-declaration-other-frame)
4229 (define-key ebrowse-global-submap-5 "F" 'ebrowse-tags-view-definition-other-frame)
4230 (define-key ebrowse-global-submap-5 "V" 'ebrowse-tags-view-declaration-other-frame)
4231 (define-key global-map ebrowse-global-prefix-key ebrowse-global-map))
4232
4233
4234\f
4235;;; Electric C++ browser buffer menu
4236
9a529312
SM
4237;; Electric buffer menu customization to display only some buffers
4238;; (in this case Tree buffers). There is only one problem with this:
4239;; If the very first character typed in the buffer menu is a space,
4240;; this will select the buffer from which the buffer menu was
4241;; invoked. But this buffer is not displayed in the buffer list if
4242;; it isn't a tree buffer. I therefore let the buffer menu command
4243;; loop read the command `p' via `unread-command-char'. This command
4244;; has no effect since we are on the first line of the buffer.
be0dbdab
GM
4245
4246(defvar electric-buffer-menu-mode-hook nil)
4247
4248
4249(defun ebrowse-hack-electric-buffer-menu ()
4250 "Hack the electric buffer menu to display browser buffers."
4251 (let (non-empty)
4252 (unwind-protect
4253 (save-excursion
4254 (setq buffer-read-only nil)
4255 (goto-char 1)
4256 (forward-line 2)
4257 (while (not (eobp))
4258 (let ((b (Buffer-menu-buffer nil)))
4259 (if (or (ebrowse-buffer-p b)
4260 (string= (buffer-name b) "*Apropos Members*"))
4261 (progn (forward-line 1)
4262 (setq non-empty t))
4263 (delete-region (point)
4264 (save-excursion (end-of-line)
4265 (min (point-max)
4266 (1+ (point)))))))))
4267 (unless non-empty
4268 (error "No tree buffers"))
4269 (setf unread-command-events (listify-key-sequence "p"))
4270 (shrink-window-if-larger-than-buffer (selected-window))
4271 (setq buffer-read-only t))))
4272
4273
4274(defun ebrowse-select-1st-to-9nth ()
4275 "Select the nth entry in the list by the keys 1..9."
4276 (interactive)
4277 (let* ((maxlin (count-lines (point-min) (point-max)))
027a4b6b 4278 (n (min maxlin (+ 2 (string-to-number (this-command-keys))))))
e6ce8c42
GM
4279 (goto-char (point-min))
4280 (forward-line (1- n))
be0dbdab
GM
4281 (throw 'electric-buffer-menu-select (point))))
4282
4283
4284(defun ebrowse-install-1-to-9-keys ()
1c1d2dc8 4285 "Define keys 1..9 to select the 1st to 9nth entry in the list."
be0dbdab
GM
4286 (dotimes (i 9)
4287 (define-key (current-local-map) (char-to-string (+ i ?1))
4288 'ebrowse-select-1st-to-9nth)))
4289
4290
4291(defun ebrowse-electric-buffer-list ()
4292 "Display an electric list of Ebrowse buffers."
4293 (interactive)
4294 (unwind-protect
4295 (progn
4296 (add-hook 'electric-buffer-menu-mode-hook
4297 'ebrowse-hack-electric-buffer-menu)
4298 (add-hook 'electric-buffer-menu-mode-hook
4299 'ebrowse-install-1-to-9-keys)
4300 (call-interactively 'electric-buffer-list))
4301 (remove-hook 'electric-buffer-menu-mode-hook
4302 'ebrowse-hack-electric-buffer-menu)))
4303
4304\f
4305;;; Mouse support
4306
4307(defun ebrowse-mouse-find-member (event)
4308 "Find the member clicked on in another frame.
4309EVENT is a mouse button event."
4310 (interactive "e")
4311 (mouse-set-point event)
4312 (let (start name)
4313 (save-excursion
4314 (skip-chars-backward "a-zA-Z0-9_")
4315 (setq start (point))
4316 (skip-chars-forward "a-zA-Z0-9_")
4317 (setq name (buffer-substring start (point))))
4318 (ebrowse-tags-view/find-member-decl/defn
4319 5 :view nil :definition t :member-name name)))
4320
4321
4322(defun ebrowse-popup-menu (menu event)
4323 "Pop up MENU and perform an action if something was selected.
4324EVENT is the mouse event."
4325 (save-selected-window
4326 (select-window (posn-window (event-start event)))
4327 (let ((selection (x-popup-menu event menu)) binding)
4328 (while selection
4329 (setq binding (lookup-key (or binding menu) (vector (car selection)))
4330 selection (cdr selection)))
4331 (when binding
4332 (call-interactively binding)))))
4333
4334
4335(easy-menu-define
106ba1bb 4336 ebrowse-tree-buffer-class-object-menu ebrowse-tree-mode-map
be0dbdab
GM
4337 "Object menu for classes in the tree buffer"
4338 '("Class"
4339 ["Functions" ebrowse-tree-command:show-member-functions
4340 :help "Display a list of member functions"
4341 :active t]
4342 ["Variables" ebrowse-tree-command:show-member-variables
4343 :help "Display a list of member variables"
4344 :active t]
4345 ["Static Functions" ebrowse-tree-command:show-static-member-functions
4346 :help "Display a list of static member functions"
4347 :active t]
4348 ["Static Variables" ebrowse-tree-command:show-static-member-variables
4349 :help "Display a list of static member variables"
4350 :active t]
4351 ["Friends/ Defines" ebrowse-tree-command:show-friends
4352 :help "Display a list of friends of a class"
4353 :active t]
4354 ["Types" ebrowse-tree-command:show-types
4355 :help "Display a list of types defined in a class"
4356 :active t]
4357 "-----------------"
4358 ["View" ebrowse-view-class-declaration
4359 :help "View class declaration"
4360 :active (eq (get-text-property (point) 'ebrowse-what) 'class-name)]
4361 ["Find" ebrowse-find-class-declaration
4362 :help "Find class declaration in file"
4363 :active (eq (get-text-property (point) 'ebrowse-what) 'class-name)]
4364 "-----------------"
4365 ["Mark" ebrowse-toggle-mark-at-point
4366 :help "Mark class point is on"
4367 :active (eq (get-text-property (point) 'ebrowse-what) 'class-name)]
4368 "-----------------"
4369 ["Collapse" ebrowse-collapse-branch
4370 :help "Collapse subtree under class point is on"
4371 :active (eq (get-text-property (point) 'ebrowse-what) 'class-name)]
4372 ["Expand" ebrowse-expand-branch
4373 :help "Expand subtree under class point is on"
4374 :active (eq (get-text-property (point) 'ebrowse-what) 'class-name)]))
4375
4376
4377(easy-menu-define
106ba1bb 4378 ebrowse-tree-buffer-object-menu ebrowse-tree-mode-map
be0dbdab
GM
4379 "Object menu for tree buffers"
4380 '("Ebrowse"
4381 ["Filename Display" ebrowse-toggle-file-name-display
4382 :help "Toggle display of source files names"
4383 :style toggle
4384 :selected ebrowse--show-file-names-flag
4385 :active t]
4386 ["Tree Indentation" ebrowse-set-tree-indentation
4387 :help "Set the tree's indentation"
4388 :active t]
4389 ["Unmark All Classes" ebrowse-mark-all-classes
4390 :help "Unmark all classes in the class tree"
4391 :active t]
4392 ["Expand All" ebrowse-expand-all
4393 :help "Expand all subtrees in the class tree"
4394 :active t]
4395 ["Statistics" ebrowse-statistics
4396 :help "Show a buffer with class hierarchy statistics"
4397 :active t]
4398 ["Find Class" ebrowse-read-class-name-and-go
4399 :help "Find a class in the tree"
4400 :active t]
4401 ["Member Buffer" ebrowse-pop/switch-to-member-buffer-for-same-tree
4402 :help "Show a member buffer for this class tree"
4403 :active t]))
4404
4405
4406(defun ebrowse-mouse-3-in-tree-buffer (event)
4407 "Perform mouse actions in tree buffers.
4408EVENT is the mouse event."
4409 (interactive "e")
4410 (mouse-set-point event)
4411 (let* ((where (posn-point (event-start event)))
4412 (property (get-text-property where 'ebrowse-what)))
4413 (case (event-click-count event)
4414 (1
4415 (case property
4416 (class-name
4417 (ebrowse-popup-menu ebrowse-tree-buffer-class-object-menu event))
4418 (t
4419 (ebrowse-popup-menu ebrowse-tree-buffer-object-menu event)))))))
4420
4421
4422(defun ebrowse-mouse-2-in-tree-buffer (event)
4423 "Perform mouse actions in tree buffers.
4424EVENT is the mouse event."
4425 (interactive "e")
4426 (mouse-set-point event)
4427 (let* ((where (posn-point (event-start event)))
4428 (property (get-text-property where 'ebrowse-what)))
4429 (case (event-click-count event)
4430 (1 (case property
4431 (class-name
4432 (ebrowse-tree-command:show-member-functions)))))))
4433
4434
4435(defun ebrowse-mouse-1-in-tree-buffer (event)
4436 "Perform mouse actions in tree buffers.
4437EVENT is the mouse event."
4438 (interactive "e")
4439 (mouse-set-point event)
4440 (let* ((where (posn-point (event-start event)))
4441 (property (get-text-property where 'ebrowse-what)))
4442 (case (event-click-count event)
4443 (2 (case property
4444 (class-name
4445 (let ((collapsed (save-excursion (skip-chars-forward "^\r\n")
4446 (looking-at "\r"))))
4447 (ebrowse-collapse-fn (not collapsed))))
4448 (mark
4449 (ebrowse-toggle-mark-at-point 1)))))))
4450
4451
4452\f
be0dbdab
GM
4453(provide 'ebrowse)
4454
fa043571
SM
4455;; Local variables:
4456;; eval:(put 'ebrowse-output 'lisp-indent-hook 0)
4457;; eval:(put 'ebrowse-ignoring-completion-case 'lisp-indent-hook 0)
4458;; eval:(put 'ebrowse-save-selective 'lisp-indent-hook 0)
4459;; eval:(put 'ebrowse-for-all-trees 'lisp-indent-hook 1)
4460;; End:
be0dbdab 4461
55535639 4462;;; ebrowse.el ends here