Mercurial > hg > xemacs-beta
comparison lisp/etags.el @ 223:2c611d1463a6 r20-4b10
Import from CVS: tag r20-4b10
author | cvs |
---|---|
date | Mon, 13 Aug 2007 10:10:54 +0200 |
parents | 262b8bb4a523 |
children | 12579d965149 |
comparison
equal
deleted
inserted
replaced
222:aae4c8b01452 | 223:2c611d1463a6 |
---|---|
1 ;;; etags.el --- etags facility for Emacs | 1 ;;; etags.el --- etags facility for Emacs |
2 | 2 |
3 ;; Copyright 1985, 1986, 1988, 1990 Free Software Foundation, Inc. | 3 ;; Copyright 1985, 1986, 1988, 1990, 1997 Free Software Foundation, Inc. |
4 | 4 |
5 ;; Author: Their Name is Legion (see list below) | |
6 ;; Maintainer: XEmacs Development Team | |
5 ;; Keywords: tools | 7 ;; Keywords: tools |
6 | 8 |
7 ;; This file is part of XEmacs. | 9 ;; This file is part of XEmacs. |
8 | 10 |
9 ;; GNU Emacs is distributed in the hope that it will be useful, | 11 ;; XEmacs is free software; you can redistribute it and/or modify it |
10 ;; but WITHOUT ANY WARRANTY. No author or distributor | 12 ;; under the terms of the GNU General Public License as published by |
11 ;; accepts responsibility to anyone for the consequences of using it | 13 ;; the Free Software Foundation; either version 2, or (at your option) |
12 ;; or for whether it serves any particular purpose or works at all, | 14 ;; any later version. |
13 ;; unless he says so in writing. Refer to the GNU Emacs General Public | 15 |
14 ;; License for full details. | 16 ;; XEmacs is distributed in the hope that it will be useful, but |
15 | 17 ;; WITHOUT ANY WARRANTY; without even the implied warranty of |
16 ;; Everyone is granted permission to copy, modify and redistribute | 18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
17 ;; GNU Emacs, but only under the conditions described in the | 19 ;; General Public License for more details. |
18 ;; GNU Emacs General Public License. A copy of this license is | 20 |
19 ;; supposed to have been given to you along with GNU Emacs so you | 21 ;; You should have received a copy of the GNU General Public License |
20 ;; can know your rights and responsibilities. It should be in a | 22 ;; along with XEmacs; see the file COPYING. If not, write to the |
21 ;; file named COPYING. Among other things, the copyright notice | 23 ;; Free Software Foundation, 59 Temple Place - Suite 330, |
22 ;; and this notice must be preserved on all copies. | 24 ;; Boston, MA 02111-1307, USA. |
23 | 25 |
24 ;;; Synched up with: Not synched with FSF. (This file is almost | 26 ;;; Synched up with: Not synched with FSF. |
25 ;;; completely different from FSF's etags.el. It appears that an | 27 |
26 ;;; early version of this file (tags.el) was rewritten by two | 28 ;;; Commentary: |
27 ;;; different people; we got one, FSF got the other. Various | 29 |
28 ;;; people have said that our version is better and faster. | 30 ;; This file is completely different from FSF's etags.el. It appears |
29 | 31 ;; that an early version of this file (tags.el) has been rewritten by |
32 ;; two different people; we got one, FSF got the other. Various | |
33 ;; people have said that our version is better and faster. | |
30 | 34 |
31 ;; TODO: | 35 ;; TODO: |
32 ;; 1. place cursor in echo area while searching | 36 ;; - DOCUMENT! |
33 ;; 2. document! | |
34 ;; 3. determine semantics of interactively setting the tags file for a buffer | |
35 | |
36 ;; Comments with **** mean something is left to be done. | |
37 | 37 |
38 ;; Derived from the original lisp/tags.el. | 38 ;; Derived from the original lisp/tags.el. |
39 | 39 |
40 ;; Ideas and code from the work of the following people: | 40 ;; Ideas and code from the work of the following people: |
41 ;; Andy Norman <ange@hplb.hpl.hp.com>, author of ange-tags.el | 41 ;; Andy Norman <ange@hplb.hpl.hp.com>, author of ange-tags.el |
50 ;; Shinichirou Sugou <shin@sgtp.apple.juice.or.jp> | 50 ;; Shinichirou Sugou <shin@sgtp.apple.juice.or.jp> |
51 ;; an unidentified anonymous elisp hacker | 51 ;; an unidentified anonymous elisp hacker |
52 ;; Kyle Jones <kyle_jones@wonderworks.com> | 52 ;; Kyle Jones <kyle_jones@wonderworks.com> |
53 ;; added "Exact match, then inexact" code | 53 ;; added "Exact match, then inexact" code |
54 ;; added support for include directive. | 54 ;; added support for include directive. |
55 ;; Hrvoje Niksic <hniksic@srce.hr> | |
56 ;; various changes. | |
55 | 57 |
56 | 58 |
57 ;; Auxiliary functions | 59 ;;; User variables. |
58 | |
59 (defun tags-delete (item list) | |
60 "Delete the item from the list, testing with equal. Copies the list." | |
61 (delete item (copy-list list))) | |
62 | |
63 (defun tags-remove-duplicates (list) | |
64 "Delete equal duplicates from the list; copies the list." | |
65 (let (res) | |
66 (dolist (el list) | |
67 (unless (member el res) | |
68 (push el res))) | |
69 (nreverse res))) | |
70 | |
71 | |
72 ;; Tag tables for a buffer | |
73 | 60 |
74 (defgroup etags nil | 61 (defgroup etags nil |
75 "Etags facility for Emacs" | 62 "Etags facility for Emacs. |
63 Using etags, you can create tag tables for any number of files, and | |
64 easily access the symbols in those files, using the `\\[find-tag]' | |
65 command." | |
76 :prefix "tags-" | 66 :prefix "tags-" |
77 :group 'tools) | 67 :group 'tools) |
78 | 68 |
79 | 69 |
80 ;;;###autoload | |
81 (defcustom tags-build-completion-table 'ask | 70 (defcustom tags-build-completion-table 'ask |
82 "*If this variable is nil, then tags completion is disabled. | 71 "*If this variable is nil, then tags completion is disabled. |
83 If this variable is t, then things which prompt for tags will do so with | 72 If it is t, then things which prompt for tags will do so with completion |
84 completion across all known tags. | 73 across all known tags. |
85 If this variable is the symbol `ask', then you will be asked whether each | 74 If it is the symbol `ask', you will be asked whether each tags table |
86 tags table should be added to the completion list as it is read in. | 75 should be added to the completion list as it is read in. (With the |
87 (With the exception that for very small tags tables, you will not be asked, | 76 exception that for very small tags tables, you will not be asked, |
88 since they can be parsed quickly.)" | 77 since they can be parsed quickly.)" |
89 :type '(radio (const :tag "Disabled" nil) | 78 :type '(choice (const :tag "Disabled" nil) |
90 (const :tag "Complete All" t) | 79 (const :tag "Complete All" t) |
91 (const :tag "Ask" ask)) | 80 (const :tag "Ask" ask)) |
92 :group 'etags) | 81 :group 'etags) |
93 | 82 |
94 ;;;###autoload | |
95 (defcustom tags-always-exact nil | 83 (defcustom tags-always-exact nil |
96 "*If this variable is non-nil, then tags always looks for exact matches." | 84 "*If this variable is non-nil, then tags always looks for exact matches. |
85 If it is nil (the default), tags will first go through exact matches, | |
86 then through the non-exact ones." | |
97 :type 'boolean | 87 :type 'boolean |
98 :group 'etags) | 88 :group 'etags) |
99 | 89 |
100 ;;;###autoload | |
101 (defcustom tag-table-alist nil | 90 (defcustom tag-table-alist nil |
102 "*A list which determines which tags files are active for a buffer. | 91 "*A list which determines which tags files are active for a buffer. |
103 This is not really an association list, in that all elements are | 92 This is not really an association list, in that all elements are |
104 checked. The CAR of each element of this list is a pattern against | 93 checked. The CAR of each element of this list is a pattern against |
105 which the buffer's file name is compared; if it matches, then the CDR | 94 which the buffer's file name is compared; if it matches, then the CDR |
142 If there is a file called \"TAGS\" in the same directory as the file in | 131 If there is a file called \"TAGS\" in the same directory as the file in |
143 question, then that tags file will always be used as well (after the | 132 question, then that tags file will always be used as well (after the |
144 `buffer-tag-table' but before the tables specified by this list.) | 133 `buffer-tag-table' but before the tables specified by this list.) |
145 | 134 |
146 If the variable tags-file-name is set, then the tags file it names will apply | 135 If the variable tags-file-name is set, then the tags file it names will apply |
147 to all buffers (for backwards compatibility.) It is searched first. | 136 to all buffers (for backwards compatibility.) It is searched first." |
148 " | 137 :type '(repeat (cons :format "%v" |
149 :type '(repeat (cons (choice :value "" | 138 (choice :value "" |
150 (regexp :tag "Buffer regexp") | 139 (regexp :tag "Buffer regexp") |
151 (function :tag "Expression")) | 140 sexp) |
152 (string :tag "Tag file or directory"))) | 141 (choice :value "" |
142 (string :tag "Tag file or directory") | |
143 sexp))) | |
153 :group 'etags) | 144 :group 'etags) |
154 | 145 |
155 (defvar buffer-tag-table nil | 146 (defvar buffer-tag-table nil |
156 "*The additional name of one TAGS table to be used for this buffer. | 147 "*The additional name of one TAGS table to be used for this buffer. |
157 You can set this with meta-x set-buffer-tag-table. See the documentation | 148 You can set this with `\\[set-buffer-tag-table]'. See the documentation |
158 for the variable `tag-table-alist' for more information.") | 149 for the variable `tag-table-alist' for more information.") |
159 (make-variable-buffer-local 'buffer-tag-table) | 150 (make-variable-buffer-local 'buffer-tag-table) |
160 | 151 |
161 (defvar tags-file-name nil | 152 (defvar tags-file-name nil |
162 "The name of the tags-table used by all buffers. | 153 "The name of the tags-table used by all buffers. |
163 This is for backwards compatibility, and is largely supplanted by the | 154 This is for backwards compatibility, and is largely supplanted by the |
164 variable tag-table-alist.") | 155 variable tag-table-alist.") |
165 | 156 |
166 | |
167 ;; XEmacs change: added tags-auto-read-changed-tag-files | |
168 (defcustom tags-auto-read-changed-tag-files nil | 157 (defcustom tags-auto-read-changed-tag-files nil |
169 "*If non-nil, always re-read changed TAGS file without prompting, if nil | 158 "*If non-nil, always re-read changed TAGS file without prompting. |
170 then prompt if changed TAGS file should be re-read." | 159 If nil, prompt whether to re-read the changed TAGS file." |
171 :type 'boolean | 160 :type 'boolean |
172 :group 'etags) | 161 :group 'etags) |
162 | |
163 (defcustom make-tags-files-invisible nil | |
164 "*If non-nil, TAGS-files will not show up in buffer-lists or be | |
165 selectable (or deletable.)" | |
166 :type 'boolean | |
167 :group 'etags) | |
168 | |
169 (defcustom tags-search-nuke-uninteresting-buffers t | |
170 "*If non-nil, keep newly-visited files if they contain the search target. | |
171 This affects the `tags-search' and `tags-query-replace' commands." | |
172 :type 'boolean | |
173 :group 'etags) | |
174 | |
175 | |
176 ;; Auxiliary functions | |
177 | |
178 (defun tags-remove-duplicates (list) | |
179 "Delete equal duplicates from the list; copies the list." | |
180 (let (res) | |
181 (dolist (el list) | |
182 (unless (member el res) | |
183 (push el res))) | |
184 (nreverse res))) | |
185 | |
186 | |
187 ;; Buffer tag tables. | |
173 | 188 |
174 (defun buffer-tag-table-list () | 189 (defun buffer-tag-table-list () |
175 "Returns a list (ordered) of the tags tables which should be used for | 190 "Returns a list (ordered) of the tags tables which should be used for |
176 the current buffer." | 191 the current buffer." |
177 (let (result) | 192 (let (result) |
193 ;; Explicitly set buffer-tag-table | |
178 (when buffer-tag-table | 194 (when buffer-tag-table |
179 (push buffer-tag-table result)) | 195 (push buffer-tag-table result)) |
180 ;; Current directory | 196 ;; Current directory |
181 (when (file-readable-p (concat default-directory "TAGS")) | 197 (when (file-readable-p (concat default-directory "TAGS")) |
182 (push (concat default-directory "TAGS") result)) | 198 (push (concat default-directory "TAGS") result)) |
214 ;; get-tag-table-buffer has side-effects | 230 ;; get-tag-table-buffer has side-effects |
215 (symbol-value-in-buffer 'buffer-file-name | 231 (symbol-value-in-buffer 'buffer-file-name |
216 (get-tag-table-buffer name)))) | 232 (get-tag-table-buffer name)))) |
217 result)) | 233 result)) |
218 (setq result (delq nil result)) | 234 (setq result (delq nil result)) |
235 ;; If no TAGS file has been found, ask the user explicitly. | |
219 ;; #### tags-file-name is *evil*. | 236 ;; #### tags-file-name is *evil*. |
220 (or result tags-file-name | 237 (or result tags-file-name |
221 (call-interactively 'visit-tags-table)) | 238 (call-interactively 'visit-tags-table)) |
222 (when tags-file-name | 239 (when tags-file-name |
223 (setq result (nconc result (list tags-file-name)))) | 240 (setq result (nconc result (list tags-file-name)))) |
239 (when (file-directory-p file) | 256 (when (file-directory-p file) |
240 (setq file (expand-file-name "TAGS" file))) | 257 (setq file (expand-file-name "TAGS" file))) |
241 ;; It used to be that, if a user pressed RET by mistake, the bogus | 258 ;; It used to be that, if a user pressed RET by mistake, the bogus |
242 ;; `tags-file-name' would remain, causing the error at | 259 ;; `tags-file-name' would remain, causing the error at |
243 ;; `buffer-tag-table'. | 260 ;; `buffer-tag-table'. |
244 (when (file-readable-p file) | 261 (when (file-exists-p file) |
245 (setq tags-file-name file)))) | 262 (setq tags-file-name file)))) |
246 | 263 |
247 (defun set-buffer-tag-table (file) | 264 (defun set-buffer-tag-table (file) |
248 "In addition to the tags tables specified by the variable `tag-table-alist', | 265 "In addition to the tags tables specified by the variable `tag-table-alist', |
249 each buffer can have one additional table. This command sets that. | 266 each buffer can have one additional table. This command sets that. |
253 (read-file-name "Visit tags table: (directory sufficient) " | 270 (read-file-name "Visit tags table: (directory sufficient) " |
254 nil default-directory t))) | 271 nil default-directory t))) |
255 (or file (error "No TAGS file name supplied")) | 272 (or file (error "No TAGS file name supplied")) |
256 (setq file (expand-file-name file)) | 273 (setq file (expand-file-name file)) |
257 (when (file-directory-p file) | 274 (when (file-directory-p file) |
258 (setq file (concat file "TAGS"))) | 275 (setq file (expand-file-name "TAGS" file))) |
259 (or (file-exists-p file) (error "TAGS file missing: %s" file)) | 276 (or (file-exists-p file) (error "TAGS file missing: %s" file)) |
260 (setq buffer-tag-table file)) | 277 (setq buffer-tag-table file)) |
261 | 278 |
262 | 279 |
263 ;; Manipulating the tag table buffer | 280 ;; Manipulating the tag table buffer |
264 | 281 |
265 (defconst tag-table-completion-status nil | 282 (defconst tag-table-completion-status nil |
266 "Indicates whether a completion table has been built, or has explicitly not | 283 "Indicates whether a completion table has been built. |
267 been built. this is nil, t, or 'disabled.") | 284 Either nil, t, or `disabled'.") |
268 (make-variable-buffer-local 'tag-table-completion-status) | 285 (make-variable-buffer-local 'tag-table-completion-status) |
269 | |
270 (defcustom make-tags-files-invisible nil | |
271 "*If non-nil, TAGS-files will not show up in buffer-lists or be | |
272 selectable (or deletable.)" | |
273 :type 'boolean | |
274 :group 'etags) | |
275 | 286 |
276 (defconst tag-table-files nil | 287 (defconst tag-table-files nil |
277 "If the current buffer is a TAGS table, this holds a list of the files | 288 "If the current buffer is a TAGS table, this holds a list of the files |
278 referenced by this file, or nil if that hasn't been computed yet.") | 289 referenced by this file, or nil if that hasn't been computed yet.") |
279 (make-variable-buffer-local 'tag-table-files) | 290 (make-variable-buffer-local 'tag-table-files) |
280 | 291 |
281 (defun get-tag-table-buffer (tag-table) | 292 (defun get-tag-table-buffer (tag-table) |
282 "Returns a buffer visiting the given TAGS table, reverting if appropriate, | 293 "Returns a buffer visiting the given TAGS table. |
283 and possibly building a completion-table." | 294 If appropriate, reverting the buffer, and possibly build a completion-table." |
284 (or (stringp tag-table) | 295 (or (stringp tag-table) |
285 (error "Bad tags file name supplied: %s" tag-table)) | 296 (error "Bad tags file name supplied: %s" tag-table)) |
286 ;; add support for removing symbolic links from name | 297 ;; Remove symbolic links from name. |
287 (if (fboundp 'symlink-expand-file-name) | 298 (setq tag-table (symlink-expand-file-name tag-table)) |
288 (setq tag-table (symlink-expand-file-name tag-table))) | |
289 (let (buf build-completion check-name) | 299 (let (buf build-completion check-name) |
290 (setq buf (get-file-buffer tag-table)) | 300 (setq buf (get-file-buffer tag-table)) |
291 (or buf | 301 (unless buf |
292 (if (file-readable-p tag-table) | 302 (if (file-readable-p tag-table) |
293 (setq buf (find-file-noselect tag-table) | 303 (setq buf (find-file-noselect tag-table) |
294 check-name t) | 304 check-name t) |
295 (error "No such tags file: %s" tag-table))) | 305 (error "No such tags file: %s" tag-table))) |
296 (with-current-buffer buf | 306 (with-current-buffer buf |
297 ;; make the TAGS buffer invisible | 307 ;; Make the TAGS buffer invisible. |
298 (when (and check-name | 308 (when (and check-name |
299 make-tags-files-invisible | 309 make-tags-files-invisible |
300 (string-match "\\`[^ ]" (buffer-name))) | 310 (string-match "\\`[^ ]" (buffer-name))) |
301 (rename-buffer (generate-new-buffer-name | 311 (rename-buffer (generate-new-buffer-name |
302 (concat " " (buffer-name))))) | 312 (concat " " (buffer-name))))) |
303 (or (verify-visited-file-modtime buf) | 313 (or (verify-visited-file-modtime buf) |
304 ;; XEmacs change: added tags-auto-read-changed-tag-files | 314 (cond ((or tags-auto-read-changed-tag-files |
305 (cond ((or tags-auto-read-changed-tag-files (yes-or-no-p | 315 (yes-or-no-p |
306 (format "Tags file %s has changed, read new contents? " | 316 (format "Tags file %s has changed, read new contents? " |
307 tag-table))) | 317 tag-table))) |
308 (when tags-auto-read-changed-tag-files | 318 (when tags-auto-read-changed-tag-files |
309 (message "Tags file %s has changed, reading new contents..." | 319 (message "Tags file %s has changed, reading new contents..." |
310 tag-table)) | 320 tag-table)) |
311 (revert-buffer t t) | 321 (revert-buffer t t) |
312 (if (eq tag-table-completion-status t) | 322 (when (eq tag-table-completion-status t) |
313 (setq tag-table-completion-status nil)) | 323 (setq tag-table-completion-status nil)) |
314 (setq tag-table-files nil)))) | 324 (setq tag-table-files nil)))) |
315 (or (eq (char-after 1) ?\f) | 325 (or (eq (char-after 1) ?\f) |
316 (error "File %s not a valid tags file" tag-table)) | 326 (error "File %s not a valid tags file" tag-table)) |
317 (or (memq tag-table-completion-status '(t disabled)) | 327 (or (memq tag-table-completion-status '(t disabled)) |
318 (setq build-completion t)) | 328 (setq build-completion t)) |
319 (and build-completion | 329 (when build-completion |
320 (if (cond | 330 (if (ecase tags-build-completion-table |
321 ((eq tags-build-completion-table nil) | 331 (nil nil) |
322 nil) | 332 (t t) |
323 ((eq tags-build-completion-table t) | 333 (ask |
324 t) | 334 ;; don't bother asking for small ones |
325 ((eq tags-build-completion-table 'ask) | 335 (or (< (buffer-size) 20000) |
326 ;; don't bother asking for small ones | 336 (y-or-n-p |
327 (or (< (buffer-size) 20000) | 337 (format "Build tag completion table for %s? " |
328 (y-or-n-p | 338 tag-table))))) |
329 (format "Build tag completion table for %s? " | 339 ;; The user wants to build the table: |
330 tag-table)))) | 340 (condition-case nil |
331 (t (error | 341 (progn |
332 "tags-build-completion-table is not t, nil, or ask."))) | 342 (add-to-tag-completion-table) |
333 (condition-case nil | 343 (setq tag-table-completion-status t)) |
334 (progn | 344 ;; Allow user to C-g out correctly |
335 (add-to-tag-completion-table) | 345 (quit |
336 (setq tag-table-completion-status t)) | 346 (message "Tags completion table construction aborted") |
337 ;; Allow user to C-g out correctly | 347 (setq tag-table-completion-status nil |
338 (quit | 348 quit-flag t) |
339 (setq tag-table-completion-status nil) | 349 t)) |
340 (setq quit-flag t) | 350 ;; The table is verboten. |
341 (eval t))) | 351 (setq tag-table-completion-status 'disabled)))) |
342 (setq tag-table-completion-status 'disabled)))) | |
343 buf)) | 352 buf)) |
344 | 353 |
345 (defun file-of-tag () | 354 (defun file-of-tag () |
346 "Return the file name of the file whose tags point is within. | 355 "Return the file name of the file whose tags point is within. |
347 Assumes the tag table is the current buffer. | 356 Assumes the tag table is the current buffer. |
348 File name returned is relative to tag table file's directory." | 357 File name returned is relative to tag table file's directory." |
349 (let ((opoint (point)) | 358 (let ((opoint (point)) |
350 prev size) | 359 prev size) |
351 (save-excursion | 360 (save-excursion |
352 (goto-char (point-min)) | 361 (goto-char (point-min)) |
353 (while (< (point) opoint) | 362 (while (< (point) opoint) |
354 (forward-line 1) | 363 (forward-line 1) |
355 (end-of-line) | 364 (end-of-line) |
356 (skip-chars-backward "^,\n") | 365 (skip-chars-backward "^,\n") |
357 (setq prev (point) | 366 (setq prev (point) |
358 size (read (current-buffer))) | 367 size (read (current-buffer))) |
359 (goto-char prev) | 368 (goto-char prev) |
360 (forward-line 1) | 369 (forward-line 1) |
361 ;; New include syntax | 370 ;; New include syntax |
362 ;; filename,include | 371 ;; filename,include |
363 ;; tacked on to the end of a tag file means use filename | 372 ;; tacked on to the end of a tag file means use filename |
364 ;; as a tag file before giving up. | 373 ;; as a tag file before giving up. |
365 ;; Skip it here. | 374 ;; Skip it here. |
366 (if (not (eq size 'include)) | 375 (unless (eq size 'include) |
367 (forward-char size))) | 376 (forward-char size))) |
368 (goto-char (1- prev)) | 377 (goto-char (1- prev)) |
369 (buffer-substring (point) (point-at-bol))))) | 378 (buffer-substring (point) (point-at-bol))))) |
370 | 379 |
371 (defun tag-table-include-files () | 380 (defun tag-table-include-files () |
372 "Return all file names associated with `include' directives in a tag buffer." | 381 "Return all file names associated with `include' directives in a tag buffer." |
373 ;; New include syntax | 382 ;; New include syntax |
374 ;; filename,include | 383 ;; filename,include |
375 ;; tacked on to the end of a tag file means use filename as a | 384 ;; tacked on to the end of a tag file means use filename as a |
376 ;; tag file before giving up. | 385 ;; tag file before giving up. |
377 (let ((files nil)) | 386 (let ((files nil)) |
378 (save-excursion | 387 (save-excursion |
379 (goto-char (point-min)) | 388 (goto-char (point-min)) |
380 (while (re-search-forward "\f\n\\(.*\\),include$" nil t) | 389 (while (re-search-forward "\f\n\\(.*\\),include$" nil t) |
381 (setq files (cons (match-string 1) files)))) | 390 (push (match-string 1) files))) |
382 files )) | 391 files)) |
383 | 392 |
384 (defun tag-table-files (tag-table) | 393 (defun tag-table-files (tag-table) |
385 "Returns a list of the files referenced by the named TAGS table." | 394 "Returns a list of the files referenced by the named TAGS table." |
386 (with-current-buffer (get-tag-table-buffer tag-table) | 395 (with-current-buffer (get-tag-table-buffer tag-table) |
387 (or tag-table-files | 396 (unless tag-table-files |
388 (let (files prev size) | 397 (let (files prev size) |
389 (goto-char (point-min)) | 398 (goto-char (point-min)) |
390 (while (not (eobp)) | 399 (while (not (eobp)) |
391 (forward-line 1) | 400 (forward-line 1) |
392 (end-of-line) | 401 (end-of-line) |
393 (skip-chars-backward "^,\n") | 402 (skip-chars-backward "^,\n") |
394 (setq prev (point) | 403 (setq prev (point) |
395 size (read (current-buffer))) | 404 size (read (current-buffer))) |
396 (goto-char prev) | 405 (goto-char prev) |
397 (push (expand-file-name (buffer-substring (1- (point)) | 406 (push (expand-file-name (buffer-substring (1- (point)) |
398 (point-at-bol)) | 407 (point-at-bol)) |
399 default-directory) | 408 default-directory) |
400 files) | 409 files) |
401 (forward-line 1) | 410 (forward-line 1) |
402 (forward-char size)) | 411 (forward-char size)) |
403 (setq tag-table-files (nreverse files)))) | 412 (setq tag-table-files (nreverse files)))) |
404 tag-table-files)) | 413 tag-table-files)) |
405 | 414 |
406 ;; **** should this be on previous page? | 415 ;; #### should this be on previous page? |
407 (defun buffer-tag-table-files () | 416 (defun buffer-tag-table-files () |
408 "Returns a list of all files referenced by all TAGS tables that | 417 "Returns a list of all files referenced by all TAGS tables that |
409 this buffer uses." | 418 this buffer uses." |
410 (apply #'nconc | 419 (apply #'nconc |
411 (mapcar #'tag-table-files (buffer-tag-table-list)))) | 420 (mapcar #'tag-table-files (buffer-tag-table-list)))) |
474 ;; "\\(.*[ \t]+\\)?\\(\\(\\sw\\|\\s_\\)+\\)[ ()]*\C-?" | 483 ;; "\\(.*[ \t]+\\)?\\(\\(\\sw\\|\\s_\\)+\\)[ ()]*\C-?" |
475 ;; "\\(\\sw\\|\\s_\\)+[ ()]*\C-?" | 484 ;; "\\(\\sw\\|\\s_\\)+[ ()]*\C-?" |
476 ) | 485 ) |
477 (defconst tags-file-pattern "^\f\n\\(.+\\),[0-9]+\n") | 486 (defconst tags-file-pattern "^\f\n\\(.+\\),[0-9]+\n") |
478 | 487 |
488 ;; #### Should make it work with the `include' directive! | |
479 (defun add-to-tag-completion-table () | 489 (defun add-to-tag-completion-table () |
480 "Sucks the current buffer (a TAGS table) into the completion-table." | 490 "Sucks the current buffer (a TAGS table) into the completion-table." |
481 (message "Adding %s to tags completion table..." | 491 (message "Adding %s to tags completion table..." buffer-file-name) |
482 buffer-file-name) | |
483 (goto-char (point-min)) | 492 (goto-char (point-min)) |
484 (let ((tag-table-symbol (intern buffer-file-name tag-completion-table)) | 493 (let ((tag-table-symbol (intern buffer-file-name tag-completion-table)) |
485 ;; tag-table-symbol is used by intern-tag-symbol | 494 ;; tag-table-symbol is used by intern-tag-symbol |
486 filename file-type name name2 tag-symbol | 495 filename file-type name name2 tag-symbol |
487 tag-symbol-tables | 496 tag-symbol-tables |
488 (case-fold-search nil)) | 497 (case-fold-search nil)) |
489 ;; loop over the files mentioned in the TAGS file | 498 ;; Loop over the files mentioned in the TAGS file for each file, |
490 ;; for each file, try to find its major-mode, | 499 ;; try to find its major-mode, then process tags appropriately. |
491 ;; then process tags appropriately | |
492 (while (looking-at tags-file-pattern) | 500 (while (looking-at tags-file-pattern) |
493 (goto-char (match-end 0)) | 501 (goto-char (match-end 0)) |
494 (setq filename (file-name-sans-versions | 502 (setq filename (file-name-sans-versions (match-string 1)) |
495 (buffer-substring (match-beginning 1) | 503 ;; We used to check auto-mode-alist for the proper |
496 (match-end 1))) | 504 ;; file-type. This was way too slow, as it had to process |
497 ;; Old code used to check auto-mode-alist for the proper | 505 ;; an enormous amount of regexps for each time. Now we |
498 ;; file-type. This is too slow, as it breaks the | 506 ;; use the shotgun approach with only two regexps. |
499 ;; compiled-regexp caching, and slows the whole thing | |
500 ;; down. We'll use the shotgun approach with only two | |
501 ;; regexps. | |
502 file-type (cond ((string-match "\\.\\([cC]\\|cc\\|cxx\\)\\'" | 507 file-type (cond ((string-match "\\.\\([cC]\\|cc\\|cxx\\)\\'" |
503 filename) | 508 filename) |
504 'c-mode) | 509 'c-mode) |
505 ((string-match "\\.\\(el\\|cl\\|lisp\\)\\'" | 510 ((string-match "\\.\\(el\\|cl\\|lisp\\)\\'" |
506 filename) | 511 filename) |
507 'lisp-mode) | 512 'lisp-mode) |
508 ((string-match "\\.scm\\'" filename) | 513 ((string-match "\\.scm\\'" filename) |
509 'scheme-mode) | 514 'scheme-mode) |
510 (t nil))) | 515 (t nil))) |
511 (cond ((and (eq file-type 'c-mode) | 516 (set-syntax-table (cond ((and (eq file-type 'c-mode) |
512 c-mode-syntax-table) | 517 c-mode-syntax-table) |
513 (set-syntax-table c-mode-syntax-table)) | 518 c-mode-syntax-table) |
514 ((eq file-type 'lisp-mode) | 519 ((eq file-type 'lisp-mode) |
515 (set-syntax-table lisp-mode-syntax-table)) | 520 lisp-mode-syntax-table) |
516 (t | 521 (t (standard-syntax-table)))) |
517 (set-syntax-table (standard-syntax-table)))) | 522 ;; Clear loop variables. |
518 ;; clear loop variables | |
519 (setq name nil name2 nil) | 523 (setq name nil name2 nil) |
520 (message "%s..." filename) | 524 (lmessage 'progress "%s..." filename) |
521 ;; loop over the individual tag lines | 525 ;; Loop over the individual tag lines. |
522 (while (not (or (eobp) (eq (following-char) ?\f))) | 526 (while (not (or (eobp) (eq (char-after) ?\f))) |
523 (cond ((and (eq file-type 'c-mode) | 527 (cond ((and (eq file-type 'c-mode) |
524 (looking-at "DEFUN[ \t]")) | 528 (looking-at "DEFUN[ \t]")) |
529 ;; DEFUN | |
525 (or (looking-at tags-DEFUN-pattern) | 530 (or (looking-at tags-DEFUN-pattern) |
526 (error "DEFUN doesn't fit pattern")) | 531 (error "DEFUN doesn't fit pattern")) |
527 (setq name (buffer-substring (match-beginning 1) | 532 (setq name (match-string 1) |
528 (match-end 1)) | 533 name2 (match-string 2))) |
529 name2 (buffer-substring (match-beginning 2) | 534 ;;((looking-at "\\s ") |
530 (match-end 2)))) | 535 ;; skip probably bogus entry: |
531 ;;; ((looking-at "\\s ") | 536 ;;) |
532 ;;; ;; skip probably bogus entry: | |
533 ;;; ) | |
534 ((and (eq file-type 'c-mode) | 537 ((and (eq file-type 'c-mode) |
535 (looking-at ".*\\[")) | 538 (looking-at ".*\\[")) |
539 ;; Array | |
536 (cond ((not (looking-at tags-array-pattern)) | 540 (cond ((not (looking-at tags-array-pattern)) |
537 (message "array definition doesn't fit pattern") | 541 (message "array definition doesn't fit pattern") |
538 (setq name nil)) | 542 (setq name nil)) |
539 (t | 543 (t |
540 (setq name (buffer-substring (match-beginning 1) | 544 (setq name (match-string 1))))) |
541 (match-end 1)))))) | |
542 ((and (eq file-type 'scheme-mode) | 545 ((and (eq file-type 'scheme-mode) |
543 (looking-at "\\s-*(\\s-*def\\sw*\\s-*(?\\s-*\\(\\(\\sw\\|\\s_\\|:\\)+\\))?\\s-*\C-?")) | 546 (looking-at "\\s-*(\\s-*def\\sw*\\s-*(?\\s-*\\(\\(\\sw\\|\\s_\\|:\\)+\\))?\\s-*\C-?")) |
544 (setq name (buffer-substring (match-beginning 1) | 547 ;; Something Schemish (is this really necessary??) |
545 (match-end 1)))) | 548 (setq name (match-string 1))) |
546 ((looking-at tags-def-pattern) | 549 ((looking-at tags-def-pattern) |
547 (setq name (buffer-substring (match-beginning 2) | 550 ;; ??? |
548 (match-end 2))))) | 551 (setq name (match-string 2)))) |
549 ;; add the tags we found to the completion table | 552 ;; add the tags we found to the completion table |
550 (and name (intern-tag-symbol name)) | 553 (and name (intern-tag-symbol name)) |
551 (and name2 (intern-tag-symbol name2)) | 554 (and name2 (intern-tag-symbol name2)) |
552 (forward-line 1))) | 555 (forward-line 1))) |
553 (or (eobp) (error "Bad TAGS file"))) | 556 (or (eobp) (error "Bad TAGS file"))) |
554 (message "Adding %s to tags completion table...done" | 557 (message "Adding %s to tags completion table...done" buffer-file-name)) |
555 buffer-file-name)) | |
556 | 558 |
557 | 559 |
558 ;; Interactive find-tag | 560 ;; Interactive find-tag |
559 | 561 |
560 (defvar find-tag-default-hook nil | 562 (defvar find-tag-default-hook nil |
593 (defun buffer-tag-table-symbol-list () | 595 (defun buffer-tag-table-symbol-list () |
594 (mapcar (lambda (table-name) | 596 (mapcar (lambda (table-name) |
595 (intern table-name tag-completion-table)) | 597 (intern table-name tag-completion-table)) |
596 (buffer-tag-table-list))) | 598 (buffer-tag-table-list))) |
597 | 599 |
598 (defvar find-tag-history nil "History list for find-tag-tag") | 600 (defvar find-tag-history nil "History list for find-tag-tag.") |
599 | 601 |
600 (defun find-tag-tag (prompt) | 602 (defun find-tag-tag (prompt) |
601 (let* ((default (find-tag-default)) | 603 (let* ((default (find-tag-default)) |
602 (buffer-tag-table-list (buffer-tag-table-symbol-list)) | 604 (buffer-tag-table-list (buffer-tag-table-symbol-list)) |
603 tag-symbol-tables tag-name) | 605 tag-symbol-tables tag-name) |
639 (exact-syntax-table (get-symbol-syntax-table (syntax-table))) | 641 (exact-syntax-table (get-symbol-syntax-table (syntax-table))) |
640 tag-table-currently-matching-exact | 642 tag-table-currently-matching-exact |
641 tag-target exact-tagname | 643 tag-target exact-tagname |
642 tag-tables tag-table-point file linebeg startpos buf | 644 tag-tables tag-table-point file linebeg startpos buf |
643 offset found pat syn-tab) | 645 offset found pat syn-tab) |
644 (if (consp tagname) (setq tagname (car tagname))) | 646 (when (consp tagname) |
647 (setq tagname (car tagname))) | |
645 (cond (next | 648 (cond (next |
646 (setq tagname (car last-tag-data)) | 649 (setq tagname (car last-tag-data)) |
647 (setq tag-table-currently-matching-exact | 650 (setq tag-table-currently-matching-exact |
648 (car (cdr (cdr last-tag-data))))) | 651 (car (cdr (cdr last-tag-data))))) |
649 (t | 652 (t |
652 (setq exact-tagname (concat "\\_" tagname "\\_")) | 655 (setq exact-tagname (concat "\\_" tagname "\\_")) |
653 (while (string-match "\\\\_" exact-tagname) | 656 (while (string-match "\\\\_" exact-tagname) |
654 (aset exact-tagname (1- (match-end 0)) ?b)) | 657 (aset exact-tagname (1- (match-end 0)) ?b)) |
655 (save-excursion | 658 (save-excursion |
656 (catch 'found | 659 (catch 'found |
657 ;; loop searching for exact matches and then inexact matches. | 660 ;; Loop searching for exact matches and then inexact matches. |
658 (while (not (eq tag-table-currently-matching-exact 'neither)) | 661 (while (not (eq tag-table-currently-matching-exact 'neither)) |
659 (cond (tmpnext | 662 (cond (tmpnext |
660 (setq tag-tables (cdr (cdr (cdr last-tag-data)))) | 663 (setq tag-tables (cdr (cdr (cdr last-tag-data))) |
661 (setq tag-table-point (car (cdr last-tag-data))) | 664 tag-table-point (car (cdr last-tag-data))) |
662 ;; start from the beginning of the table list | 665 ;; Start from the beginning of the table list on the |
663 ;; on the next iteration of the loop. | 666 ;; next iteration of the loop. |
664 (setq tmpnext nil)) | 667 (setq tmpnext nil)) |
665 (t | 668 (t |
666 (setq tag-tables (buffer-tag-table-list)) | 669 (setq tag-tables (buffer-tag-table-list) |
667 (setq tag-table-point 1))) | 670 tag-table-point 1))) |
668 (if tag-table-currently-matching-exact | 671 (if tag-table-currently-matching-exact |
669 (progn | 672 (setq tag-target exact-tagname |
670 (setq tag-target exact-tagname) | 673 syn-tab exact-syntax-table) |
671 (setq syn-tab exact-syntax-table)) | 674 (setq tag-target tagname |
672 (setq tag-target tagname) | 675 syn-tab normal-syntax-table)) |
673 (setq syn-tab normal-syntax-table)) | |
674 (with-caps-disable-folding tag-target | 676 (with-caps-disable-folding tag-target |
675 (while tag-tables | 677 (while tag-tables |
676 (set-buffer (get-tag-table-buffer (car tag-tables))) | 678 (set-buffer (get-tag-table-buffer (car tag-tables))) |
677 (bury-buffer (current-buffer)) | 679 (bury-buffer (current-buffer)) |
678 (goto-char (or tag-table-point (point-min))) | 680 (goto-char (or tag-table-point (point-min))) |
679 (setq tag-table-point nil) | 681 (setq tag-table-point nil) |
680 (let ((osyn (syntax-table)) | 682 (letf (((syntax-table) syn-tab) |
681 case-fold-search) | 683 (case-fold-search nil)) |
682 (unwind-protect | 684 ;; #### should there be support for non-regexp |
683 (progn | 685 ;; tag searches? |
684 (set-syntax-table syn-tab) | 686 (while (re-search-forward tag-target nil t) |
685 ;; **** should there be support for non-regexp | 687 (and (save-match-data |
686 ;; tag searches? | 688 (looking-at "[^\n\C-?]*\C-?")) |
687 (while (re-search-forward tag-target nil t) | 689 ;; If we're looking for inexact matches, skip |
688 (if (and (save-match-data | 690 ;; exact matches since we've visited them |
689 (looking-at "[^\n\C-?]*\C-?")) | 691 ;; already. |
690 ;; if we're looking for inexact | 692 (or tag-table-currently-matching-exact |
691 ;; matches, skip exact matches | 693 (letf (((syntax-table) exact-syntax-table)) |
692 ;; since we've visited them | 694 (save-excursion |
693 ;; already. | 695 (goto-char (match-beginning 0)) |
694 (or tag-table-currently-matching-exact | 696 (not (looking-at exact-tagname))))) |
695 (unwind-protect | 697 (throw 'found t)))) |
696 (save-excursion | |
697 (set-syntax-table | |
698 exact-syntax-table) | |
699 (goto-char (match-beginning 0)) | |
700 (not (looking-at exact-tagname))) | |
701 (set-syntax-table syn-tab)))) | |
702 (throw 'found t)))) | |
703 (set-syntax-table osyn))) | |
704 (setq tag-tables | 698 (setq tag-tables |
705 (nconc (tag-table-include-files) (cdr tag-tables))))) | 699 (nconc (tag-table-include-files) (cdr tag-tables))))) |
706 (if (and (not exact) (eq tag-table-currently-matching-exact t)) | 700 (if (and (not exact) (eq tag-table-currently-matching-exact t)) |
707 (setq tag-table-currently-matching-exact nil) | 701 (setq tag-table-currently-matching-exact nil) |
708 (setq tag-table-currently-matching-exact 'neither))) | 702 (setq tag-table-currently-matching-exact 'neither))) |
710 (if next "more " "") | 704 (if next "more " "") |
711 (if exact "matching" "containing") | 705 (if exact "matching" "containing") |
712 tagname)) | 706 tagname)) |
713 (search-forward "\C-?") | 707 (search-forward "\C-?") |
714 (setq file (expand-file-name (file-of-tag) | 708 (setq file (expand-file-name (file-of-tag) |
715 ;; XEmacs change: this needs to be | 709 ;; In XEmacs, this needs to be |
716 ;; relative to the | 710 ;; relative to: |
717 (or (file-name-directory (car tag-tables)) | 711 (or (file-name-directory (car tag-tables)) |
718 "./"))) | 712 "./"))) |
719 (setq linebeg (buffer-substring (1- (point)) (point-at-bol))) | 713 (setq linebeg (buffer-substring (1- (point)) (point-at-bol))) |
720 (search-forward ",") | 714 (search-forward ",") |
721 (setq startpos (read (current-buffer))) | 715 (setq startpos (read (current-buffer))) |
722 (setq last-tag-data | 716 (setq last-tag-data |
723 (nconc (list tagname (point) tag-table-currently-matching-exact) | 717 (nconc (list tagname (point) tag-table-currently-matching-exact) |
724 tag-tables)) | 718 tag-tables)) |
725 (setq buf (find-file-noselect file)) | 719 (setq buf (find-file-noselect file)) |
726 (with-current-buffer buf | 720 (with-current-buffer buf |
727 (save-excursion | 721 (save-excursion |
728 (save-restriction | 722 (save-restriction |
729 (widen) | 723 (widen) |
730 (setq offset 1000) | 724 ;; Here we search for PAT in the range [STARTPOS - OFFSET, |
731 (setq pat (concat "^" (regexp-quote linebeg))) | 725 ;; STARTPOS + OFFSET], with increasing values of OFFSET. |
732 (or startpos (setq startpos (point-min))) | 726 ;; |
733 (while (and (not found) | 727 ;; We used to set the initial offset to 1000, but the |
734 (progn | 728 ;; actual sources show that finer-grained control is |
735 (goto-char (- startpos offset)) | 729 ;; needed (e.g. two `hash_string's in src/symbols.c.) So, |
736 (not (bobp)))) | 730 ;; I changed 100 to 100, and (* 3 offset) to (* 5 offset). |
737 (setq found (re-search-forward pat (+ startpos offset) t)) | 731 (setq offset 100) |
738 (setq offset (* 3 offset))) | 732 (setq pat (concat "^" (regexp-quote linebeg))) |
739 (or found | 733 (or startpos (setq startpos (point-min))) |
740 (re-search-forward pat nil t) | 734 (while (and (not found) |
741 (error "%s not found in %s" pat file)) | 735 (progn |
742 (beginning-of-line) | 736 (goto-char (- startpos offset)) |
743 (setq startpos (point))))) | 737 (not (bobp)))) |
738 (setq found (re-search-forward pat (+ startpos offset) t)) | |
739 (setq offset (* 5 offset))) | |
740 ;; Finally, try finding it anywhere in the buffer. | |
741 (or found | |
742 (re-search-forward pat nil t) | |
743 (error "%s not found in %s" pat file)) | |
744 (beginning-of-line) | |
745 (setq startpos (point))))) | |
744 (cons buf startpos)))) | 746 (cons buf startpos)))) |
745 | 747 |
746 ;;;###autoload | 748 ;;;###autoload |
747 (defun find-tag (tagname &optional other-window) | 749 (defun find-tag (tagname &optional other-window) |
748 "*Find tag whose name contains TAGNAME. | 750 "*Find tag whose name contains TAGNAME. |
772 (let* ((local-find-tag-hook find-tag-hook) | 774 (let* ((local-find-tag-hook find-tag-hook) |
773 (next (null tagname)) | 775 (next (null tagname)) |
774 (result (find-tag-internal tagname)) | 776 (result (find-tag-internal tagname)) |
775 (tag-buf (car result)) | 777 (tag-buf (car result)) |
776 (tag-point (cdr result))) | 778 (tag-point (cdr result))) |
777 ;; push old position | 779 ;; Push old position on the tags mark stack. |
778 (if (or (not next) | 780 (if (or (not next) |
779 (not (memq last-command | 781 (not (memq last-command |
780 '(find-tag find-tag-other-window tags-loop-continue)))) | 782 '(find-tag find-tag-other-window tags-loop-continue)))) |
781 (push-tag-mark)) | 783 (push-tag-mark)) |
782 (if other-window | 784 (if other-window |
792 (setq tags-loop-scan (list 'find-tag nil nil) | 794 (setq tags-loop-scan (list 'find-tag nil nil) |
793 tags-loop-operate nil) | 795 tags-loop-operate nil) |
794 ;; Return t in case used as the tags-loop-scan. | 796 ;; Return t in case used as the tags-loop-scan. |
795 t) | 797 t) |
796 | 798 |
797 ;; This function is unchanged from lisp/tags.el: | |
798 ;;;###autoload | 799 ;;;###autoload |
799 (defun find-tag-other-window (tagname &optional next) | 800 (defun find-tag-other-window (tagname &optional next) |
800 "*Find tag whose name contains TAGNAME. | 801 "*Find tag whose name contains TAGNAME. |
801 Selects the buffer that the tag is contained in in another window | 802 Selects the buffer that the tag is contained in in another window |
802 and puts point at its definition. | 803 and puts point at its definition. |
823 (if next | 824 (if next |
824 (find-tag nil t) | 825 (find-tag nil t) |
825 (find-tag tagname t))) | 826 (find-tag tagname t))) |
826 | 827 |
827 | 828 |
828 ;; Completion on tags in the buffer | 829 ;; Completion on tags in the buffer. |
829 | 830 |
830 (defun complete-symbol (&optional table predicate prettify) | 831 (defun complete-symbol (&optional table predicate prettify) |
831 (let* ((end (point)) | 832 (let* ((end (point)) |
832 (beg (save-excursion | 833 (beg (save-excursion |
833 (backward-sexp 1) | 834 (backward-sexp 1) |
834 (while (= (char-syntax (following-char)) ?\') | 835 ;;(while (= (char-syntax (following-char)) ?\') |
835 (forward-char 1)) | 836 ;; (forward-char 1)) |
837 (skip-syntax-forward "'") | |
836 (point))) | 838 (point))) |
837 (pattern (buffer-substring beg end)) | 839 (pattern (buffer-substring beg end)) |
838 (table (or table obarray)) | 840 (table (or table obarray)) |
839 (completion (try-completion pattern table predicate))) | 841 (completion (try-completion pattern table predicate))) |
840 (cond ((eq completion t)) | 842 (cond ((eq completion t)) |
841 ((null completion) | 843 ((null completion) |
842 (message "Can't find completion for \"%s\"" pattern) | 844 (error "Can't find completion for \"%s\"" pattern)) |
843 (ding)) | |
844 ((not (string-equal pattern completion)) | 845 ((not (string-equal pattern completion)) |
845 (delete-region beg end) | 846 (delete-region beg end) |
846 (insert completion)) | 847 (insert completion)) |
847 (t | 848 (t |
848 (message "Making completion list...") | 849 (message "Making completion list...") |
851 (setq list (funcall prettify list))) | 852 (setq list (funcall prettify list))) |
852 (with-output-to-temp-buffer "*Help*" | 853 (with-output-to-temp-buffer "*Help*" |
853 (display-completion-list list))) | 854 (display-completion-list list))) |
854 (message "Making completion list...%s" "done"))))) | 855 (message "Making completion list...%s" "done"))))) |
855 | 856 |
857 ;;;###autoload | |
856 (defun tag-complete-symbol () | 858 (defun tag-complete-symbol () |
857 "The function used to do tags-completion (using 'tag-completion-predicate)." | 859 "The function used to do tags-completion (using 'tag-completion-predicate)." |
858 (interactive) | 860 (interactive) |
859 (let* ((buffer-tag-table-list (buffer-tag-table-symbol-list)) | 861 (let* ((buffer-tag-table-list (buffer-tag-table-symbol-list)) |
860 tag-symbol-tables) | 862 tag-symbol-tables) |
887 ;; Initialize the list from the tags table. | 889 ;; Initialize the list from the tags table. |
888 (setq next-file-list (buffer-tag-table-files))) | 890 (setq next-file-list (buffer-tag-table-files))) |
889 (t | 891 (t |
890 ;; Initialize the list by evalling the argument. | 892 ;; Initialize the list by evalling the argument. |
891 (setq next-file-list (eval initialize)))) | 893 (setq next-file-list (eval initialize)))) |
892 (if (null next-file-list) | 894 (when (null next-file-list) |
893 (progn | 895 (and novisit |
894 (and novisit | 896 (get-buffer " *next-file*") |
895 (get-buffer " *next-file*") | 897 (kill-buffer " *next-file*")) |
896 (kill-buffer " *next-file*")) | 898 (error "All files processed")) |
897 (error "All files processed."))) | |
898 (let* ((file (car next-file-list)) | 899 (let* ((file (car next-file-list)) |
899 (buf (get-file-buffer file)) | 900 (buf (get-file-buffer file)) |
900 (new (not buf))) | 901 (new (not buf))) |
901 (setq next-file-list (cdr next-file-list)) | 902 (pop next-file-list) |
902 | 903 |
903 (if (not (and new novisit)) | 904 (if (not (and new novisit)) |
904 (switch-to-buffer (find-file-noselect file novisit) t) | 905 (switch-to-buffer (find-file-noselect file novisit) t) |
905 ;; Like find-file, but avoids random warning messages. | 906 ;; Like find-file, but avoids random junk. |
906 (set-buffer (get-buffer-create " *next-file*")) | 907 (set-buffer (get-buffer-create " *next-file*")) |
907 (kill-all-local-variables) | 908 (kill-all-local-variables) |
908 (erase-buffer) | 909 (erase-buffer) |
909 (insert-file-contents file nil)) | 910 (insert-file-contents file nil)) |
910 (widen) | 911 (widen) |
911 (cond ((> (point) (point-min)) | 912 (when (> (point) (point-min)) |
912 (push-mark nil t) | 913 (push-mark nil t) |
913 (goto-char (point-min)))) | 914 (goto-char (point-min))) |
914 (and new file))) | 915 (and new file))) |
915 | |
916 (defcustom tags-search-nuke-uninteresting-buffers t | |
917 "*If t (the default), tags-search and tags-query-replace will only | |
918 keep newly-visited buffers if they contain the search target." | |
919 :type 'boolean | |
920 :group 'etags) | |
921 | 916 |
922 ;;;###autoload | 917 ;;;###autoload |
923 (defun tags-loop-continue (&optional first-time) | 918 (defun tags-loop-continue (&optional first-time) |
924 "Continue last \\[tags-search] or \\[tags-query-replace] command. | 919 "Continue last \\[tags-search] or \\[tags-query-replace] command. |
925 Used noninteractively with non-nil argument to begin such a command (the | 920 Used noninteractively with non-nil argument to begin such a command (the |
928 the value of `tags-loop-scan' is a form to be executed on each file | 923 the value of `tags-loop-scan' is a form to be executed on each file |
929 to see if it is interesting (it returns non-nil if so) | 924 to see if it is interesting (it returns non-nil if so) |
930 and `tags-loop-operate' is a form to execute to operate on an interesting file | 925 and `tags-loop-operate' is a form to execute to operate on an interesting file |
931 If the latter returns non-nil, we exit; otherwise we scan the next file." | 926 If the latter returns non-nil, we exit; otherwise we scan the next file." |
932 (interactive) | 927 (interactive) |
933 (let (new | 928 (let ((messaged nil) |
934 (messaged nil)) | 929 (more-files-p t) |
935 (while | 930 new) |
936 (progn | 931 (while more-files-p |
937 ;; Scan files quickly for the first or next interesting one. | 932 ;; Scan files quickly for the first or next interesting one. |
938 (while (or first-time | 933 (while (or first-time |
939 (save-restriction | 934 (save-restriction |
940 (widen) | 935 (widen) |
941 (not (eval tags-loop-scan)))) | 936 (not (eval tags-loop-scan)))) |
942 (setq new (next-file first-time | 937 (setq new (next-file first-time |
943 tags-search-nuke-uninteresting-buffers)) | 938 tags-search-nuke-uninteresting-buffers)) |
944 ;; If NEW is non-nil, we got a temp buffer, | 939 ;; If NEW is non-nil, we got a temp buffer, |
945 ;; and NEW is the file name. | 940 ;; and NEW is the file name. |
946 (if (or messaged | 941 (if (or messaged |
947 (and (not first-time) | 942 (and (not first-time) |
948 (> (device-baud-rate) search-slow-speed) | 943 (> (device-baud-rate) search-slow-speed) |
949 (setq messaged t))) | 944 (setq messaged t))) |
950 (message "Scanning file %s..." (or new buffer-file-name))) | 945 (lmessage 'progress |
951 (setq first-time nil) | 946 "Scanning file %s..." (or new buffer-file-name))) |
952 (goto-char (point-min))) | 947 (setq first-time nil) |
953 | 948 (goto-char (point-min))) |
954 ;; If we visited it in a temp buffer, visit it now for real. | 949 |
955 (if (and new tags-search-nuke-uninteresting-buffers) | 950 ;; If we visited it in a temp buffer, visit it now for real. |
956 (let ((pos (point))) | 951 (if (and new tags-search-nuke-uninteresting-buffers) |
957 (erase-buffer) | 952 (let ((pos (point))) |
958 (set-buffer (find-file-noselect new)) | 953 (erase-buffer) |
959 (widen) | 954 (set-buffer (find-file-noselect new)) |
960 (goto-char pos))) | 955 (widen) |
961 | 956 (goto-char pos))) |
962 (switch-to-buffer (current-buffer)) | 957 |
963 | 958 (switch-to-buffer (current-buffer)) |
964 ;; Now operate on the file. | 959 |
965 ;; If value is non-nil, continue to scan the next file. | 960 ;; Now operate on the file. |
966 (eval tags-loop-operate))) | 961 ;; If value is non-nil, continue to scan the next file. |
962 (setq more-files-p (eval tags-loop-operate))) | |
967 (and messaged | 963 (and messaged |
968 (null tags-loop-operate) | 964 (null tags-loop-operate) |
969 (message "Scanning file %s...found" buffer-file-name)))) | 965 (message "Scanning file %s...found" buffer-file-name)))) |
970 | 966 |
971 | 967 |
978 See documentation of variable `tag-table-alist'." | 974 See documentation of variable `tag-table-alist'." |
979 (interactive "sTags search (regexp): ") | 975 (interactive "sTags search (regexp): ") |
980 (if (and (equal regexp "") | 976 (if (and (equal regexp "") |
981 (eq (car tags-loop-scan) 'with-caps-disable-folding) | 977 (eq (car tags-loop-scan) 'with-caps-disable-folding) |
982 (null tags-loop-operate)) | 978 (null tags-loop-operate)) |
983 ;; Continue last tags-search as if by M-,. | 979 ;; Continue last tags-search as if by `M-,'. |
984 (tags-loop-continue nil) | 980 (tags-loop-continue nil) |
985 (setq tags-loop-scan `(with-caps-disable-folding ,regexp | 981 (setq tags-loop-scan `(with-caps-disable-folding ,regexp |
986 (re-search-forward ,regexp nil t)) | 982 (re-search-forward ,regexp nil t)) |
987 tags-loop-operate nil) | 983 tags-loop-operate nil) |
988 (tags-loop-continue (or file-list-form t)))) | 984 (tags-loop-continue (or file-list-form t)))) |
989 | 985 |
990 ;;;###autoload | 986 ;;;###autoload |
991 (defun tags-query-replace (from to &optional delimited file-list-form) | 987 (defun tags-query-replace (from to &optional delimited file-list-form) |
992 "Query-replace-regexp FROM with TO through all files listed in tags table. | 988 "Query-replace-regexp FROM with TO through all files listed in tags table. |
993 Third arg DELIMITED (prefix arg) means replace only word-delimited matches. | 989 Third arg DELIMITED (prefix arg) means replace only word-delimited matches. |
994 If you exit (\\[keyboard-quit] or ESC), you can resume the query-replace | 990 If you exit (\\[keyboard-quit] or ESC), you can resume the query-replace |
1007 (not (null delimited)))) | 1003 (not (null delimited)))) |
1008 (tags-loop-continue (or file-list-form t))) | 1004 (tags-loop-continue (or file-list-form t))) |
1009 | 1005 |
1010 ;; Miscellaneous | 1006 ;; Miscellaneous |
1011 | 1007 |
1012 ;; **** need to alter | |
1013 ;; This function is unchanged from lisp/tags.el: | |
1014 ;;;###autoload | 1008 ;;;###autoload |
1015 (defun list-tags (string) | 1009 (defun list-tags (file) |
1016 "Display list of tags in file FILE. | 1010 "Display list of tags in FILE." |
1017 FILE should not contain a directory spec | 1011 (interactive (list (read-file-name |
1018 unless it has one in the tag table." | 1012 (if (buffer-file-name) |
1019 (interactive "fList tags (in file): ") | 1013 (format "List tags (in file, %s by default): " |
1020 (setq string (expand-file-name string)) | 1014 (file-name-nondirectory (buffer-file-name))) |
1015 "List tags (in file): ") | |
1016 nil (buffer-file-name) t))) | |
1017 (find-file-noselect file) | |
1021 (with-output-to-temp-buffer "*Tags List*" | 1018 (with-output-to-temp-buffer "*Tags List*" |
1022 (princ "Tags in file ") | 1019 (princ "Tags in file ") |
1023 (princ string) | 1020 (princ file) |
1024 (terpri) | 1021 (terpri) |
1025 (save-excursion | 1022 (save-excursion |
1026 (visit-tags-table-buffer) | 1023 (dolist (tags-file (with-current-buffer (get-file-buffer file) |
1027 (goto-char 1) | 1024 (buffer-tag-table-list))) |
1028 (search-forward (concat "\f\n" string ",")) | 1025 ;; We don't want completions getting in the way. |
1029 (forward-line 1) | 1026 (let ((tags-build-completion-table nil)) |
1030 (while (not (or (eobp) (looking-at "\f"))) | 1027 (set-buffer (get-tag-table-buffer tags-file))) |
1031 (princ (buffer-substring (point) | 1028 (goto-char (point-min)) |
1032 (progn (skip-chars-forward "^\C-?") | 1029 (when |
1033 (point)))) | 1030 (search-forward (concat "\f\n" (file-name-nondirectory file) ",") |
1034 (terpri) | 1031 nil t) |
1035 (forward-line 1))))) | 1032 (forward-line 1) |
1036 | 1033 (while (not (or (eobp) (looking-at "\f"))) |
1037 ;; **** need to alter | 1034 (princ (buffer-substring (point) |
1038 ;; This function is unchanged from lisp/tags.el: | 1035 (progn (skip-chars-forward "^\C-?") |
1036 (point)))) | |
1037 (terpri) | |
1038 (forward-line 1))))))) | |
1039 | |
1039 ;;;###autoload | 1040 ;;;###autoload |
1040 (defun tags-apropos (string) | 1041 (defun tags-apropos (string) |
1041 "Display list of all tags in tag table REGEXP matches." | 1042 "Display list of all tags in tag table REGEXP matches." |
1042 (interactive "sTag apropos (regexp): ") | 1043 (interactive "sTag apropos (regexp): ") |
1043 (with-output-to-temp-buffer "*Tags List*" | 1044 (with-output-to-temp-buffer "*Tags List*" |
1044 (princ "Tags matching regexp ") | 1045 (princ "Tags matching regexp ") |
1045 (prin1 string) | 1046 (prin1 string) |
1046 (terpri) | 1047 (terpri) |
1047 (save-excursion | 1048 (save-excursion |
1048 (visit-tags-table-buffer) | 1049 (visit-tags-table-buffer) |
1049 (goto-char 1) | 1050 (goto-char 1) |
1050 (while (re-search-forward string nil t) | 1051 (while (re-search-forward string nil t) |
1051 (beginning-of-line) | 1052 (beginning-of-line) |
1052 (princ (buffer-substring (point) | 1053 (princ (buffer-substring (point) |
1053 (progn (skip-chars-forward "^\C-?") | 1054 (progn (skip-chars-forward "^\C-?") |
1054 (point)))) | 1055 (point)))) |
1055 (terpri) | 1056 (terpri) |
1056 (forward-line 1))))) | 1057 (forward-line 1))))) |
1057 | 1058 |
1058 ;; **** copied from tags.el | 1059 ;; #### copied from tags.el. This function is *very* big in FSF. |
1059 (defun visit-tags-table-buffer () | 1060 (defun visit-tags-table-buffer () |
1060 "Select the buffer containing the current tag table. | 1061 "Select the buffer containing the current tag table." |
1061 This is a file whose name is in the variable tags-file-name." | |
1062 (or tags-file-name | 1062 (or tags-file-name |
1063 (call-interactively 'visit-tags-table)) | 1063 (call-interactively 'visit-tags-table)) |
1064 (set-buffer (or (get-file-buffer tags-file-name) | 1064 (set-buffer (or (get-file-buffer tags-file-name) |
1065 (progn | 1065 (progn |
1066 (setq tag-table-files nil) | 1066 (setq tag-table-files nil) |
1073 (error "File %s not a valid tag table" tags-file-name))) | 1073 (error "File %s not a valid tag table" tags-file-name))) |
1074 | 1074 |
1075 | 1075 |
1076 ;; Sample uses of find-tag-hook and find-tag-default-hook | 1076 ;; Sample uses of find-tag-hook and find-tag-default-hook |
1077 | 1077 |
1078 ;; This is wrong. We should either make this behaviour default and | |
1079 ;; back it up, or not use it at all. For now, I've commented it out. | |
1080 ;; --hniksic | |
1081 | |
1078 ;; Example buffer-local tag finding | 1082 ;; Example buffer-local tag finding |
1079 | 1083 |
1080 (or (boundp 'emacs-lisp-mode-hook) | 1084 ;(add-hook 'emacs-lisp-mode-hook 'setup-emacs-lisp-default-tag-hook) |
1081 (setq emacs-lisp-mode-hook nil)) | 1085 |
1082 (if (eq (car-safe emacs-lisp-mode-hook) 'lambda) | 1086 ;(defun setup-emacs-lisp-default-tag-hook () |
1083 (setq emacs-lisp-mode-hook (list emacs-lisp-mode-hook))) | 1087 ; (cond ((eq major-mode 'emacs-lisp-mode) |
1084 (or (memq 'setup-emacs-lisp-default-tag-hook emacs-lisp-mode-hook) | 1088 ; (make-variable-buffer-local 'find-tag-default-hook) |
1085 (setq emacs-lisp-mode-hook | 1089 ; (setq find-tag-default-hook 'emacs-lisp-default-tag)))) |
1086 (cons 'setup-emacs-lisp-default-tag-hook emacs-lisp-mode-hook))) | 1090 ;;; Run it once immediately |
1087 | 1091 ;(setup-emacs-lisp-default-tag-hook) |
1088 (defun setup-emacs-lisp-default-tag-hook () | 1092 ;(when (get-buffer "*scratch*") |
1089 (cond ((eq major-mode 'emacs-lisp-mode) | 1093 ; (with-current-buffer "*scratch*" |
1090 (make-variable-buffer-local 'find-tag-default-hook) | 1094 ; (setup-emacs-lisp-default-tag-hook))) |
1091 (setq find-tag-default-hook 'emacs-lisp-default-tag)))) | 1095 |
1092 ;; Run it once immediately | 1096 ;(defun emacs-lisp-default-tag () |
1093 (setup-emacs-lisp-default-tag-hook) | 1097 ; "Function to return a default tag for Emacs-Lisp mode." |
1094 (when (get-buffer "*scratch*") | 1098 ; (let ((tag (or (variable-at-point) |
1095 (with-current-buffer "*scratch*" | 1099 ; (function-at-point)))) |
1096 (setup-emacs-lisp-default-tag-hook))) | 1100 ; (if tag (symbol-name tag)))) |
1097 | |
1098 (defun emacs-lisp-default-tag () | |
1099 "Function to return a default tag for Emacs-Lisp mode." | |
1100 (let ((tag (or (variable-at-point) | |
1101 (function-at-point)))) | |
1102 (if tag (symbol-name tag)))) | |
1103 | 1101 |
1104 | 1102 |
1105 ;; Display short info on tag in minibuffer | 1103 ;; Display short info on tag in minibuffer |
1106 | 1104 |
1107 (if (null (lookup-key esc-map "?")) | 1105 ;; Don't pollute `M-?' -- we may need it for more important stuff. --hniksic |
1108 (define-key esc-map "?" 'display-tag-info)) | 1106 ;(if (null (lookup-key esc-map "?")) |
1107 ; (define-key esc-map "?" 'display-tag-info)) | |
1109 | 1108 |
1110 (defun display-tag-info (tagname) | 1109 (defun display-tag-info (tagname) |
1111 "Prints a description of the first tag matching TAGNAME in the echo area. | 1110 "Prints a description of the first tag matching TAGNAME in the echo area. |
1112 If this is an elisp function, prints something like \"(defun foo (x y z)\". | 1111 If this is an elisp function, prints something like \"(defun foo (x y z)\". |
1113 That is, is prints the first line of the definition of the form. | 1112 That is, is prints the first line of the definition of the form. |
1158 tags-loop-operate nil) | 1157 tags-loop-operate nil) |
1159 ;; Always return non-nil | 1158 ;; Always return non-nil |
1160 t) | 1159 t) |
1161 | 1160 |
1162 | 1161 |
1163 ;; Keep track of old locations before finding tags | 1162 ;; Tag mark stack. |
1164 | 1163 |
1165 (defvar tag-mark-stack1 nil) | 1164 (defvar tag-mark-stack1 nil) |
1166 (defvar tag-mark-stack2 nil) | 1165 (defvar tag-mark-stack2 nil) |
1166 | |
1167 (defcustom tag-mark-stack-max 16 | 1167 (defcustom tag-mark-stack-max 16 |
1168 "*The maximum number of elements kept on the mark-stack used | 1168 "*The maximum number of elements kept on the mark-stack used |
1169 by tags-search. See also the commands push-tag-mark (\\[push-tag-mark]) | 1169 by tags-search. See also the commands `\\[push-tag-mark]' and |
1170 and pop-tag-mark. (\\[pop-tag-mark])." | 1170 and `\\[pop-tag-mark]'." |
1171 :type 'integer | 1171 :type 'integer |
1172 :group 'etags) | 1172 :group 'etags) |
1173 | 1173 |
1174 (defun push-mark-on-stack (stack-symbol &optional max-size) | 1174 (defun push-mark-on-stack (stack-symbol &optional max-size) |
1175 (let ((stack (symbol-value stack-symbol))) | 1175 (let ((stack (symbol-value stack-symbol))) |
1186 (marker (car stack)) | 1186 (marker (car stack)) |
1187 (m-buf (marker-buffer marker))) | 1187 (m-buf (marker-buffer marker))) |
1188 (set stack-symbol1 (cdr stack)) | 1188 (set stack-symbol1 (cdr stack)) |
1189 (or m-buf | 1189 (or m-buf |
1190 (error "Marker has no buffer")) | 1190 (error "Marker has no buffer")) |
1191 (if (null (buffer-name m-buf)) | 1191 (or (buffer-live-p m-buf) |
1192 (error "Buffer has been killed")) | 1192 (error "Buffer has been killed")) |
1193 (push-mark-on-stack stack-symbol2 max-size) | 1193 (push-mark-on-stack stack-symbol2 max-size) |
1194 (switch-to-buffer m-buf) | 1194 (switch-to-buffer m-buf) |
1195 (widen) | 1195 (widen) |
1196 (goto-char (marker-position marker)))) | 1196 (goto-char marker))) |
1197 | 1197 |
1198 (defun push-tag-mark () | 1198 (defun push-tag-mark () |
1199 (push-mark-on-stack 'tag-mark-stack1 tag-mark-stack-max)) | 1199 (push-mark-on-stack 'tag-mark-stack1 tag-mark-stack-max)) |
1200 | 1200 |
1201 (if (memq (lookup-key esc-map "*") '(nil undefined)) | 1201 ;;;###autoload (define-key esc-map "*" 'pop-tag-mark) |
1202 (define-key esc-map "*" 'pop-tag-mark)) | |
1203 | 1202 |
1204 (defun pop-tag-mark (arg) | 1203 (defun pop-tag-mark (arg) |
1205 "find-tag maintains a mark-stack seperate from the \\[set-mark-command] mark-stack. | 1204 "Go to last tag position. |
1205 `find-tag' maintains a mark-stack seperate from the \\[set-mark-command] mark-stack. | |
1206 This function pops (and moves to) the tag at the top of this stack." | 1206 This function pops (and moves to) the tag at the top of this stack." |
1207 (interactive "P") | 1207 (interactive "P") |
1208 (if (not arg) | 1208 (if (not arg) |
1209 (pop-mark-from-stack | 1209 (pop-mark-from-stack |
1210 'tag-mark-stack1 'tag-mark-stack2 tag-mark-stack-max) | 1210 'tag-mark-stack1 'tag-mark-stack2 tag-mark-stack-max) |