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