gnu-emacs-sources
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

etags-select.el


From: Scott Frazer
Subject: etags-select.el
Date: Thu, 07 Jun 2007 06:51:44 -0700
User-agent: G2/1.0

Someone on gnu.emacs.help asked if there was a way to browse through
multiple matching tags for an identifier and choose a specific one (as
opposed to tags-loop-continue). This is helpful when you have
overloaded function names and want to go to the right one. I am using
an aspect-oriented language (Specman) that extends methods all over
the place, so this was something I've been thinking about doing for a
while. So I finally took a couple hours and did it.

It seems to work for Emacs, XEmacs, and my personal favorite: Emacs
with a hacked version of XEmacs etags.el (which I find superior).

;;; etags-select.el --- Select from multiple tags

;; Copyright (C) 2007  Scott Frazer

;; Author: Scott Frazer <address@hidden>
;; Keywords: etags tags tag select

;; This file 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 file 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., 51 Franklin Street, Fifth
Floor,
;; Boston, MA 02110-1301, USA.

;;; Commentary:

;; Open a buffer with file/lines of exact-match tags shown.  Select
one by
;; going to a line and pressing return.
;;
;; I use this:
;; (global-set-key "\M-?" 'etags-select-find-tag-at-point)

;;; Code:

(require 'custom)
(require 'etags)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Custom stuff

(defgroup etags-select-mode nil
  "*etags select mode."
  :group 'etags)

(defcustom etags-select-mode-hook nil
  "*List of functions to call on entry to etags-select-mode mode."
  :group 'etags-select-mode
  :type 'hook)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Variables

(defvar etags-select-buffer-name "*etags-select*"
  "etags-select buffer name.")

(defvar etags-select-mode-font-lock-keywords nil
  "etags-select font-lock-keywords")

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Functions

(if (string-match "XEmacs" emacs-version)
    (fset 'etags-select-match-string 'match-string)
  (fset 'etags-select-match-string 'match-string-no-properties))

;; I use Emacs, but with a hacked version of XEmacs' etags.el, thus
this variable

(defvar etags-select-use-xemacs-etags-p (fboundp 'get-tag-table-
buffer)
  "Use XEmacs etags?")

(defun etags-select-insert-all-exact-matches (tagname tag-file)
  (let ((tag-table-buffer (if etags-select-use-xemacs-etags-p
                              (get-tag-table-buffer tag-file)
                            (visit-tags-table-buffer tag-file)
                            (get-file-buffer tag-file)))
        (tag-file-path (file-name-directory tag-file))
        tag-line filename current-filename)
    (set-buffer tag-table-buffer)
    (goto-char (point-min))
    (while (re-search-forward (concat "" tagname "") nil t)
      (beginning-of-line)
      (re-search-forward "\\(.*\\)")
      (setq tag-line (etags-select-match-string 1))
      (end-of-line)
      (save-excursion
        (re-search-backward "")
        (re-search-forward "^\\(.*?\\),")
        (setq filename (concat tag-file-path (etags-select-match-
string 1))))
      (set-buffer etags-select-buffer-name)
      (when (not (string= filename current-filename))
        (insert "\nIn: " filename "\n")
        (setq current-filename filename))
      (insert tag-line "\n")
      (set-buffer tag-table-buffer))))

(defun etags-select-find-tag-at-point ()
  (interactive)
  (let ((tagname (find-tag-default))
        (tag-files (if etags-select-use-xemacs-etags-p
                       (buffer-tag-table-list)
                     tags-table-list)))
    (get-buffer-create etags-select-buffer-name)
    (set-buffer etags-select-buffer-name)
    (setq buffer-read-only nil)
    (erase-buffer)
    (display-buffer etags-select-buffer-name)
    (pop-to-buffer etags-select-buffer-name)
    (insert "Finding tag: " tagname "\n")
    (mapcar (lambda (tag-file) (etags-select-insert-all-exact-matches
tagname tag-file)) tag-files)
    (set-buffer etags-select-buffer-name)
    (goto-char (point-min))
    (set-buffer-modified-p nil)
    (setq buffer-read-only t)
    (force-mode-line-update)
    (etags-select-mode tagname)))

(defun etags-select-goto-tag ()
  (interactive)
  (let (tag-point text-to-search-for filename filename-point (search-
count 1))
    (beginning-of-line)
    (if (looking-at "\\(\\s-*$\\|In:\\|Finding tag:\\)")
        (message "Please put the cursor on a line with the tag.")
      (setq tag-point (point))
      (setq overlay-arrow-position (point-marker))
      (re-search-forward "\\s-*\\(.*\\)\\s-*$")
      (setq text-to-search-for (concat "^\\s-*" (etags-select-match-
string 1)))
      (goto-char tag-point)
      (re-search-backward "^In: \\(.*\\)$")
      (setq filename (etags-select-match-string 1))
      (setq filename-point (point))
      (goto-char tag-point)
      (while (re-search-backward text-to-search-for filename-point t)
        (setq search-count (1+ search-count)))
      (goto-char tag-point)
      (other-window 1)
      (find-file filename)
      (goto-char (point-min))
      (while (> search-count 0)
        (unless (re-search-forward text-to-search-for nil t)
          (message "TAGS file out of date ... stopping at closest
match")
          (setq search-count 1))
        (setq search-count (1- search-count)))
      (beginning-of-line))))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Keymap

(defvar etags-select-mode-map nil "'etags-select-mode' keymap.")
(if (not etags-select-mode-map)
    (let ((map (make-keymap)))
      (define-key map [(return)] 'etags-select-goto-tag)
      (setq etags-select-mode-map map)))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; Mode startup

(defun etags-select-mode (tagname)
  "etags-select-mode is a mode for browsing through tags.\n\n
\\{etags-select-mode-map}"
  (interactive)
  (kill-all-local-variables)
  (setq major-mode 'etags-select-mode)
  (setq mode-name "etags-select")
  (set-syntax-table text-mode-syntax-table)
  (use-local-map etags-select-mode-map)
  (make-local-variable 'font-lock-defaults)
  (setq etags-select-mode-font-lock-keywords
        (list (list "^\\(Finding tag:\\)" '(1 font-lock-keyword-face))
              (list "^\\(In:\\) \\(.*\\)" '(1 font-lock-keyword-face)
'(2 font-lock-string-face))
              (list tagname '(0 font-lock-function-name-face))))
  (setq font-lock-defaults '(etags-select-mode-font-lock-keywords))
  (setq overlay-arrow-position nil)
  (run-hooks 'etags-select-mode-hook))

(provide 'etags-select)
;;; etags-select.el ends here



reply via email to

[Prev in Thread] Current Thread [Next in Thread]