Deprecated: The each() function is deprecated. This message will be suppressed on further calls in /home/zhenxiangba/zhenxiangba.com/public_html/phproxy-improved-master/index.php on line 456
;;; ecb-speedbar.el --- Integration of speedbar into ECB
;; Copyright (C) 2000 - 2003 Jesper Nordenberg,
;; Klaus Berndl,
;; Kevin A. Burton,
;; Free Software Foundation, Inc.
;; Author: Jesper Nordenberg
;; Klaus Berndl
;; Kevin A. Burton
;; Maintainer: Klaus Berndl
;; Kevin A. Burton
;; Keywords: browser, code, programming, tools
;; Created: 2002
;; This program is free software; you can redistribute it and/or modify it under
;; the terms of the GNU General Public License as published by the Free Software
;; Foundation; either version 2, or (at your option) any later version.
;; This program is distributed in the hope that it will be useful, but WITHOUT
;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
;; FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
;; details.
;; You should have received a copy of the GNU General Public License along with
;; GNU Emacs; see the file COPYING. If not, write to the Free Software
;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
;; $Id: ecb-speedbar.el,v 1.49 2003/09/08 12:20:17 berndl Exp $
;;; Commentary:
;; This package provide speedbar integration and using for the ECB.
;;
;; There are two complete different aspects of integration/using speedbar for
;; ECB:
;;
;; 1. Integration the speedbar itself into the ecb-frame:
;;
;; This allows you to:
;;
;; - Sync up to the speedbar with the current buffer.
;;
;; - Files opened with the speedbar are displayed in the ecb source window.
;;
;; 2. Using the speedbar-mechanism for parsing files supported not by semantic
;; but by imenu and/or etags.
;;
;; This is not done via the speedbar-display but only the parsing mechanism
;; of `speedbar-fetch-dynamic-tags' is used and the tags are natively
;; display in the methods-buffer of ECB!
;;
;; Note that this is tested with recent speedbars >= 0.14beta1. If the
;; speedbar implementation changes a lot this could break.
;;
;; If you enjoy this software, please consider a donation to the EFF
;; (http://www.eff.org)
;;; History:
;; For the ChangeLog of this file see the CVS-repository. For a complete
;; history of the ECB-package see the file NEWS.
;;; Code:
(eval-when-compile
(require 'silentcomp))
(require 'speedbar)
(require 'ecb-util)
;; imenu
(silentcomp-defvar imenu--rescan-item)
(silentcomp-defvar imenu--index-alist)
(defconst ecb-speedbar-adviced-functions '((speedbar-click . around)
(speedbar-frame-mode . around)
(speedbar-get-focus . around)
;; we have to fix a bug there
(dframe-mouse-set-point . around))
"These functions of speedbar are always adviced if ECB is active. Each
element of the list is a cons-cell where the car is the function-symbol and
the cdr the advice-class \(before, around or after). If a function should be
adviced with more than one class \(e.g. with a before and an after-advice)
then for every class a cons must be added to this list.")
(defadvice speedbar-click (around ecb)
"Makes the function compatible with ECB. If ECB is active and the window of
`ecb-speedbar-buffer-name' is visible \(means a layouts uses the
speedbar-integration) and the clicked node in speedbar is a file then the
ECB-edit-window is selected at the end. So always the edit-window is selected
after clicking onto a filename in the speedbar."
;; Klaus Berndl : We must use an around-advice because
;; we need exactly the information if the *clicked* item is a file or not.
;; This is only available before the original speedbar-click actions because
;; speedbar seems to do some intelligent stuff like autom. using the first
;; file if a clicked directory contains any.
(let ((item (and (fboundp 'speedbar-line-file)
(speedbar-line-file))))
ad-do-it
(if (and ecb-minor-mode
(equal (selected-frame) ecb-frame)
(window-live-p (get-buffer-window ecb-speedbar-buffer-name))
(and item
(file-exists-p item)
(not (file-directory-p item))))
(ecb-select-edit-window))))
(defadvice speedbar-frame-mode (around ecb)
"During running speedbar within ECB this command is disabled!"
(if ecb-minor-mode
(message "This command is disabled during running speedbar within ECB!")
ad-do-it))
(defadvice speedbar-get-focus (around ecb)
"During running speedbar within ECB this function behaves like follows:
Change window focus to or from the ECB-speedbar-window. If the selected window
is not speedbar-window, then the speedbar-window is selected. If the
speedbar-window is active, then select the edit-window."
(if ecb-minor-mode
(if (equal (current-buffer) (get-buffer ecb-speedbar-buffer-name))
(ecb-select-edit-window)
(ecb-speedbar-select-speedbar-window))
ad-do-it))
;; Klaus Berndl : This implementation is done to make
;; clear where the bug is fixed...a better impl. can be seen in
;; tree-buffer-mouse-set-point (does the same but better code - IMHO).
(defadvice dframe-mouse-set-point (around ecb)
"Fixes a bug in the original implementation: if clicked onto an image then
the point was not set by `mouse-set-point'."
(if (and (fboundp 'event-over-glyph-p) (event-over-glyph-p e))
;; We are in XEmacs, and clicked on a picture
(let ((ext (event-glyph-extent e)))
;; This position is back inside the extent where the
;; junk we pushed into the property list lives.
(if (extent-end-position ext)
(progn
(mouse-set-point e)
(goto-char (1- (extent-end-position ext))))
(mouse-set-point e)))
;; We are not in XEmacs, OR we didn't click on a picture.
(mouse-set-point e)))
(defconst ecb-speedbar-buffer-name " SPEEDBAR"
"Name of the ECB speedbar buffer.")
(defun ecb-speedbar-select-speedbar-window ()
(ignore-errors
(and (window-live-p (get-buffer-window ecb-speedbar-buffer-name))
(select-window (get-buffer-window ecb-speedbar-buffer-name)))))
(defun ecb-speedbar-set-buffer()
"Set the speedbar buffer within ECB."
(ecb-speedbar-activate)
(set-window-buffer (selected-window)
(get-buffer-create ecb-speedbar-buffer-name))
(if ecb-running-emacs-21
(set (make-local-variable 'automatic-hscrolling) nil)))
(defvar ecb-speedbar-verbosity-level-old nil)
(defvar ecb-speedbar-select-frame-method-old nil)
(defun ecb-speedbar-activate()
"Make sure the speedbar is running. WARNING: This could be dependent on the
current speedbar implementation but normally it should work with recent
speedbar versions >= 0.14beta1. But be aware: If the speedbar impl changes in
future this could break."
;; enable the advices for speedbar
(ecb-enable-advices ecb-speedbar-adviced-functions)
;;disable automatic speedbar updates... let the ECB handle this with
;;ecb-current-buffer-sync
(speedbar-disable-update)
;;always stay in the current frame
;; save the old value but only first time!
(if (null ecb-speedbar-select-frame-method-old)
(setq ecb-speedbar-select-frame-method-old speedbar-select-frame-method))
(setq speedbar-select-frame-method 'attached)
(when (not (buffer-live-p speedbar-buffer))
(save-excursion
(setq speedbar-buffer (get-buffer-create ecb-speedbar-buffer-name))
(set-buffer speedbar-buffer)
(speedbar-mode)))
;;Start up the timer
(speedbar-reconfigure-keymaps)
(speedbar-update-contents)
(speedbar-set-timer 1)
;;Set the frame that the speedbar should use. This should be the selected
;;frame. AKA the frame that ECB is running in.
(setq speedbar-frame ecb-frame)
(setq dframe-attached-frame ecb-frame)
;;this needs to be 0 because we can't have the speedbar too chatty in the
;;current frame because this will mean that the minibuffer will be updated too
;;much.
;; save the old value but only first time!
(if (null ecb-speedbar-verbosity-level-old)
(setq ecb-speedbar-verbosity-level-old speedbar-verbosity-level))
(setq speedbar-verbosity-level 0)
(add-hook 'ecb-current-buffer-sync-hook
'ecb-speedbar-current-buffer-sync)
;;reset the selection variable
(setq speedbar-last-selected-file nil))
(defun ecb-speedbar-deactivate ()
"Reset things as before activating speedbar by ECB"
(ecb-disable-advices ecb-speedbar-adviced-functions)
(setq speedbar-frame nil)
(setq dframe-attached-frame nil)
(speedbar-enable-update)
(if ecb-speedbar-select-frame-method-old
(setq speedbar-select-frame-method ecb-speedbar-select-frame-method-old))
(setq ecb-speedbar-select-frame-method-old nil)
(if ecb-speedbar-verbosity-level-old
(setq speedbar-verbosity-level ecb-speedbar-verbosity-level-old))
(setq ecb-speedbar-verbosity-level-old nil)
(remove-hook 'ecb-current-buffer-sync-hook
'ecb-speedbar-current-buffer-sync)
(when (and speedbar-buffer
(buffer-live-p speedbar-buffer))
(kill-buffer speedbar-buffer)
(setq speedbar-buffer nil)))
(defun ecb-speedbar-active-p ()
"Return not nil if speedbar is active and integrated in the `ecb-frame'."
(and (get-buffer ecb-speedbar-buffer-name)
(get-buffer-window (get-buffer ecb-speedbar-buffer-name) ecb-frame)))
(defun ecb-speedbar-update-contents ()
"Encapsulate updating the speedbar."
(speedbar-update-contents))
(defun ecb-speedbar-current-buffer-sync()
"Update the speedbar so that it's synced up with the current file."
(interactive)
;;only operate if the current frame is the ECB frame and the
;;ecb-speedbar-buffer is visible!
(ecb-do-if-buffer-visible-in-ecb-frame 'ecb-speedbar-buffer-name
;; this macro binds the local variables visible-buffer and visible-window!
(let ((speedbar-default-directory
(save-excursion
(set-buffer visible-buffer)
(ecb-fix-filename default-directory)))
(ecb-default-directory (ecb-fix-filename default-directory)))
(when (and (not (string-equal speedbar-default-directory
ecb-default-directory))
speedbar-buffer
(buffer-live-p speedbar-buffer))
(ecb-speedbar-update-contents)))))
;; Handling of files which can not be parsed by semantic (i.e. there is no
;; semantic-grammar available) but which can be parsed by imenu and/or etags
;; via speedbar.
(defun ecb-speedbar-sb-token-p (token)
"Return not nil if TOKEN is a semantic-token generated from a speedbar tag."
(semantic-token-get token 'ecb-speedbar-token))
(require 'tree-buffer)
(require 'ecb-face)
(defun ecb-create-non-semantic-tree (node tag-list)
"Add all tags of TAG-LIST with side-effects as children to NODE. TAG-LIST is
a list generated by `ecb-get-tags-for-non-semantic-files'. TAG-LIST is of the
form:
\( \(\"name\" . marker-or-number) <-- one tag at this level
\(\"name\" \(\"name\" . mon) (\"name\" . mon) ) <-- one group of tags
\(\"name\" mon \(\"name\" . mon) ) <-- group w/ a pos. and tags
Groups can contain tags which are groups again...therefore this function is
called recursive for the elements of a group.
Return NODE."
(let ((new-node nil)
(new-token nil))
(dolist (tag tag-list)
(cond ((null tag) nil) ;this would be a separator
((speedbar-generic-list-tag-p tag)
;; the semantic token for this tag
(setq new-token (list (car tag)
(intern (car tag))
nil nil nil
(make-vector 2 (cdr tag))))
(semantic-token-put new-token 'ecb-speedbar-token t)
(tree-node-new (progn
(set-text-properties
0 (length (car tag))
`(face ,ecb-method-non-semantic-face) (car tag))
(car tag))
0
new-token
t
node))
((speedbar-generic-list-positioned-group-p tag)
;; the semantic token for this tag
(setq new-token (list (car tag)
(intern (car tag))
nil nil nil
(make-vector 2 (car (cdr tag)))))
(semantic-token-put new-token 'ecb-speedbar-token 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-token
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
(tree-node-new (progn
(set-text-properties
0 (length (car tag))
`(face ,ecb-method-non-semantic-face) (car tag))
(car tag))
1
nil nil node))
(cdr tag))
(tree-node-set-expanded new-node
(member major-mode
ecb-non-semantic-methods-initial-expand)))
(t (ecb-error "ecb-create-non-semantic-tree: malformed tag-list!")
)))
node))
(defun ecb-get-tags-for-non-semantic-files ()
"Get a tag-list for current source-file. This is done via the
`speedbar-fetch-dynamic-tags' mechanism which supports imenu and etags."
(require 'imenu)
(if (member major-mode ecb-non-semantic-exclude-modes)
nil
(let* ((lst (let ((speedbar-dynamic-tags-function-list
(if (not (assoc major-mode
ecb-non-semantic-parsing-function))
speedbar-dynamic-tags-function-list
(list (cons (cdr (assoc major-mode
ecb-non-semantic-parsing-function))
'identity)))))
(speedbar-fetch-dynamic-tags (buffer-file-name
(current-buffer)))))
(tag-list (cdr lst))
(methods speedbar-tag-hierarchy-method))
;; removing the imenu-Rescan-item
(if (string= (car (car tag-list)) (car imenu--rescan-item))
(setq tag-list (cdr tag-list)))
;; If imenu or etags returns already groups (etags will do this probably
;; not, but imenu will do this sometimes - e.g. with cperl) then we do not
;; regrouping with the speedbar-methods of
;; `speedbar-tag-hierarchy-method'!
(when (dolist (tag tag-list t)
(if (or (speedbar-generic-list-positioned-group-p tag)
(speedbar-generic-list-group-p tag))
(return nil)))
(while methods
(setq tag-list (funcall (car methods) tag-list)
methods (cdr methods))))
tag-list)))
(silentcomp-provide 'ecb-speedbar)
;;; ecb-speedbar.el ends here