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