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