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