1 ;;; gtags.el --- gtags facility for Emacs
4 ;; Copyright (c) 1997, 1998, 1999 Shigio Yamaguchi. All rights reserved.
6 ;; Redistribution and use in source and binary forms, with or without
7 ;; modification, are permitted provided that the following conditions
9 ;; 1. Redistributions of source code must retain the above copyright
10 ;; notice, this list of conditions and the following disclaimer.
11 ;; 2. Redistributions in binary form must reproduce the above copyright
12 ;; notice, this list of conditions and the following disclaimer in the
13 ;; documentation and/or other materials provided with the distribution.
14 ;; 3. All advertising materials mentioning features or use of this software
15 ;; must display the following acknowledgement:
16 ;; This product includes software developed by Shigio Yamaguchi.
17 ;; 4. Neither the name of the author nor the names of any co-contributors
18 ;; may be used to endorse or promote products derived from this software
19 ;; without specific prior written permission.
21 ;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22 ;; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 ;; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 ;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25 ;; FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 ;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 ;; OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 ;; HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 ;; LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 ;; OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 ;; This file is part of GLOBAL.
37 ;; Author: Shigio Yamaguchi <shigio@wafu.netgate.net>
43 (defvar gtags-buffer-stack nil
44 "Stack for tag browsing.")
45 (defvar gtags-point-stack nil
46 "Stack for tag browsing.")
47 (defvar gtags-complete-list nil
48 "Gtags complete list.")
49 (defconst symbol-regexp "[A-Za-z_][A-Za-z_0-9]*"
50 "Regexp matching tag name.")
51 (defconst definition-regexp "#[ \t]*define[ \t]+\\|ENTRY(\\|ALTENTRY("
52 "Regexp matching tag definition name.")
53 (defvar gtags-read-only nil
54 "Gtags read only mode")
55 (defvar gtags-mode-map (make-sparse-keymap)
56 "Keymap used in gtags mode.")
57 (define-key gtags-mode-map "\et" 'gtags-find-tag)
58 (define-key gtags-mode-map "\er" 'gtags-find-rtag)
59 (define-key gtags-mode-map "\es" 'gtags-find-symbol)
60 (define-key gtags-mode-map "\eg" 'gtags-find-pattern)
61 (define-key gtags-mode-map "\C-]" 'gtags-find-tag-from-here)
62 (define-key gtags-mode-map "\eh" 'gtags-display-browser)
63 (define-key gtags-mode-map "\C-t" 'gtags-pop-stack)
64 (define-key gtags-mode-map "\e." 'etags-style-find-tag)
65 (define-key gtags-mode-map [mouse-2] 'gtags-find-tag-by-event)
66 (define-key gtags-mode-map [mouse-3] 'gtags-pop-stack)
68 (defvar gtags-select-mode-map (make-sparse-keymap)
69 "Keymap used in gtags select mode.")
70 (define-key gtags-select-mode-map "q" 'gtags-pop-stack)
71 (define-key gtags-select-mode-map "\C-t" 'gtags-pop-stack)
72 (define-key gtags-select-mode-map "\C-m" 'gtags-select-tag)
73 (define-key gtags-select-mode-map " " 'scroll-up)
74 (define-key gtags-select-mode-map "\^?" 'scroll-down)
75 (define-key gtags-select-mode-map "\C-f" 'scroll-up)
76 (define-key gtags-select-mode-map "\C-b" 'scroll-down)
77 (define-key gtags-select-mode-map "n" 'next-line)
78 (define-key gtags-select-mode-map "p" 'previous-line)
79 (define-key gtags-select-mode-map "j" 'next-line)
80 (define-key gtags-select-mode-map "k" 'previous-line)
81 (define-key gtags-select-mode-map [mouse-2] 'gtags-select-tag-by-event)
82 (define-key gtags-select-mode-map [mouse-3] 'gtags-pop-stack)
87 (defun util-match-string (n)
88 (buffer-substring (match-beginning n) (match-end n)))
90 ;; Return a default tag to search for, based on the text at point.
91 (defun gtags-current-token ()
93 ((looking-at "[0-9A-Za-z_]")
94 (while (looking-at "[0-9A-Za-z_]")
98 (while (looking-at "[ \t]")
100 (if (and (bolp) (looking-at definition-regexp))
101 (goto-char (match-end 0)))
102 (if (looking-at symbol-regexp)
103 (util-match-string 0) nil))
105 ;; push current context to stack
106 (defun push-context ()
107 (setq gtags-buffer-stack (cons (current-buffer) gtags-buffer-stack))
108 (setq gtags-point-stack (cons (point) gtags-point-stack)))
110 ;; pop context from stack
111 (defun pop-context ()
112 (if (not gtags-buffer-stack) nil
114 (setq buffer (car gtags-buffer-stack))
115 (setq gtags-buffer-stack (cdr gtags-buffer-stack))
116 (setq point (car gtags-point-stack))
117 (setq gtags-point-stack (cdr gtags-point-stack))
118 (list buffer point))))
120 ;; if the buffer exist in the stack
121 (defun exist-in-stack (buffer)
122 (memq buffer gtags-buffer-stack))
125 (defun is-function ()
127 (while (and (not (eolp)) (looking-at "[0-9A-Za-z_]"))
129 (while (and (not (eolp)) (looking-at "[ \t]"))
131 (if (looking-at "(") t nil)))
133 ;; is it a definition?
134 (defun is-definition ()
136 (if (and (string-match "\.java$" buffer-file-name) (looking-at "[^(]+([^)]*)[ \t]*{"))
142 ((looking-at "define")
144 (while (and (not (bolp)) (looking-at "[ \t]"))
146 (if (and (bolp) (looking-at "#"))
148 ((looking-at "ENTRY\\|ALTENTRY")
149 (if (bolp) t nil)))))))
152 ;; interactive command
154 (defun gtags-find-tag ()
155 "Input tag name and move to the definition."
158 (setq tagname (completing-read ":tag " gtags-complete-list))
160 (gtags-goto-tag tagname "")))
162 (defun etags-style-find-tag ()
163 "Input tag name and move to the definition.(etags style)"
165 (let (tagname prompt input)
166 (setq tagname (gtags-current-token))
168 (setq prompt (concat "Find tag: (default " tagname ") "))
169 (setq prompt "Find tag: "))
170 (setq input (completing-read prompt gtags-complete-list))
171 (if (not (equal "" input)) (setq tagname input))
173 (gtags-goto-tag tagname "")))
175 (defun gtags-find-symbol ()
176 "Input symbol and move to the locations."
178 (let (tagname prompt input)
179 (setq tagname (gtags-current-token))
181 (setq prompt (concat "Find symbol: (default " tagname ") "))
182 (setq prompt "Find symbol: "))
183 (setq input (read-string prompt))
184 (if (not (equal "" input)) (setq tagname input))
186 (gtags-goto-tag tagname "s")))
188 (defun gtags-find-pattern ()
189 "Input pattern and move to the locations."
191 (let (tagname prompt input)
192 (setq tagname (gtags-current-token))
194 (setq prompt (concat "Find pattern: (default " tagname ") "))
195 (setq prompt "Find pattern: "))
196 (setq input (read-string prompt))
197 (if (not (equal "" input)) (setq tagname input))
199 (gtags-goto-tag tagname "g")))
201 (defun gtags-find-rtag ()
202 "Input tag name and move to the referenced point."
205 (setq tagname (completing-read ":rtag " gtags-complete-list))
207 (gtags-goto-tag tagname "r")))
209 (defun gtags-find-tag-from-here ()
210 "Get the expression as a tagname around here and move there."
213 (setq tagname (gtags-current-token))
215 (if (is-definition) (setq flag "r") (setq flag ""))
220 (gtags-goto-tag tagname flag))))
222 (defun gtags-display-browser ()
223 "Display current screen on hypertext browser."
228 (if (equal (point-min) (point))
230 (setq lno (count-lines (point-min) (point)))))
231 (message (number-to-string lno))
232 (call-process "gozilla" nil t nil (concat "+" (number-to-string lno)) buffer-file-name)))
234 (defun gtags-find-tag-by-event (event)
235 "Get the expression as a tagname around here and move there."
237 (select-window (posn-window (event-end event)))
238 (set-buffer (window-buffer (posn-window (event-end event))))
239 (goto-char (posn-point (event-end event)))
241 (if (= 0 (count-lines (point-min) (point-max)))
242 (progn (setq tagname "main") (setq flag ""))
243 (setq tagname (gtags-current-token))
245 (if (is-definition) (setq flag "r") (setq flag ""))
250 (gtags-goto-tag tagname flag))))
252 (defun gtags-select-tag ()
253 "Select a tagname in [GTAGS SELECT MODE] and move there."
256 (gtags-select-it nil))
258 (defun gtags-select-tag-by-event (event)
259 "Select a tagname in [GTAGS SELECT MODE] and move there."
261 (select-window (posn-window (event-end event)))
262 (set-buffer (window-buffer (posn-window (event-end event))))
263 (goto-char (posn-point (event-end event)))
265 (gtags-select-it nil))
267 (defun gtags-pop-stack ()
268 "Move to previous point on the stack."
270 (let (delete context buffer)
271 (if (not (exist-in-stack (current-buffer)))
273 (setq context (pop-context))
275 (message "The tags stack is empty.")
277 (kill-buffer (current-buffer)))
278 (switch-to-buffer (nth 0 context))
279 (goto-char (nth 1 context)))))
286 (defun gtags-goto-tag (tagname flag)
287 (let (save prefix buffer lines)
288 (setq save (current-buffer))
296 (t (setq prefix "(D)")))
298 (setq buffer (generate-new-buffer (generate-new-buffer-name (concat prefix tagname))))
300 (if (not (= 0 (call-process "global" nil t nil (concat "-ax" flag) tagname)))
301 (progn (message (buffer-substring (point-min)(1- (point-max))))
303 (goto-char (point-min))
304 (setq lines (count-lines (point-min) (point-max)))
307 (message "%s: tag not found" tagname)
314 (switch-to-buffer buffer)
315 (gtags-select-mode))))))
317 ;; select a tag line from lines
318 (defun gtags-select-it (delete)
320 ;; get context from current tag line
322 ;; (if (not (looking-at "[A-Za-z_][A-Za-z_0-9]*[ \t]+\\([0-9]+\\)[ \t]\\([^ \t]+\\)[ \t]"))
323 (if (not (looking-at "[^ \t]+[ \t]+\\([0-9]+\\)[ \t]\\([^ \t]+\\)[ \t]"))
325 (setq line (string-to-number (util-match-string 1)))
326 (setq file (util-match-string 2))
327 (if delete (kill-buffer (current-buffer)))
328 ;; move to the context
329 (if gtags-read-only (find-file-read-only file) (find-file file))
331 (use-local-map gtags-mode-map))))
333 ;; make complete list
334 (defun make-gtags-complete-list ()
335 ;; "Make tag name list for completion."
338 (setq gtags-complete-list (make-vector 63 0))
339 (set-buffer (generate-new-buffer "*Completions*"))
340 (call-process "global" nil t nil "-c")
341 (goto-char (point-min))
342 (while (looking-at symbol-regexp)
343 (intern (util-match-string 0) gtags-complete-list)
345 (kill-buffer (current-buffer))))
349 "Minor mode for browsing C source using GLOBAL."
351 (if (y-or-n-p "Do you use function name completion?")
352 (make-gtags-complete-list))
353 (use-local-map gtags-mode-map)
354 (run-hooks 'gtags-mode-hook))
356 ;; make gtags select mode
357 (defun gtags-select-mode ()
358 "Major mode for choosing a tag from tags list."
359 (setq buffer-read-only t
360 major-mode 'gtags-select-mode
361 mode-name "Gtags Select")
362 (use-local-map gtags-select-mode-map)
363 (setq truncate-lines t)
364 (goto-char (point-min))
365 (message "[GTAGS SELECT MODE] %d lines" (count-lines (point-min) (point-max)))
366 (run-hooks 'gtags-select-mode-hook))
368 ;;; gtags.el ends here