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