From 22235cab818d9ff777e25d9b8f64720649d33496 Mon Sep 17 00:00:00 2001 From: berndl Date: Sat, 28 Feb 2004 16:14:45 +0000 Subject: [PATCH] Smarter mechanism to highlight the current tag in the Methods-buffer --- NEWS | 27 +++ ecb-file-browser.el | 4 +- ecb-layout.el | 38 ++-- ecb-method-browser.el | 401 +++++++++++++++++++++++++++--------------- ecb-speedbar.el | 52 +++--- ecb-upgrade.el | 3 +- ecb.el | 16 +- ecb.texi | 16 +- tree-buffer.el | 67 +++---- 9 files changed, 401 insertions(+), 223 deletions(-) diff --git a/NEWS b/NEWS index fb6d2ba..ac09888 100644 --- a/NEWS +++ b/NEWS @@ -20,6 +20,28 @@ class is filtered out then no filter can be applied to its members like methods or attributes. + These tag-filters can also applied to sources which are not supported by + the semantic-parser but "only" by imenu or etags. But because for these + sources not all information are avaiable the protection- and tag-class + filter can not used with such "non-semantic"-sources. + +** Much smarter mechanism to highlight the current tag in the methods-buffer. + Previous versions of ECB have always expanded the whole tree in the + Methods-buffer if the current tag in the source-buffer was not visible in + the current tree - e.g. because the variables-bucket was collapsed or the + containing type of a tag (e.g. the class of a method) was collapsed. So in + most cases much more was expanded as needed to make the current tag + visible. + + The mechanism of ECB 2.22 only expands the needed parts of the tree-buffer + to make the related node visible: First we try to highlight the current tag + with current expansion-state of the Methods-buffer. If the node is not + visible so the tag can not be highlighted then we go upstairs the ladder of + type-tags the current tag belongs to (e.g. we expand successive the nodes + of the whole class-hierachy of the current method-tag until the related + node becomes visible). Only if this has still no success then we expand the + full tree-buffer and try to highlight the current tag. + ** The popup-menus can now be nested into 4 levels of submenus. In general there could be an infinite depth of nesting but it makes no sense - if possible at all - to define infinite nested defcustom-types. So there is a limit of @@ -48,6 +70,11 @@ *** Fixed a small bug in `ecb-toggle-compile-window-height'. This bug has influenced the behavior of `display-buffer' when called from programs for "compilation-buffers". + +*** Fixed a bug related to the speedbar-integration. + This bug complained "Can not switch buffer in dedicated window" when the + intergrated speedbar-buffer was selected and the user tries to open a file + or to jump to a tag. diff --git a/ecb-file-browser.el b/ecb-file-browser.el index 148e546..670b589 100644 --- a/ecb-file-browser.el +++ b/ecb-file-browser.el @@ -1567,7 +1567,9 @@ can last a long time - depending of machine- and disk-performance." (interactive "nLevel: ") (save-selected-window (ecb-exec-in-directories-window - (tree-buffer-expand-nodes level))) + (dolist (node (tree-node-get-children (tree-buffer-get-root))) + (tree-buffer-expand-node node level)) + (tree-buffer-update))) (ecb-current-buffer-sync 'force)) diff --git a/ecb-layout.el b/ecb-layout.el index ec4fdfa..e1602d6 100644 --- a/ecb-layout.el +++ b/ecb-layout.el @@ -2317,13 +2317,34 @@ EDIT-WIN-NR must be an integer between 1 and length of EDIT-WIN-LIST \(rsp. (equal (selected-window) ecb-compile-window))) -(defun ecb-point-in-tree-buffer () - "Return nil if point is not in any tree-buffer of ECB otherwise return the -buffer-object." +(defun ecb-point-in-ecb-tree-buffer () + "Return nil if point is not in any of the standard tree-buffers \(currently +these are the buffers with name `ecb-directories-buffer-name', +`ecb-sources-buffer-name', `ecb-methods-buffer-name' and +`ecb-history-buffer-name') of ECB otherwise return the buffer-object." (when (and (equal (selected-frame) ecb-frame) (member (buffer-name (current-buffer)) ecb-tree-buffers)) (current-buffer))) +(defun ecb-dedicated-special-buffers () + "Return a list of these special dedicated buffers which are registrated via +the macro `ecb-with-dedicated-window' \(these are normally only the standard +tree-buffers of ECB plus the integrated speedbar-buffer, but in general it can +be more if there are additional buffers registrated, e.g. by other +applications)." + (delq nil (mapcar (function (lambda (e) + (get-buffer (car e)))) + ecb-buffer-setfunction-registration))) + +(defun ecb-point-in-dedicated-special-buffer () + "Return nil if point is not in any of these special dedicated buffers which +are registrated via the macro `ecb-with-dedicated-window' \(see +`ecb-dedicated-special-buffers'). Otherwise return the buffer-object." + (when (equal (selected-frame) ecb-frame) + (if (member (current-buffer) (ecb-dedicated-special-buffers)) + (current-buffer)))) + + (defun ecb-point-in-ecb-window () "Return nil if point is not in any of the special dedicated ECB-windows otherwise return the window-object of this ECB-window. This works for every @@ -2394,10 +2415,7 @@ can use these variables." ;; We MUST not use here `ecb-point-in-edit-window' because this would ;; slow-down the performance of all Emacs-versions unless GNU Emacs 21 ;; because they have no builtin `window-list'-function. - (when (and (not (ecb-point-in-tree-buffer)) - ;; TODO: Klaus Berndl : Do we need this - ;; check elsewhere?? - (not (ecb-speedbar-buffer-selected)) + (when (and (not (ecb-point-in-dedicated-special-buffer)) (not (equal (minibuffer-window ecb-frame) (selected-window))) (not (ecb-point-in-compile-window))) @@ -2410,7 +2428,7 @@ can use these variables." (current-buffer))) (setq ecb-compile-window-was-selected-before-command nil) (setq ecb-last-compile-buffer-in-compile-window nil)) - (if (member (buffer-name) ecb-tree-buffers) + (if (ecb-point-in-dedicated-special-buffer) (setq ecb-ecb-window-was-selected-before-command (buffer-name)) (setq ecb-ecb-window-was-selected-before-command nil)))) @@ -2457,10 +2475,10 @@ some special tasks: (equal (selected-frame) ecb-frame) (= (minibuffer-depth) 0)) (cond ((and (not ecb-ecb-window-was-selected-before-command) - (ecb-point-in-tree-buffer)) + (ecb-point-in-dedicated-special-buffer)) (ecb-display-one-ecb-buffer (buffer-name))) ((and ecb-ecb-window-was-selected-before-command - (not (ecb-point-in-tree-buffer))) + (not (ecb-point-in-dedicated-special-buffer))) (ecb-redraw-layout-full nil nil nil nil)))))) ;; TODO: Klaus Berndl : need some more tests - see above ;; `ecb-minibuffer-exit-hook' diff --git a/ecb-method-browser.el b/ecb-method-browser.el index 5e4f4d9..d42e8c6 100644 --- a/ecb-method-browser.el +++ b/ecb-method-browser.el @@ -72,7 +72,8 @@ (defun ecb-method-browser-initialize () (setq ecb-selected-tag nil) (setq ecb-methods-root-node nil) - (setq ecb-methods-user-filter-alist nil)) + (setq ecb-methods-user-filter-alist nil) + (setq ecb-current-post-processed-tag-table nil)) ;;==================================================== ;; Customization @@ -1528,34 +1529,66 @@ filter belongs and the value is the applied filter to that buffer.") (ecb-methods-filter-apply nil nil nil "" (car (tree-buffer-get-data-store)) t)) -;; TODO: Klaus Berndl : -;; How to include this in the current filter-mechanism?? +(defun ecb-get-type-tag-of-current-node (curr-node) + "Returns that tag of class 'type the tag of the node CURR-NODE of the +Methods-buffer belongs to. If the tag of CURR-NODE do not belong to a type +then nil is returned." + (let ((parent (tree-node-get-parent curr-node))) + (catch 'found + (while (not (eq (tree-buffer-get-root) parent)) + (if (equal (ecb--semantic-tag-class (tree-node-get-data parent)) + 'type) + (throw 'found (tree-node-get-data parent)) + (setq parent (tree-node-get-parent parent)))) + nil))) + +(defun ecb-get-type-tag-of-tag (&optional tag table always-parent-type) + "Returns that tag of class 'type the tag TAG belongs to. If TAG does not +belong to a type then nil is returned. If TAG is already of class 'type then +the behavior depends on the optional argument ALWAYS-PARENT-TYPE: If nil then +the current tag is returned otherwise the next parent-tag of class 'type is +returned. + +If TAG is nil the tag returned by `ecb-get-real-curr-tag' is used. If TABLE is +nil then the tag-table of the current buffer is used; otherwise the tag-table +TABLE is used." + (let* ((table (or table (ecb-get-current-tag-table))) + (curr-tag (or tag (ecb-get-real-curr-tag))) + (function-parent (ecb--semantic-tag-function-parent curr-tag))) + (if (and (not always-parent-type) + (equal (ecb--semantic-tag-class curr-tag) 'type)) + curr-tag + (if function-parent + ;; we have an external member and we search the type this external + ;; member belongs to. This can either be a type-tag in the current + ;; file (which is then contained in table) or a faux-tag (created by + ;; semantic-adopt-external-members) when the parent-type of this + ;; external member is defined outside the current source - but this + ;; faux-type is contained in table too. + (catch 'found + (dolist (tag (semantic-flatten-tags-table table)) + (if (and (equal (ecb--semantic-tag-class tag) 'type) + (string= (ecb--semantic-tag-name tag) function-parent) + (delq nil (mapcar (lambda (child) + (if (ecb--semantic-equivalent-tag-p + child curr-tag) + curr-tag)) + (ecb--semantic-tag-children-compatibility tag t)))) + (throw 'found tag))) + nil) + ;; we are already inside the parent-type - if there is any, so we + ;; simply search the nearest tag of class 'type in the reversed + ;; overlay-stack + (catch 'found + (dolist (tag (cdr (reverse + (ecb--semantic-find-tag-by-overlay + (ecb--semantic-tag-start curr-tag) + (ecb--semantic-tag-buffer curr-tag))))) + (if (equal (ecb--semantic-tag-class tag) 'type) + (throw 'found tag))) + nil))))) -;; (let* ((tagstack (reverse (ecb--semantic-find-tag-by-overlay))) -;; (curr-tag (car tagstack)) -;; (next-tag (car (cdr tagstack))) -;; ) -;; (if (and (equal (ecb--semantic-tag-class curr-tag) 'variable) -;; (equal (ecb--semantic-tag-class next-tag) 'function) -;; (member curr-tag (ecb--semantic-tag-function-arguments next-tag))) -;; (setq curr-tag next-tag))) -(defun ecb-methods-filter-current-parent-type (curr-node) - (let* ((parent (tree-node-get-parent curr-node)) - (result nil)) - (setq result - (catch 'found - (while (not (eq (tree-buffer-get-root) parent)) - (if (equal (ecb--semantic-tag-class (tree-node-get-data parent)) - 'type) - (throw 'found parent) - (setq parent (tree-node-get-parent parent)))))) - (if result - (save-excursion - (set-buffer (car (tree-buffer-get-data-store))) - (ecb-rebuild-methods-buffer-with-tagcache - (list (tree-node-get-data result)))) - (message "No type-parent available.")))) (defun ecb-methods-filter-inverse () "Apply an inverse filter to the Methods-buffer. This is the same as calling @@ -1640,6 +1673,12 @@ help-echo." (defun ecb-methods-filter-apply (filtertype filter inverse filter-display source-buffer &optional remove-last) + (save-excursion + (set-buffer source-buffer) + (if (and (member filtertype '(protection tag-class)) + (not (ecb--semantic-active-p))) + (ecb-error "A %s-filter '%s' can only applied to semantic-supported sources!" + filtertype filter))) (let* ((filter-elem (assoc source-buffer ecb-methods-user-filter-alist)) (new-filter-spec (and filtertype (list filtertype filter (if inverse 'not 'identity) @@ -1661,7 +1700,16 @@ help-echo." (when (buffer-live-p source-buffer) (save-excursion (set-buffer source-buffer) - (ecb-rebuild-methods-buffer)))) + (if (ecb--semantic-active-p) + ;; For semantic-sources we do not use `ecb-rebuild-methods-buffer)' + ;; because this would always reparse the source-buffer even if not + ;; necessary. + (save-restriction + (ecb-with-original-basic-functions + (widen)) + (ecb-rebuild-methods-buffer-with-tagcache + (ecb--semantic-bovinate-toplevel t))) + (ecb-rebuild-methods-buffer))))) (defun ecb-methods-filter-modeline-prefix (buffer-name sel-dir sel-source) "Compute a mode-line prefix for the Methods-buffer so the current filter @@ -1874,7 +1922,6 @@ the current tag-tree for this source. The cache contains exactly one element for a certain source.") (setq ecb-tag-tree-cache nil) - (defun ecb-clear-tag-tree-cache (&optional source-file-name) "Clears wither the whole tag-tree-cache \(SOURCE-FILE-NAME is nil) or removes only the tag-tree for SOURCE-FILE-NAME from the cache." @@ -1883,6 +1930,23 @@ removes only the tag-tree for SOURCE-FILE-NAME from the cache." (setq ecb-tag-tree-cache (adelete 'ecb-tag-tree-cache source-file-name)))) +(defvar ecb-current-post-processed-tag-table nil + "This is the current tag-table of the current source-buffer returned by +`ecb-post-process-taglist'. Do not set this variable, only the function +`ecb-rebuild-methods-buffer-with-tagcache' is allowed to do this.") +(make-variable-buffer-local 'ecb-current-post-processed-tag-table) + +(defun ecb-get-current-tag-table () + "Return the current tag-table of the current source-buffer returned by +`ecb-post-process-taglist'. Use always this function if you just need the +current post-processed tag-table of the current buffer and you do not need or +want rebuilding the Methods-buffer." + ecb-current-post-processed-tag-table) + +(defun ecb-set-current-tag-table (table) + "Set the current tag-table of the current source-buffer to TABLE. Return +TABLE." + (setq ecb-current-post-processed-tag-table table)) (defun ecb-rebuild-methods-buffer-with-tagcache (updated-cache @@ -1991,7 +2055,9 @@ to be rescanned/reparsed and therefore the Method-buffer will be rebuild too." (if non-semantic-handling (if (equal non-semantic-handling 'parsed) (ecb-create-non-semantic-tree new-tree updated-cache)) - (ecb-add-tags new-tree (ecb-post-process-taglist updated-cache))) + (ecb-add-tags new-tree + (ecb-set-current-tag-table + (ecb-post-process-taglist updated-cache)))) (if cache (setcdr cache new-tree) (setq cache (cons norm-buffer-file-name new-tree)) @@ -2148,86 +2214,116 @@ by this command." (if new-value "on" "off") new-value))) -;; TODO: Klaus Berndl : Hier auch was möglich mit -;; (ecb-exec-in-methods-window -;; (tree-buffer-find-node-data curr-tag)) -(defun ecb-tag-sync-test (&optional force) - (when (and ecb-minor-mode - ;; we do not use here `ecb-point-in-ecb-window' because this - ;; would slow down Emacs dramatically when tag-synchronization is - ;; done via post-command-hook and not via an idle-timer. - (not (ecb-point-in-tree-buffer)) - (not (ecb-point-in-compile-window))) - (when ecb-highlight-tag-with-point - (let* ((tagstack (reverse (ecb--semantic-find-tag-by-overlay))) - (curr-tag (car tagstack)) - (next-tag (car (cdr tagstack))) - ) - (if (and (equal (ecb--semantic-tag-class curr-tag) 'variable) +(defun ecb-get-real-curr-tag () + "Get the \"real\" current tag. This will be in most cases the tag returned +by `ecb--semantic-current-tag' but there are exceptions: + +- If the current-tag is an argument-tag of a function-tag then we are not + interested in this argument-tag but in its parent-tag which is the + function-tag the argument belongs. +- If the current-tag is a label-tag then we are interested in the type-tag + which contains this label \(e.g. usefull in c++ and the labels public, + protected and private)." + (let* ((tagstack (reverse (ecb--semantic-find-tag-by-overlay))) + (curr-tag (car tagstack)) + (next-tag (car (cdr tagstack))) + ) + (if (or (and (equal (ecb--semantic-tag-class curr-tag) 'variable) (equal (ecb--semantic-tag-class next-tag) 'function) - (member curr-tag (ecb--semantic-tag-function-arguments next-tag))) - (setq curr-tag next-tag)) - (when (or force (not (equal ecb-selected-tag curr-tag))) - (setq ecb-selected-tag curr-tag) - (save-selected-window - (ecb-exec-in-methods-window - (or (tree-buffer-highlight-node-data - curr-tag nil (equal ecb-highlight-tag-with-point 'highlight)) - ;; The node representing CURR-TAG could not be highlighted be - ;; `tree-buffer-highlight-node-data' - probably it is - ;; invisible. Let's try to make visible and then highlighting - ;; again. - (when (and curr-tag ecb-auto-expand-tag-tree - (or (equal ecb-auto-expand-tag-tree 'all) - (member (ecb--semantic-tag-class curr-tag) - (ecb-normalize-expand-spec - ecb-methods-nodes-expand-spec)))) - (ecb-expand-methods-nodes-internal - 100 - (equal ecb-auto-expand-tag-tree 'all)) - (tree-buffer-highlight-node-data - curr-tag nil (equal ecb-highlight-tag-with-point 'highlight)) - ))))))))) - + (member curr-tag + (ecb--semantic-tag-function-arguments next-tag))) + (equal (ecb--semantic-tag-class curr-tag) 'label)) + (setq curr-tag next-tag)) + curr-tag)) + +(defun ecb-try-highlight-tag (highlight-tag curr-tag table) + "First we try to expand only the absolute needed parts of the tree-buffer to +highlight the tag HIGHLIGHT-TAG - this means we recursively go upstairs the +ladder of types the current tag belongs to. If this has still no success then +we return nil otherwise true \(the HIGHLIGHT-TAG is highlighted). + +If called from program: HIGHLIGHT-TAG is the tag to highlight, CURR-TAG has to +be equal to HIGHLIGHT-TAG and TABLE must be the current tag-table of the +current buffer." + (let ((type-tag (and curr-tag + (ecb-get-type-tag-of-tag curr-tag table t))) + (type-node nil)) + (or (and curr-tag + (save-selected-window + (ecb-exec-in-methods-window + (or (tree-buffer-highlight-node-data + highlight-tag nil + (equal ecb-highlight-tag-with-point 'highlight)) + ;; The node representing HIGHLIGHT-TAG could not be + ;; highlighted by `tree-buffer-highlight-node-data' - + ;; probably it is invisible. Let's try to make expand its + ;; containing type and then highlighting again. + (when (and highlight-tag + (or (equal ecb-auto-expand-tag-tree 'all) + (member (ecb--semantic-tag-class highlight-tag) + (ecb-normalize-expand-spec + ecb-methods-nodes-expand-spec)))) + (setq type-node + (cdr (and type-tag + (tree-buffer-find-name-node-data type-tag)))) + (when type-node + (ecb-expand-methods-node-internal + type-node + 100 + (equal ecb-auto-expand-tag-tree 'all) + nil t) + (tree-buffer-highlight-node-data + highlight-tag nil + (equal ecb-highlight-tag-with-point 'highlight)))))))) + (if curr-tag + (ecb-try-highlight-tag highlight-tag type-tag table))))) + +;; This approach only expands the needed parts of the tree-buffer when +;; the current-tag is not visible as node and not the whole tree-buffer. (defun ecb-tag-sync (&optional force) (when (and ecb-minor-mode ;; we do not use here `ecb-point-in-ecb-window' because this ;; would slow down Emacs dramatically when tag-synchronization is ;; done via post-command-hook and not via an idle-timer. - (not (ecb-point-in-tree-buffer)) + (not (ecb-point-in-dedicated-special-buffer)) (not (ecb-point-in-compile-window))) (when ecb-highlight-tag-with-point - (let* ((tagstack (reverse (ecb--semantic-find-tag-by-overlay))) - (curr-tag (car tagstack)) - (next-tag (car (cdr tagstack))) - ) - (if (and (equal (ecb--semantic-tag-class curr-tag) 'variable) - (equal (ecb--semantic-tag-class next-tag) 'function) - (member curr-tag (ecb--semantic-tag-function-arguments next-tag))) - (setq curr-tag next-tag)) + (let ((curr-tag (ecb-get-real-curr-tag))) (when (or force (not (equal ecb-selected-tag curr-tag))) (setq ecb-selected-tag curr-tag) - (save-selected-window - (ecb-exec-in-methods-window - (or (tree-buffer-highlight-node-data - curr-tag nil (equal ecb-highlight-tag-with-point 'highlight)) - ;; The node representing CURR-TAG could not be highlighted be - ;; `tree-buffer-highlight-node-data' - probably it is - ;; invisible. Let's try to make visible and then highlighting - ;; again. - (when (and curr-tag ecb-auto-expand-tag-tree - (or (equal ecb-auto-expand-tag-tree 'all) - (member (ecb--semantic-tag-class curr-tag) - (ecb-normalize-expand-spec - ecb-methods-nodes-expand-spec)))) - (ecb-expand-methods-nodes-internal - 100 - (equal ecb-auto-expand-tag-tree 'all)) - (tree-buffer-highlight-node-data - curr-tag nil (equal ecb-highlight-tag-with-point 'highlight)) + ;; If there is no tag to highlight then we remove the highlighting + (if (null curr-tag) + (save-selected-window + (ecb-exec-in-methods-window + (tree-buffer-highlight-node-data nil))) + ;; First we try to expand only the absolute needed parts - this + ;; means we go upstairs the ladder of types the current tag + ;; belongs to. If this has no success then we expand the full + ;; tree-buffer and try it again. + (if (not (ecb-try-highlight-tag curr-tag curr-tag + (ecb-get-current-tag-table))) + ;; The node representing CURR-TAG could not be highlighted by + ;; `tree-buffer-highlight-node-data' - probably it is still + ;; invisible. Let's try to make visible all nodes and then + ;; highlighting again. + (save-selected-window + (ecb-exec-in-methods-window + (when (and curr-tag + (or (equal ecb-auto-expand-tag-tree 'all) + (member (ecb--semantic-tag-class curr-tag) + (ecb-normalize-expand-spec + ecb-methods-nodes-expand-spec)))) + (ecb-expand-methods-node-internal + (tree-buffer-get-root) + 100 ;; this should be enough levels ;-) + (equal ecb-auto-expand-tag-tree 'all) + nil t) + (tree-buffer-highlight-node-data + curr-tag nil (equal ecb-highlight-tag-with-point 'highlight))) ))))))))) + (defun ecb-find-file-and-display (filename other-edit-window) "Finds the file in the correct window. What the correct window is depends on the setting in `ecb-mouse-click-destination' and the value of @@ -2321,17 +2417,28 @@ file types which are parsed by imenu or etags \(see ;; expanded to max level... (when ecb-expand-methods-switch-off-auto-expand (ecb-toggle-auto-expand-tag-tree -1)) - (ecb-expand-methods-nodes-internal level force-all t))) + (ecb-expand-methods-node-internal (save-excursion + (set-buffer ecb-methods-buffer-name) + (tree-buffer-get-root)) + level force-all t t))) +(defun ecb-expand-methods-node-internal (node level + &optional force-all + resync-tag update-tree-buffer) + "Set the expand level of NODE and its subnodes in the ECB-methods-buffer. -(defun ecb-expand-methods-nodes-internal (level &optional force-all resync-tag) - "Set the expand level of the nodes in the ECB-methods-buffer. +If NODE is equal to the root-node of the methods-tree-buffer then this +function will be called for each of the root-children. Otherwise it will only +expand/collaps NODE. For description of LEVEL and FORCE-ALL see `ecb-expand-methods-nodes'. If RESYNC-TAG is not nil then after expanding/collapsing the methods-buffer is resynced to the current tag of the edit-window. +If UPDATE-TREE-BUFFER is not nil then the methods-tree-buffer will be updated +after the expansion. + Note: All this is only valid for file-types parsed by semantic. For other file types which are parsed by imenu or etags \(see `ecb-process-non-semantic-files') FORCE-ALL is always true!" @@ -2342,32 +2449,40 @@ types which are parsed by imenu or etags \(see (ignore-errors (set-buffer (get-file-buffer ecb-path-selected-source)) ;; for non-semantic buffers we set force-all always to t - (setq force-all (not (ecb--semantic-active-p))) + (setq force-all (or force-all + (not (ecb--semantic-active-p)))) (ecb--semantic-symbol->name-assoc-list))) (ecb--semantic-symbol->name-assoc-list)))) (save-selected-window (ecb-exec-in-methods-window - (let ( ;; normalizing the elements of `ecb-methods-nodes-expand-spec' + (let (;; normalizing the elements of `ecb-methods-nodes-expand-spec' ;; and `ecb-methods-nodes-collapse-spec'. (norm-expand-types (ecb-normalize-expand-spec ecb-methods-nodes-expand-spec)) (norm-collapse-types (ecb-normalize-expand-spec - ecb-methods-nodes-collapse-spec))) - (tree-buffer-expand-nodes - level - (and (not force-all) - (function (lambda (node current-level) - (or (equal norm-expand-types 'all) - (member (ecb-methods-node-get-semantic-type - node symbol->name-assoc-list) - norm-expand-types))))) - (and (not force-all) - (function (lambda (node current-level) - (or (equal norm-collapse-types 'all) - (member (ecb-methods-node-get-semantic-type - node symbol->name-assoc-list) - norm-collapse-types)))))) - (tree-buffer-scroll (point-min) (point-min))))) + ecb-methods-nodes-collapse-spec)) + (node-list (if (equal node (tree-buffer-get-root)) + (tree-node-get-children (tree-buffer-get-root)) + (list node)))) + (dolist (node node-list) + (tree-buffer-expand-node + node + level + (and (not force-all) + (function (lambda (node current-level) + (or (equal norm-expand-types 'all) + (member (ecb-methods-node-get-semantic-type + node symbol->name-assoc-list) + norm-expand-types))))) + (and (not force-all) + (function (lambda (node current-level) + (or (equal norm-collapse-types 'all) + (member (ecb-methods-node-get-semantic-type + node symbol->name-assoc-list) + norm-collapse-types))))))) + (if update-tree-buffer + (tree-buffer-update) + (tree-buffer-scroll (point-min) (point-min)))))) ;; we want resync the new method-buffer to the current tag in the ;; edit-window. @@ -2832,27 +2947,27 @@ this fails then nil is returned otherwise t." (tree-buffer-defpopup-command ecb-methods-menu-collapse-all "Collapse all expandable and expanded nodes" - (ecb-expand-methods-nodes-internal -1 nil t)) + (ecb-expand-methods-node-internal (tree-buffer-get-root) -1 nil t t)) (tree-buffer-defpopup-command ecb-methods-menu-expand-0 "Expand all nodes with level 0." - (ecb-expand-methods-nodes-internal 0 nil t)) + (ecb-expand-methods-node-internal (tree-buffer-get-root) 0 nil t t)) (tree-buffer-defpopup-command ecb-methods-menu-expand-1 "Expand all nodes with level 1." - (ecb-expand-methods-nodes-internal 1 nil t)) + (ecb-expand-methods-node-internal (tree-buffer-get-root) 1 nil t t)) (tree-buffer-defpopup-command ecb-methods-menu-expand-2 "Expand all nodes with level 2." - (ecb-expand-methods-nodes-internal 2 nil t)) + (ecb-expand-methods-node-internal (tree-buffer-get-root) 2 nil t t)) (tree-buffer-defpopup-command ecb-methods-menu-expand-all "Expand all expandable nodes recursively." - (ecb-expand-methods-nodes-internal 100 nil t)) + (ecb-expand-methods-node-internal (tree-buffer-get-root) 100 nil t t)) (defvar ecb-common-methods-menu nil @@ -2895,29 +3010,29 @@ this fails then nil is returned otherwise t." "The menu-title for the methods menu. See `ecb-directories-menu-title-creator'.") -(tree-buffer-defpopup-command ecb-jump-to-token-in-editwin1 - "Jump to current token in the 1. edit-window." +(tree-buffer-defpopup-command ecb-jump-to-tag-in-editwin1 + "Jump to current tag in the 1. edit-window." (ecb-method-clicked node 3 1 nil)) -(tree-buffer-defpopup-command ecb-jump-to-token-in-editwin2 - "Jump to current token in the 2. edit-window." +(tree-buffer-defpopup-command ecb-jump-to-tag-in-editwin2 + "Jump to current tag in the 2. edit-window." (ecb-method-clicked node 3 2 nil)) -(tree-buffer-defpopup-command ecb-jump-to-token-in-editwin3 - "Jump to current token in the 3. edit-window." +(tree-buffer-defpopup-command ecb-jump-to-tag-in-editwin3 + "Jump to current tag in the 3. edit-window." (ecb-method-clicked node 3 3 nil)) -(tree-buffer-defpopup-command ecb-jump-to-token-in-editwin4 - "Jump to current token in the 4. edit-window." +(tree-buffer-defpopup-command ecb-jump-to-tag-in-editwin4 + "Jump to current tag in the 4. edit-window." (ecb-method-clicked node 3 4 nil)) -(tree-buffer-defpopup-command ecb-jump-to-token-in-editwin5 - "Jump to current token in the 5. edit-window." +(tree-buffer-defpopup-command ecb-jump-to-tag-in-editwin5 + "Jump to current tag in the 5. edit-window." (ecb-method-clicked node 3 5 nil)) -(tree-buffer-defpopup-command ecb-jump-to-token-in-editwin6 - "Jump to current token in the 6. edit-window." +(tree-buffer-defpopup-command ecb-jump-to-tag-in-editwin6 + "Jump to current tag in the 6. edit-window." (ecb-method-clicked node 3 6 nil)) -(tree-buffer-defpopup-command ecb-jump-to-token-in-editwin7 - "Jump to current token in the 7. edit-window." +(tree-buffer-defpopup-command ecb-jump-to-tag-in-editwin7 + "Jump to current tag in the 7. edit-window." (ecb-method-clicked node 3 7 nil)) -(tree-buffer-defpopup-command ecb-jump-to-token-in-editwin8 - "Jump to current token in the 8. edit-window." +(tree-buffer-defpopup-command ecb-jump-to-tag-in-editwin8 + "Jump to current tag in the 8. edit-window." (ecb-method-clicked node 3 8 nil)) (defun ecb-methods-menu-editwin-entries () @@ -2929,12 +3044,16 @@ edit-windows. Otherwise return nil." (dotimes (i (min 8 (length edit-win-list))) (setq result (append result - (list (list (intern (format "ecb-jump-to-token-in-editwin%d" (1+ i))) + (list (list (intern (format "ecb-jump-to-tag-in-editwin%d" (1+ i))) (format "edit-window %d" (1+ i))))))) (append (list (list "---")) ;; we want a separator - (list (append (list "Jump to token in ...") + (list (append (list "Jump to tag in ...") result)))))) +;; TODO: Klaus Berndl : Here we should create all +;; tag-filter popup-menu entries; then we can do this dynamically according to +;; the current major-mode (normally each major-mode has its own tag-class +;; namings) (defun ecb-methods-menu-creator (tree-buffer-name) "Creates the popup-menus for the methods-buffer." (setq ecb-layout-prevent-handle-ecb-window-selection t) diff --git a/ecb-speedbar.el b/ecb-speedbar.el index 99912bd..f9e7f83 100644 --- a/ecb-speedbar.el +++ b/ecb-speedbar.el @@ -309,36 +309,40 @@ Return NODE." (intern (car tag)))) (ecb--semantic--tag-set-overlay new-tag (make-vector 2 (cdr tag))) (ecb--semantic--tag-put-property new-tag 'ecb-speedbar-tag t) - (tree-node-new (progn - (set-text-properties - 0 (length (car tag)) - `(face ,ecb-method-non-semantic-face) (car tag)) - (car tag)) - 0 - new-tag - t - node)) + (ecb-apply-user-filter-to-tags (list new-tag)) + (when (not (ecb-tag-forbidden-display-p new-tag)) + (tree-node-new (progn + (set-text-properties + 0 (length (car tag)) + `(face ,ecb-method-non-semantic-face) (car tag)) + (car tag)) + 0 + new-tag + t + node))) ((speedbar-generic-list-positioned-group-p tag) ;; the semantic tag for this tag (setq new-tag (ecb--semantic-tag (car tag) (intern (car tag)))) (ecb--semantic--tag-set-overlay new-tag - (make-vector 2 (car (cdr tag)))) + (make-vector 2 (car (cdr tag)))) (ecb--semantic--tag-put-property new-tag 'ecb-speedbar-tag t) - (ecb-create-non-semantic-tree - (setq new-node - (tree-node-new (progn - (set-text-properties - 0 (length (car tag)) - `(face ,ecb-method-non-semantic-face) (car tag)) - (car tag)) - 0 - new-tag - nil node)) - (cdr (cdr tag))) - (tree-node-set-expanded new-node - (member major-mode - ecb-non-semantic-methods-initial-expand))) + (ecb-apply-user-filter-to-tags (list new-tag)) + (when (not (ecb-tag-forbidden-display-p new-tag)) + (ecb-create-non-semantic-tree + (setq new-node + (tree-node-new (progn + (set-text-properties + 0 (length (car tag)) + `(face ,ecb-method-non-semantic-face) (car tag)) + (car tag)) + 0 + new-tag + nil node)) + (cdr (cdr tag))) + (tree-node-set-expanded new-node + (member major-mode + ecb-non-semantic-methods-initial-expand)))) ((speedbar-generic-list-group-p tag) (ecb-create-non-semantic-tree (setq new-node diff --git a/ecb-upgrade.el b/ecb-upgrade.el index e62b658..5cbb275 100644 --- a/ecb-upgrade.el +++ b/ecb-upgrade.el @@ -176,7 +176,8 @@ ;; Each NEWS-string should be a one-liner shorter than 70 chars (defconst ecb-upgrade-news - '(("2.22" . ("New nifty feature for filtering the tags displayed in the Methods-buffer")) + '(("2.22" . ("New nifty feature for filtering the tags displayed in the Methods-buffer" + "Much smarter mechanism to highlight the current tag in the methods-buffer")) ("2.21" . ("Advice for `balance-windows' so only the edit-windows are balanced." "Gnus, BBDB, VM, Xrefactory etc. work even when ECB-windows are visible." "Commands using `Electric-pop-up-window' now work correctly with ECB." diff --git a/ecb.el b/ecb.el index b770119..0b01b78 100644 --- a/ecb.el +++ b/ecb.el @@ -1225,7 +1225,7 @@ speedbar-window is not visible within the ECB-frame." "Toggles if RET in a tree-buffer should finally select the edit-window. See also the option `ecb-tree-RET-selects-edit-window'." (interactive) - (let ((tree-buffer (ecb-point-in-tree-buffer))) + (let ((tree-buffer (ecb-point-in-ecb-tree-buffer))) (if tree-buffer (if (member (buffer-name tree-buffer) ecb-tree-RET-selects-edit-window--internal) @@ -2537,14 +2537,12 @@ ECB has been deactivated. Do not set this variable!") ;; function is a save "equal"-condition for ECB because ;; currently the method buffer always displays only tags ;; from exactly the buffer of the current edit-window. - (if (fboundp 'ecb--semantic-equivalent-tag-p) - 'ecb--semantic-equivalent-tag-p - (function - (lambda (l r) - (and (string= (ecb--semantic-tag-name l) (ecb--semantic-tag-name r)) - (eq (ecb--semantic-tag-class l) (ecb--semantic-tag-class r)) - (eq (ecb-semantic-tag-start l) (ecb-semantic-tag-start r)) - (eq (ecb-semantic-tag-end l) (ecb-semantic-tag-end r)))))) + ;; If `ecb--semantic-equivalent-tag-p' fails we return the + ;; result of an eq-comparison. + (function (lambda (l r) + (condition-case nil + (ecb--semantic-equivalent-tag-p l r) + (error (eq l r))))) (list 1) nil 'ecb-methods-menu-creator diff --git a/ecb.texi b/ecb.texi index 17bf0ef..ced201c 100644 --- a/ecb.texi +++ b/ecb.texi @@ -2294,10 +2294,10 @@ already applied filter. @node Filtering Methods, , Filtering Sources, Filtering the tree-buffers @subsection Applying filters to the Methods-buffer -The command @code{ecb-methods-filter} allows to filter the -semantic-tags in Methods-buffer by several criterias. As for the -Sources- and the History-buffer the same functionality is also -available via the popup-menu of the Methods-buffer. +The command @code{ecb-methods-filter} allows to filter the tags/nodes +of the Methods-buffer by several criterias. As for the Sources- and +the History-buffer the same functionality is also available via the +popup-menu of the Methods-buffer. @subsubsection Possible filter-criterias @@ -2339,6 +2339,14 @@ All tags which match the applied filter(s) will be displayed in the Methods-buffer. Such a filter is only applied to the current source-buffer, i.e. each source-buffer can have its own tag-filters. +These tag-filters can also applied to sources which are not supported +by the semantic-parser but ``only'' by imenu or etags. But because for +these sources not all information are avaiable the protection- and +tag-class filter can not used with such ``non-semantic''-sources. See +@ref{Non-semantic sources} for further details about working with +source-files not supported by the semantic-parser. + + @subsubsection Inverse Filters But if @code{ecb-methods-filter} is called with a prefix-argument then diff --git a/tree-buffer.el b/tree-buffer.el index d10f7a4..d7f4864 100644 --- a/tree-buffer.el +++ b/tree-buffer.el @@ -1141,23 +1141,21 @@ point will stay on POINT." (goto-char point) (set-window-start (get-buffer-window (current-buffer)) window-start)) +(defun tree-buffer-expand-node (node level + &optional expand-pred-fn collapse-pred-fn) + "Expand the NODE up to an expand-level of LEVEL. -(defun tree-buffer-expand-nodes (level - &optional expand-pred-fn collapse-pred-fn) - "Set the expand level of the nodes in current tree-buffer. +LEVEL specifies precisely which level of nodes should be expanded. LEVEL means +the indentation-level of the NODE itself and its \(recursive) subnodes +relative to the NODE itself. -LEVEL specifies precisely which level of nodes should be expanded. LEVEL -means the indentation-level of the nodes. +A LEVEL value X means that all \(sub)nodes with an indentation-level <= X +relative to NODE are expanded and all other are collapsed. A negative LEVEL +value means that NODE is collapsed. -A LEVEL value X means that all nodes with an indentation-level <= X are -expanded and all other are collapsed. A negative LEVEL value means all visible -nodes are collapsed. - -Nodes which are not indented have indentation-level 0! - -This function expands all nodes with level <= LEVEL, so the subnodes of these -nodes get visible and collapses all their \(recursive) subnodes with -indentation-level > LEVEL. +This function expands beginning from NODE the NODE itself and all subnodes of +NODE with level <= LEVEL, so the subnodes of these nodes get visible and +collapses all their \(recursive) subnodes with indentation-level > LEVEL. If a node has to be expanded then first the `tree-node-expanded-fn' of current tree-buffer \(see `tree-buffer-create') is called with the argument-values @@ -1166,28 +1164,31 @@ tree-buffer \(see `tree-buffer-create') is called with the argument-values This function gets two optional function-arguments which are called to test if a node should be excluded from expanding or collapsing; both functions are called with two arguments, where the first one is the expandable/collapsable -node and the second one is the current level of indentation of this node: -EXPAND-PRED-FN is called if a node has to be expanded and must return nil if -this node should not be expanded even if its indentation level is <= LEVEL and -COLLAPSE-PRED-FN is called analogous for a node which has to be collapsed and -must return nil if the node should not be collapsed even if its indentation -level is > then LEVEL. +node and the second one is the current level of indentation of this node +relativ to the startnode NODE: EXPAND-PRED-FN is called if a node has to be +expanded and must return nil if this node should not be expanded even if its +indentation level is <= LEVEL and COLLAPSE-PRED-FN is called analogous for a +node which has to be collapsed and must return nil if the node should not be +collapsed even if its indentation level is > then LEVEL. Examples: -- LEVEL = 0 expands only nodes which have no indentation itself. -- LEVEL = 2 expands nodes which are either not indented or indented once or - twice." - (dolist (node (tree-node-get-children tree-buffer-root)) - (tree-buffer-expand-node node 0 level - expand-pred-fn collapse-pred-fn)) - (tree-buffer-update)) - -(defun tree-buffer-expand-node (node current-level level - expand-pred-fn collapse-pred-fn) +- LEVEL = -1 collapses the NODE. +- LEVEL = 0 expands only the NODE itself because it is the only node which can + have no indentation relativ to itself. +- LEVEL = 2 expands the NODE itself, its children and its grandchildren - + these are the nodes which are either not indented \(the NODE itself) or + indented once \(the children) or twice \(the grandchildren)." + (if (not (equal (tree-buffer-get-root) node)) + (tree-buffer-expand-node-internal node 0 level + expand-pred-fn collapse-pred-fn))) + +(defun tree-buffer-expand-node-internal (node current-level level + expand-pred-fn collapse-pred-fn) "Expand NODE if CURRENT-LEVEL \(the indentation-level of NODE) <= LEVEL or collapses NODE if CURRENT-LEVEL > LEVEL. Do this recursive for subnodes of NODE with incremented CURRENT-LEVEL. For EXPAND-PRED-FN and COLLAPSE-PRED-FN -see `tree-buffer-expand-nodes'." +see `tree-buffer-expand-node'. This function is not for external usage; use +`tree-buffer-expand-node' instead." (when (tree-node-is-expandable node) (when (and tree-node-expanded-fn (not (tree-node-is-expanded node))) @@ -1202,8 +1203,8 @@ see `tree-buffer-expand-nodes'." (> current-level level))) (tree-node-toggle-expanded node)) (dolist (child (tree-node-get-children node)) - (tree-buffer-expand-node child (1+ current-level) level - expand-pred-fn collapse-pred-fn)))) + (tree-buffer-expand-node-internal child (1+ current-level) level + expand-pred-fn collapse-pred-fn)))) (defun tree-buffer-set-root (root) (setq tree-buffer-root root)