changelog shortlog tags changeset files revisions annotate raw

etags-select.el

changeset 66: 5b737eefe5ea
author: kim.vanwyk
date: Wed Nov 10 15:19:03 2010 +0200 (18 months ago)
permissions: -rw-r--r--
description: Adding CSharp Mode and Google Weather
1;;; etags-select.el --- Select from multiple tags
2
3;; Copyright (C) 2007 Scott Frazer
4
5;; Author: Scott Frazer <frazer.scott@gmail.com>
6;; Maintainer: Scott Frazer <frazer.scott@gmail.com>
7;; Created: 07 Jun 2007
8;; Version: 1.2
9;; Keywords: etags tags tag select
10
11;; This file 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;; This file 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, Inc., 51 Franklin Street, Fifth Floor,
24;; Boston, MA 02110-1301, USA.
25
26;;; Commentary:
27
28;; Open a buffer with file/lines of exact-match tags shown. Select one by
29;; going to a line and pressing return. pop-tag-mark still works with this
30;; code.
31;;
32;; If there is only one match, you can skip opening the selection window by
33;; setting a custom variable. This means you could substitute the key binding
34;; for find-tag-at-point with etags-select-find-tag-at-point, although it
35;; won't play well with tags-loop-continue. On the other hand, if you like
36;; the behavior of tags-loop-continue you probably don't need this code.
37;;
38;; I use this:
39;; (global-set-key "\M-?" 'etags-select-find-tag-at-point)
40;;
41;; Contributers of ideas and/or code:
42;; David Engster
43;;
44;;; Change log:
45;;
46;; 13 Jun 2007 -- Need to regexp-quote the searched-for string
47
48;;; Code:
49
50(require 'custom)
51(require 'etags)
52
53;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
54;;; Custom stuff
55
56;;;###autoload
57(defgroup etags-select-mode nil
58 "*etags select mode."
59 :group 'etags)
60
61;;;###autoload
62(defcustom etags-select-no-select-for-one-match t
63 "*If non-nil, don't open the selection window if there is only one
64matching tag."
65 :group 'etags-select-mode
66 :type '(boolean))
67
68;;;###autoload
69(defcustom etags-select-mode-hook nil
70 "*List of functions to call on entry to etags-select-mode mode."
71 :group 'etags-select-mode
72 :type 'hook)
73
74;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
75;;; Variables
76
77(defvar etags-select-buffer-name "*etags-select*"
78 "etags-select buffer name.")
79
80(defvar etags-select-mode-font-lock-keywords nil
81 "etags-select font-lock-keywords.")
82
83(defvar etags-select-starting-buffer nil
84 "etags-select buffer tag is being found from.")
85
86(defconst etags-select-non-tag-regexp "\\(\\s-*$\\|In:\\|Finding tag:\\)"
87 "etags-select non-tag regex.")
88
89;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
90;;; Functions
91
92(if (string-match "XEmacs" emacs-version)
93 (fset 'etags-select-match-string 'match-string)
94 (fset 'etags-select-match-string 'match-string-no-properties))
95
96;; I use Emacs, but with a hacked version of XEmacs' etags.el, thus this variable
97
98(defvar etags-select-use-xemacs-etags-p (fboundp 'get-tag-table-buffer)
99 "Use XEmacs etags?")
100
101(defun etags-select-insert-all-exact-matches (tagname tag-file)
102 (let ((tag-table-buffer (if etags-select-use-xemacs-etags-p
103 (get-tag-table-buffer tag-file)
104 (visit-tags-table-buffer tag-file)
105 (get-file-buffer tag-file)))
106 (tag-file-path (file-name-directory tag-file))
107 (tags-found 0)
108 tag-line filename current-filename)
109 (set-buffer tag-table-buffer)
110 (goto-char (point-min))
111 (while (re-search-forward (concat "\^?" tagname "\^A") nil t)
112 (setq tags-found (1+ tags-found))
113 (beginning-of-line)
114 (re-search-forward "\\(.*\\)\^?")
115 (setq tag-line (etags-select-match-string 1))
116 (end-of-line)
117 (save-excursion
118 (re-search-backward "\f")
119 (re-search-forward "^\\(.*?\\),")
120 (setq filename (concat tag-file-path (etags-select-match-string 1))))
121 (set-buffer etags-select-buffer-name)
122 (when (not (string= filename current-filename))
123 (insert "\nIn: " filename "\n")
124 (setq current-filename filename))
125 (insert tag-line "\n")
126 (set-buffer tag-table-buffer))
127 tags-found))
128
129;;;###autoload
130(defun etags-select-find-tag-at-point ()
131 "Do a find-tag-at-point, and display all exact matches. If only one match is
132found, see the `etags-select-no-select-for-one-match' variable to decide what
133to do."
134 (interactive)
135 (let ((tagname (find-tag-default))
136 (tag-files (if etags-select-use-xemacs-etags-p
137 (buffer-tag-table-list)
138 (mapcar 'tags-expand-table-name tags-table-list)))
139 (tags-found 0))
140 (setq etags-select-starting-buffer (buffer-name))
141 (get-buffer-create etags-select-buffer-name)
142 (set-buffer etags-select-buffer-name)
143 (setq buffer-read-only nil)
144 (erase-buffer)
145 (insert "Finding tag: " tagname "\n")
146 (mapcar (lambda (tag-file)
147 (setq tags-found (+ tags-found (etags-select-insert-all-exact-matches tagname tag-file))))
148 tag-files)
149 (cond ((= tags-found 0)
150 (message (concat "No exact match for tag \"" tagname "\""))
151 (ding))
152 ((and (= tags-found 1) etags-select-no-select-for-one-match)
153 (set-buffer etags-select-buffer-name)
154 (goto-char (point-min))
155 (etags-select-next-tag)
156 (etags-select-goto-tag))
157 (t
158 (set-buffer etags-select-buffer-name)
159 (goto-char (point-min))
160 (etags-select-next-tag)
161 (set-buffer-modified-p nil)
162 (setq buffer-read-only t)
163 (display-buffer etags-select-buffer-name)
164 (pop-to-buffer etags-select-buffer-name)
165 (force-mode-line-update)
166 (etags-select-mode tagname)))))
167
168(defun etags-select-goto-tag (&optional arg)
169 "Goto the file/line of the tag under the cursor. Use the C-u prefix to
170prevent the etags-select window from closing."
171 (interactive "P")
172 (let (tagname tag-point text-to-search-for filename filename-point (search-count 1))
173 (save-excursion
174 (goto-char (point-min))
175 (re-search-forward "Finding tag: \\(.*\\)$")
176 (setq tagname (etags-select-match-string 1)))
177 (beginning-of-line)
178 (if (looking-at etags-select-non-tag-regexp)
179 (message "Please put the cursor on a line with the tag.")
180 (setq tag-point (point))
181 (setq overlay-arrow-position (point-marker))
182 (re-search-forward "\\s-*\\(.*\\)\\s-*$")
183 (setq text-to-search-for (concat "^\\s-*" (regexp-quote (etags-select-match-string 1))))
184 (goto-char tag-point)
185 (re-search-backward "^In: \\(.*\\)$")
186 (setq filename (etags-select-match-string 1))
187 (setq filename-point (point))
188 (goto-char tag-point)
189 (while (re-search-backward text-to-search-for filename-point t)
190 (setq search-count (1+ search-count)))
191 (goto-char tag-point)
192 (if arg
193 (let ((window (get-buffer-window etags-select-starting-buffer)))
194 (when window (select-window window)))
195 (let ((window (get-buffer-window etags-select-buffer-name)))
196 (when window (delete-window window)))
197 (kill-buffer etags-select-buffer-name))
198 (display-buffer etags-select-starting-buffer)
199 (set-buffer etags-select-starting-buffer)
200 (if etags-select-use-xemacs-etags-p
201 (push-tag-mark)
202 (ring-insert find-tag-marker-ring (point-marker)))
203 (find-file filename)
204 (goto-char (point-min))
205 (while (> search-count 0)
206 (unless (re-search-forward text-to-search-for nil t)
207 (message "TAGS file out of date ... stopping at closest match")
208 (setq search-count 1))
209 (setq search-count (1- search-count)))
210 (beginning-of-line)
211 (re-search-forward tagname)
212 (goto-char (match-beginning 0)))))
213
214(defun etags-select-next-tag ()
215 (interactive)
216 (beginning-of-line)
217 (when (not (eobp))
218 (forward-line))
219 (while (and (looking-at etags-select-non-tag-regexp) (not (eobp)))
220 (forward-line))
221 (when (eobp)
222 (ding)))
223
224(defun etags-select-previous-tag ()
225 (interactive)
226 (beginning-of-line)
227 (when (not (bobp))
228 (forward-line -1))
229 (while (and (looking-at etags-select-non-tag-regexp) (not (bobp)))
230 (forward-line -1))
231 (when (bobp)
232 (ding)))
233
234(defun etags-select-quit ()
235 (interactive)
236 (kill-buffer nil)
237 (delete-window))
238
239;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
240;;; Keymap
241
242(defvar etags-select-mode-map nil "'etags-select-mode' keymap.")
243(if (not etags-select-mode-map)
244 (let ((map (make-keymap)))
245 (define-key map [(return)] 'etags-select-goto-tag)
246 (define-key map [(down)] 'etags-select-next-tag)
247 (define-key map [(up)] 'etags-select-previous-tag)
248 (define-key map [(q)] 'etags-select-quit)
249 (setq etags-select-mode-map map)))
250
251;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
252;;; Mode startup
253
254(defun etags-select-mode (tagname)
255 "etags-select-mode is a mode for browsing through tags.\n\n
256\\{etags-select-mode-map}"
257 (interactive)
258 (kill-all-local-variables)
259 (setq major-mode 'etags-select-mode)
260 (setq mode-name "etags-select")
261 (set-syntax-table text-mode-syntax-table)
262 (use-local-map etags-select-mode-map)
263 (make-local-variable 'font-lock-defaults)
264 (setq etags-select-mode-font-lock-keywords
265 (list (list "^\\(Finding tag:\\)" '(1 font-lock-keyword-face))
266 (list "^\\(In:\\) \\(.*\\)" '(1 font-lock-keyword-face) '(2 font-lock-string-face))
267 (list tagname '(0 font-lock-function-name-face))))
268 (setq font-lock-defaults '(etags-select-mode-font-lock-keywords))
269 (setq overlay-arrow-position nil)
270 (run-hooks 'etags-select-mode-hook))
271
272(provide 'etags-select)
273;;; etags-select.el ends here