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