123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538 |
- (require 'semantic)
- (require 'semantic/format)
- (require 'semantic/db)
- (require 'semantic/db-file)
- (require 'semantic/sort)
- (require 'imenu)
- (declare-function pulse-momentary-highlight-one-line "pulse" (o &optional face))
- (declare-function semanticdb-semantic-init-hook-fcn "db-mode")
- (if (featurep 'speedbar)
- (require 'semantic/sb)
- (add-hook 'speedbar-load-hook (lambda () (require 'semantic/sb))))
- (defgroup semantic-imenu nil
- "Semantic interface to Imenu."
- :group 'semantic
- :group 'imenu
- )
- (defcustom semantic-imenu-summary-function 'semantic-format-tag-abbreviate
- "*Function to use when creating items in Imenu.
- Some useful functions are found in `semantic-format-tag-functions'."
- :group 'semantic-imenu
- :type semantic-format-tag-custom-list)
- (make-variable-buffer-local 'semantic-imenu-summary-function)
- (defcustom semantic-imenu-bucketize-file t
- "*Non-nil if tags in a file are to be grouped into buckets."
- :group 'semantic-imenu
- :type 'boolean)
- (make-variable-buffer-local 'semantic-imenu-bucketize-file)
- (defcustom semantic-imenu-adopt-external-members t
- "*Non-nil if types in a file should adopt externally defined members.
- C++ and CLOS can define methods that are not in the body of a class
- definition."
- :group 'semantic-imenu
- :type 'boolean)
- (defcustom semantic-imenu-buckets-to-submenu t
- "*Non-nil if buckets of tags are to be turned into submenus.
- This option is ignored if `semantic-imenu-bucketize-file' is nil."
- :group 'semantic-imenu
- :type 'boolean)
- (make-variable-buffer-local 'semantic-imenu-buckets-to-submenu)
- (defcustom semantic-imenu-expand-type-members t
- "*Non-nil if types should have submenus with members in them."
- :group 'semantic-imenu
- :type 'boolean)
- (make-variable-buffer-local 'semantic-imenu-expand-type-members)
- (semantic-varalias-obsolete 'semantic-imenu-expand-type-parts
- 'semantic-imenu-expand-type-members "23.2")
- (defcustom semantic-imenu-bucketize-type-members t
- "*Non-nil if members of a type should be grouped into buckets.
- A nil value means to keep them in the same order.
- Overridden to nil if `semantic-imenu-bucketize-file' is nil."
- :group 'semantic-imenu
- :type 'boolean)
- (make-variable-buffer-local 'semantic-imenu-bucketize-type-members)
- (semantic-varalias-obsolete 'semantic-imenu-bucketize-type-parts
- 'semantic-imenu-bucketize-type-members "23.2")
- (defcustom semantic-imenu-sort-bucket-function nil
- "*Function to use when sorting tags in the buckets of functions.
- See `semantic-bucketize' and the FILTER argument for more details on this function."
- :group 'semantic-imenu
- :type '(radio (const :tag "No Sorting" nil)
- (const semantic-sort-tags-by-name-increasing)
- (const semantic-sort-tags-by-name-decreasing)
- (const semantic-sort-tags-by-type-increasing)
- (const semantic-sort-tags-by-type-decreasing)
- (const semantic-sort-tags-by-name-increasing-ci)
- (const semantic-sort-tags-by-name-decreasing-ci)
- (const semantic-sort-tags-by-type-increasing-ci)
- (const semantic-sort-tags-by-type-decreasing-ci)
- (function)))
- (make-variable-buffer-local 'semantic-imenu-sort-bucket-function)
- (defcustom semantic-imenu-index-directory nil
- "*Non nil to index the entire directory for tags.
- Doesn't actually parse the entire directory, but displays tags for all files
- currently listed in the current Semantic database.
- This variable has no meaning if semanticdb is not active."
- :group 'semantic-imenu
- :type 'boolean)
- (defcustom semantic-imenu-auto-rebuild-directory-indexes nil
- "*If non-nil automatically rebuild directory index imenus.
- That is when a directory index imenu is updated, automatically rebuild
- other buffer local ones based on the same semanticdb."
- :group 'semantic-imenu
- :type 'boolean)
- (defvar semantic-imenu-directory-current-file nil
- "When building a file index, this is the file name currently being built.")
- (defvar semantic-imenu-auto-rebuild-running nil
- "Non-nil if `semantic-imenu-rebuild-directory-indexes' is running.")
- (defvar semantic-imenu-expandable-tag-classes '(type)
- "List of expandable tag classes.
- Tags of those classes will be given submenu with children.
- By default, a `type' has interesting children. In Texinfo, however, a
- `section' has interesting children.")
- (make-variable-buffer-local 'semantic-imenu-expandable-tag-classes)
- (semantic-varalias-obsolete 'semantic-imenu-expandable-token
- 'semantic-imenu-expandable-tag-classes "23.2")
- (defun semantic-imenu-tag-overlay (tag)
- "Return the overlay belonging to tag.
- If TAG doesn't have an overlay, and instead as a vector of positions,
- concoct a combination of file name, and position."
- (let ((o (semantic-tag-overlay tag)))
- (if (not (semantic-overlay-p o))
- (let ((v (make-vector 3 nil)))
- (aset v 0 semantic-imenu-directory-current-file)
- (aset v 1 (aref o 0))
- (aset v 2 (aref o 1))
- v)
- o)))
- (defun semantic-imenu-goto-function (name position &optional rest)
- "Move point associated with NAME to POSITION.
- Used to override function `imenu-default-goto-function' so that
- we can continue to use overlays to maintain the current position.
- Optional argument REST is some extra stuff."
- (require 'pulse)
- (if (semantic-overlay-p position)
- (let ((os (semantic-overlay-start position))
- (ob (semantic-overlay-buffer position)))
- (if os
- (progn
- (if (not (eq ob (current-buffer)))
- (switch-to-buffer ob))
- (imenu-default-goto-function name os rest)
- (pulse-momentary-highlight-one-line (point))
- )
-
- (message "Imenu is out of date, try again. (internal bug)")
- (setq imenu--index-alist nil)))
-
-
- (if (vectorp position)
- (let ((file (aref position 0))
- (pos (aref position 1)))
- (and file (find-file file))
- (imenu-default-goto-function name pos rest)
- (pulse-momentary-highlight-one-line (point))
- )
-
-
-
- (if (eq position 'file-only)
- (progn
- (find-file name)
- (imenu-default-goto-function name (point-min) rest)
- (pulse-momentary-highlight-one-line (point))
- )
-
-
- (condition-case nil
- (progn
- (imenu-default-goto-function name position rest)
- (pulse-momentary-highlight-one-line (point))
- )
- (error
- (message "Semantic Imenu override problem. (Internal bug)")
- (setq imenu--index-alist nil)))))
- ))
- (defun semantic-imenu-flush-fcn (&optional ignore)
- "This function is called as a hook to clear the imenu cache.
- It is cleared after any parsing.
- IGNORE arguments."
- (if (eq imenu-create-index-function 'semantic-create-imenu-index)
- (setq imenu--index-alist nil
- imenu-menubar-modified-tick 0))
- (remove-hook 'semantic-after-toplevel-cache-change-hook
- 'semantic-imenu-flush-fcn t)
- (remove-hook 'semantic-after-partial-cache-change-hook
- 'semantic-imenu-flush-fcn t)
- )
- (defun semantic-create-imenu-index (&optional stream)
- "Create an imenu index for any buffer which supports Semantic.
- Uses the output of the Semantic parser to create the index.
- Optional argument STREAM is an optional stream of tags used to create menus."
- (setq imenu-default-goto-function 'semantic-imenu-goto-function)
- (prog1
- (if (and semantic-imenu-index-directory
- (featurep 'semantic/db)
- (semanticdb-minor-mode-p))
- (semantic-create-imenu-directory-index
- (or stream (semantic-fetch-tags-fast)))
- (semantic-create-imenu-index-1
- (or stream (semantic-fetch-tags-fast)) nil))
- (semantic-make-local-hook 'semantic-after-toplevel-cache-change-hook)
- (add-hook 'semantic-after-toplevel-cache-change-hook
- 'semantic-imenu-flush-fcn nil t)
- (semantic-make-local-hook 'semantic-after-partial-cache-change-hook)
- (add-hook 'semantic-after-partial-cache-change-hook
- 'semantic-imenu-flush-fcn nil t)))
- (defun semantic-create-imenu-directory-index (&optional stream)
- "Create an imenu tag index based on all files active in semanticdb.
- Optional argument STREAM is the stream of tags for the current buffer."
- (if (not semanticdb-current-database)
- (semantic-create-imenu-index-1 stream nil)
-
- (let ((index (list
- (cons (oref semanticdb-current-table file)
- (or (semantic-create-imenu-index-1 stream nil)
-
- 'file-only))))
- (tables (semanticdb-get-database-tables semanticdb-current-database)))
- (while tables
- (let ((semantic-imenu-directory-current-file
- (oref (car tables) file))
- tags)
- (when (and (not (eq (car tables) semanticdb-current-table))
- (semanticdb-live-p (car tables))
- (semanticdb-equivalent-mode (car tables))
- )
- (setq tags (oref (car tables) tags)
- index (cons (cons semantic-imenu-directory-current-file
- (or (and tags
-
-
-
- (semantic-create-imenu-index-1
- (oref (car tables) tags)
- nil))
-
- 'file-only))
- index)))
- (setq tables (cdr tables))))
-
-
- (or (not semantic-imenu-auto-rebuild-directory-indexes)
-
- semantic-imenu-auto-rebuild-running
- (unwind-protect
- (progn
- (setq semantic-imenu-auto-rebuild-running t)
- (semantic-imenu-rebuild-directory-indexes
- semanticdb-current-database))
- (setq semantic-imenu-auto-rebuild-running nil)))
- (nreverse index))))
- (defun semantic-create-imenu-index-1 (stream &optional parent)
- "Create an imenu index for any buffer which supports Semantic.
- Uses the output of the Semantic parser to create the index.
- STREAM is a stream of tags used to create menus.
- Optional argument PARENT is a tag parent of STREAM."
- (let ((tags stream)
- (semantic-imenu-adopt-external-members
- semantic-imenu-adopt-external-members))
-
- (if semantic-imenu-adopt-external-members
- (setq tags (semantic-adopt-external-members tags)
-
- semantic-imenu-adopt-external-members nil))
-
- (if semantic-imenu-bucketize-file
- (let ((buckets (semantic-bucketize
- tags parent
- semantic-imenu-sort-bucket-function))
- item name
- index)
- (cond
- ((null buckets)
- nil)
- ((or (cdr-safe buckets)
- (not semantic-imenu-buckets-to-submenu))
- (while buckets
- (setq name (car (car buckets))
- item (cdr (car buckets)))
- (if semantic-imenu-buckets-to-submenu
- (progn
-
- (if item
- (setq index
- (cons (cons name
- (semantic-create-imenu-subindex item))
- index))))
-
- (if item
- (setq index
- (append index
-
-
- (if (memq (semantic-tag-class (car item))
- semantic-imenu-expandable-tag-classes)
- (semantic-create-imenu-subindex item)
- (cons
- '("---")
- (semantic-create-imenu-subindex item)))))
- ))
- (setq buckets (cdr buckets)))
- (if semantic-imenu-buckets-to-submenu
- (nreverse index)
- index))
- (t
- (setq name (car (car buckets))
- item (cdr (car buckets)))
- (semantic-create-imenu-subindex item))))
-
- (semantic-create-imenu-subindex tags))))
- (defun semantic-create-imenu-subindex (tags)
- "From TAGS, create an imenu index of interesting things."
- (let ((notypecheck (not semantic-imenu-expand-type-members))
- children index tag parts)
- (while tags
- (setq tag (car tags)
- children (semantic-tag-components-with-overlays tag))
- (if (and (not notypecheck)
- (memq (semantic-tag-class tag)
- semantic-imenu-expandable-tag-classes)
- children
- )
-
-
-
- (progn
- (setq parts children)
-
-
-
-
-
- (setq index
- (cons
- (cons
- (funcall semantic-imenu-summary-function tag)
-
- (if (and parts
-
-
-
- (semantic-tag-p (car parts)))
- (let ((submenu
- (if (and semantic-imenu-bucketize-type-members
- semantic-imenu-bucketize-file)
- (semantic-create-imenu-index-1 parts tag)
- (semantic-create-imenu-subindex parts))))
-
-
- (if (semantic-tag-with-position-p tag)
- (cons
- (cons "*definition*"
- (semantic-imenu-tag-overlay tag))
- submenu)
- submenu))
-
-
- (if (semantic-tag-with-position-p tag)
- (semantic-imenu-tag-overlay tag)
- nil)
- ))
- index)))
- (if (semantic-tag-with-position-p tag)
- (setq index (cons
- (cons
- (funcall semantic-imenu-summary-function tag)
- (semantic-imenu-tag-overlay tag))
- index))))
- (setq tags (cdr tags)))
-
-
-
- (imenu--split-submenus (nreverse index))))
- (defun semantic-imenu-rebuild-directory-indexes (db)
- "Rebuild directory index imenus based on Semantic database DB."
- (let ((l (buffer-list))
- b)
- (while l
- (setq b (car l)
- l (cdr l))
- (if (and (not (eq b (current-buffer)))
- (buffer-live-p b))
- (with-current-buffer b
-
-
- (when (and (eq imenu-create-index-function
- 'semantic-create-imenu-index)
- semanticdb-current-database
- (eq semanticdb-current-database db))
-
- (imenu--cleanup)
- (setq imenu--index-alist nil)
- (funcall
- (if (fboundp 'imenu-menu-filter)
-
- 'imenu-menu-filter
-
- 'imenu-update-menubar))))))))
- (defun semantic-imenu-semanticdb-hook ()
- "Function to be called from `semanticdb-mode-hook'.
- Clears all imenu menus that may be depending on the database."
- (require 'semantic/db-mode)
- (semantic-map-buffers
- #'(lambda ()
-
- (if (semanticdb-minor-mode-p)
- (semanticdb-semantic-init-hook-fcn))
-
- (semantic-imenu-flush-fcn))))
- (add-hook 'semanticdb-mode-hook 'semantic-imenu-semanticdb-hook)
- (defun semantic-imenu-toggle-bucketize-file ()
- "Toggle the ability of imenu to bucketize the current file."
- (interactive)
- (setq semantic-imenu-bucketize-file (not semantic-imenu-bucketize-file))
-
- (setq imenu--index-alist nil))
- (defun semantic-imenu-toggle-buckets-to-submenu ()
- "Toggle the ability of imenu to turn buckets into submenus."
- (interactive)
- (setq semantic-imenu-buckets-to-submenu (not semantic-imenu-buckets-to-submenu))
-
- (setq imenu--index-alist nil))
- (defun semantic-imenu-toggle-bucketize-type-parts ()
- "Toggle the ability of imenu to bucketize the current file."
- (interactive)
- (setq semantic-imenu-bucketize-type-members (not semantic-imenu-bucketize-type-members))
-
- (setq imenu--index-alist nil))
- (require 'advice)
- (defvar semantic-which-function 'semantic-default-which-function
- "Function to convert semantic tags into `which-function' text.")
- (defcustom semantic-which-function-use-color nil
- "*Use color when displaying the current function with `which-function'."
- :group 'semantic-imenu
- :type 'boolean)
- (defun semantic-default-which-function (taglist)
- "Convert TAGLIST into a string usable by `which-function'.
- Returns the first tag name in the list, unless it is a type,
- in which case it concatenates them together."
- (cond ((eq (length taglist) 1)
- (semantic-format-tag-abbreviate
- (car taglist) nil semantic-which-function-use-color))
- ((memq (semantic-tag-class (car taglist))
- semantic-imenu-expandable-tag-classes)
- (concat (semantic-format-tag-name
- (car taglist) nil semantic-which-function-use-color)
- (car semantic-type-relation-separator-character)
-
-
- (semantic-default-which-function (cdr taglist))))
- (t (semantic-format-tag-abbreviate
- (car taglist) nil semantic-which-function-use-color))))
- (provide 'semantic/imenu)
|