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)