aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoland McGrath1992-09-15 21:04:44 +0000
committerRoland McGrath1992-09-15 21:04:44 +0000
commit47f3c45980985f67d4de687a106c1a9b10b41c77 (patch)
tree7f36a94fb47d326b85a63ca56db0dc58ea8eaf1f
parent275da7879142a80cf3de5b81d494b0d69ec6b831 (diff)
downloademacs-47f3c45980985f67d4de687a106c1a9b10b41c77.tar.gz
emacs-47f3c45980985f67d4de687a106c1a9b10b41c77.zip
*** empty log message ***
-rw-r--r--lisp/progmodes/etags.el429
1 files changed, 242 insertions, 187 deletions
diff --git a/lisp/progmodes/etags.el b/lisp/progmodes/etags.el
index 97fb6a16971..09973910973 100644
--- a/lisp/progmodes/etags.el
+++ b/lisp/progmodes/etags.el
@@ -33,16 +33,23 @@ Use the `etags' program to make a tags table file.")
33;;;###autoload 33;;;###autoload
34(defvar tags-table-list nil 34(defvar tags-table-list nil
35 "*List of names of tags table files which are currently being searched. 35 "*List of names of tags table files which are currently being searched.
36Elements that are directories mean the file \"TAGS\" in that directory.
36An element of nil means to look for a file \"TAGS\" in the current directory. 37An element of nil means to look for a file \"TAGS\" in the current directory.
37Use `visit-tags-table-buffer' to cycle through tags tables in this list.") 38Use `visit-tags-table-buffer' to cycle through tags tables in this list.")
38 39
39(defvar tags-table-list-pointer nil 40(defvar tags-table-list-pointer nil
40 "Pointer into `tags-table-list', or into a list of included tags tables, 41 "Pointer into `tags-table-list' where the current state of searching is.
41where the current state of searching is. Use `visit-tags-table-buffer' to 42Might instead point into a list of included tags tables.
42cycle through tags tables in this list.") 43Use `visit-tags-table-buffer' to cycle through tags tables in this list.")
44
45(defvar tags-table-list-started-at nil
46 "Pointer into `tags-table-list', where the current search started.")
43 47
44(defvar tags-table-parent-pointer-list nil 48(defvar tags-table-parent-pointer-list nil
45 "List of values to restore into `tags-table-list-pointer' when it hits nil.") 49 "Saved state of the tags table that included this one.
50Each element is (POINTER . STARTED-AT), giving the values of
51 `tags-table-list-pointer' and `tags-table-list-started-at' from
52 before we moved into the current table.")
46 53
47(defvar tags-table-set-list nil 54(defvar tags-table-set-list nil
48 "List of sets of tags table which have been used together in the past. 55 "List of sets of tags table which have been used together in the past.
@@ -56,8 +63,8 @@ not the value in the buffer \\[find-tag] goes to.")
56 63
57;;;###autoload 64;;;###autoload
58(defvar find-tag-default-function nil 65(defvar find-tag-default-function nil
59 "*If non-nil, a function of no arguments used by \\[find-tag] to pick a 66 "*A function of no arguments used by \\[find-tag] to pick a default tag.
60default tag. If nil, and the symbol that is the value of `major-mode' 67If nil, and the symbol that is the value of `major-mode'
61has a `find-tag-default-function' property (see `put'), that is used. 68has a `find-tag-default-function' property (see `put'), that is used.
62Otherwise, `find-tag-default' is used.") 69Otherwise, `find-tag-default' is used.")
63 70
@@ -165,203 +172,248 @@ file the tag was in."
165 current-prefix-arg)) 172 current-prefix-arg))
166 (let ((tags-file-name file)) 173 (let ((tags-file-name file))
167 (save-excursion 174 (save-excursion
168 (or (visit-tags-file t) 175 (or (visit-tags-table-buffer 'same)
169 (signal 'file-error (list "Visiting tags table" 176 (signal 'file-error (list "Visiting tags table"
170 "file does not exist" 177 "file does not exist"
171 file))) 178 file)))
172 (setq file tags-file-name))) 179 (setq file tags-file-name)))
173 (if local 180 (if local
174 (setq tags-file-name file) 181 (set (make-local-variable 'tags-file-name) file)
175 (kill-local-variable 'tags-file-name)
176 (setq-default tags-file-name file))) 182 (setq-default tags-file-name file)))
177 183
178;; Move tags-table-list-pointer along and set tags-file-name. 184;; Move tags-table-list-pointer along and set tags-file-name.
179;; Returns nil when out of tables. 185;; Returns nil when out of tables.
180(defun tags-next-table () 186(defun tags-next-table (&optional reset no-includes)
181 (if (tags-included-tables) 187 (if reset
182 (progn 188 (setq tags-table-list-pointer tags-table-list)
189
190 (if (and (not no-includes)
191 (visit-tags-table-buffer 'same)
192 (tags-included-tables))
183 ;; Move into the included tags tables. 193 ;; Move into the included tags tables.
184 (if tags-table-list-pointer 194 (setq tags-table-parent-pointer-list
185 (setq tags-table-parent-pointer-list 195 (cons (cons tags-table-list-pointer tags-table-list-started-at)
186 (cons tags-table-list-pointer 196 tags-table-parent-pointer-list)
187 tags-table-parent-pointer-list))) 197 tags-table-list-pointer tags-included-tables
188 (setq tags-table-list-pointer tags-included-tables)) 198 tags-table-list-started-at tags-included-tables)
189
190 (if tags-table-list-pointer
191 ;; Go to the next table in the list.
192 (setq tags-table-list-pointer
193 (cdr tags-table-list-pointer))
194
195 ;; Pop back to the tags table which includes this one.
196 (setq tags-table-list-pointer
197 (car tags-table-parent-pointer-list)
198 tags-table-parent-pointer-list
199 (cdr tags-table-parent-pointer-list))))
200 199
201 (and tags-table-list-pointer 200 ;; Go to the next table in the list.
202 (setq tags-file-name 201 (setq tags-table-list-pointer
203 (or (car tags-table-list-pointer) 202 (cdr tags-table-list-pointer))
204 ;; nil means look for TAGS in current directory. 203 (or tags-table-list-pointer
205 (expand-file-name "TAGS" default-directory))))) 204 ;; Wrap around.
205 (setq tags-table-list-pointer tags-table-list))
206
207 (if (eq tags-table-list-pointer tags-table-list-started-at)
208 ;; We have come full circle.
209 (if tags-table-parent-pointer-list
210 ;; Pop back to the tags table which includes this one.
211 (progn
212 (setq tags-table-list-pointer
213 (car (car tags-table-parent-pointer-list))
214 tags-table-list-started-at
215 (cdr (car tags-table-parent-pointer-list))
216 tags-table-parent-pointer-list
217 (cdr tags-table-parent-pointer-list))
218 (tags-next-table nil t))
219 ;; All out of tags tables.
220 (setq tags-table-list-pointer nil))))
221
222 (and tags-table-list-pointer
223 (setq tags-file-name
224 (tags-expand-table-name (car tags-table-list-pointer))))))
225
226(defun tags-expand-table-name (file)
227 (or file
228 ;; nil means look for TAGS in current directory.
229 (setq file default-directory))
230 (setq file (expand-file-name file))
231 (if (file-directory-p file)
232 (expand-file-name "TAGS" file)
233 file))
234
235(defun tags-table-list-member (file &optional list)
236 (or list
237 (setq list tags-table-list))
238 (setq file (tags-expand-table-name file))
239 (while (and list
240 (not (string= file (tags-expand-table-name (car list)))))
241 (setq list (cdr list)))
242 list)
243
244;; Subroutine of visit-tags-table-buffer. Frobs its local vars.
245;; Search TABLES for one that has tags for THIS-FILE.
246;; Recurses on included tables.
247(defun tags-table-including (this-file tables &optional recursing)
248 (let ((found nil))
249 (while (and (not found)
250 tables)
251 (let ((tags-file-name (tags-expand-table-name (car tables))))
252 (if (or (get-file-buffer tags-file-name)
253 (file-exists-p tags-file-name))
254 (progn
255 ;; Select the tags table buffer and get the file list up to date.
256 (visit-tags-table-buffer 'same)
257 (or tags-table-files
258 (setq tags-table-files
259 (funcall tags-table-files-function)))
260
261 (cond ((member this-file tags-table-files)
262 ;; Found it.
263 (setq found tables))
264
265 ((tags-included-tables)
266 (let ((old tags-table-parent-pointer-list))
267 (unwind-protect
268 (progn
269 (or recursing
270 ;; At top level (not in an included tags
271 ;; table), set the list to nil so we can
272 ;; collect just the elts from this run.
273 (setq tags-table-parent-pointer-list nil))
274 (setq found
275 (tags-table-including this-file
276 tags-included-tables
277 t))
278 (if found
279 (progn
280 (setq tags-table-parent-pointer-list
281 (cons
282 (cons tags-table-list-pointer
283 tags-table-list-started-at)
284 tags-table-parent-pointer-list)
285 tags-table-list-pointer found
286 tags-table-list-started-at found
287 ;; Don't frob lists later.
288 cont 'included))))
289 (or recursing
290 ;; Recursive calls have consed onto the front
291 ;; of the list, so it is now outermost first.
292 ;; We want it innermost first.
293 (setq tags-table-parent-pointer-list
294 (nconc (nreverse
295 tags-table-parent-pointer-list)
296 old))))))))))
297 (setq tables (cdr tables)))
298 found))
206 299
207(defun visit-tags-table-buffer (&optional cont) 300(defun visit-tags-table-buffer (&optional cont)
208 "Select the buffer containing the current tags table. 301 "Select the buffer containing the current tags table.
209If optional arg is t, visit the next table in `tags-table-list'. 302If optional arg is t, visit the next table in `tags-table-list'.
210If optional arg is the atom `reset', reset to the head of `tags-table-list'.
211If optional arg is the atom `same', don't look for a new table; 303If optional arg is the atom `same', don't look for a new table;
212 just select the buffer. 304 just select the buffer.
213If arg is nil or absent, choose a buffer from information in 305If arg is nil or absent, choose a first buffer from information in
214`tags-file-name', `tags-table-list', `tags-table-list-pointer'. 306`tags-file-name', `tags-table-list', `tags-table-list-pointer'.
215Returns t if it visits a tags table, or nil if there are no more in the list." 307Returns t if it visits a tags table, or nil if there are no more in the list."
216 (cond ((eq cont 'same) 308 (cond ((eq cont 'same))
217 (let ((tags-file-name (car tags-table-list-pointer))) 309
218 (and tags-file-name 310 (cont
219 (visit-tags-file nil))) 311 (if (tags-next-table)
220 312 ;; Skip over nonexistent files.
221 (cont 313 (while (and (let ((file (tags-expand-table-name tags-file-name)))
222 (if (eq cont 'reset) 314 (not (or (get-file-buffer file)
223 (setq tags-table-list-pointer tags-table-list) 315 (file-exists-p file))))
224 (tags-next-table)) 316 (tags-next-table)))))
225 317
226 (while (and (not (visit-tags-file nil)) ;Skip over nonexistent files. 318 (t
227 (tags-next-table))) 319 (setq tags-file-name
228 (not (null tags-table-list-pointer))) 320 (or (cdr (assq 'tags-file-name (buffer-local-variables)))
229 321 (and default-tags-table-function
230 (t 322 (funcall default-tags-table-function))
231 (setq tags-file-name 323 ;; Look for a tags table that contains
232 (or (cdr (assq 'tags-file-name (buffer-local-variables))) 324 ;; tags for the current buffer's file.
233 (and default-tags-table-function 325 ;; If one is found, the lists will be frobnicated,
234 (funcall default-tags-table-function)) 326 ;; and CONT will be set non-nil so we don't do it below.
235 ;; Look for a tags table that contains 327 (save-excursion
236 ;; tags for the current buffer's file. 328 (car (tags-table-including buffer-file-name
237 (let ((tables tags-table-list) 329 tags-table-list)))
238 (this-file (buffer-file-name)) 330 (car tags-table-list)
239 (found nil)) 331 tags-file-name
240 (save-excursion 332 (expand-file-name
241 (while tables 333 (read-file-name "Visit tags table: (default TAGS) "
242 (let ((tags-file-name (car tables))) 334 default-directory
243 (if (and (file-exists-p tags-file-name) 335 "TAGS"
244 (progn 336 t))))))
245 (visit-tags-file nil) 337
246 (or tags-table-files 338 (setq tags-file-name (tags-expand-table-name tags-file-name))
247 (setq tags-table-files 339
248 (funcall 340 (if (and cont (null tags-table-list-pointer))
249 tags-table-files-function))) 341 ;; All out of tables.
250 (assoc this-file tags-file-files))) 342 nil
251 (setq found (car tables) 343
252 tables nil) 344 (if (if (get-file-buffer tags-file-name)
253 (setq tables (cdr tables)))))) 345 (let (win)
254 found) 346 (set-buffer (get-file-buffer tags-file-name))
255 (car tags-table-list-pointer) 347 (setq win (or verify-tags-table-function
256 tags-file-name 348 (initialize-new-tags-table)))
257 (expand-file-name 349 (if (or (verify-visited-file-modtime (current-buffer))
258 (read-file-name "Visit tags table: (default TAGS) " 350 (not (yes-or-no-p
259 default-directory 351 "Tags file has changed, read new contents? ")))
260 (expand-file-name "TAGS" 352 (and win (funcall verify-tags-table-function))
261 default-directory) 353 (revert-buffer t t)
262 t)))) 354 (initialize-new-tags-table)))
263 (visit-tags-file t))))) 355 (set-buffer (find-file-noselect tags-file-name))
264 356 (or (string= tags-file-name buffer-file-name)
265;; Visit tags-file-name and check that it's a valid tags table. Returns 357 ;; find-file-noselect has changed the file name.
266;; nil and does nothing if tags-file-name does not exist. Otherwise, on 358 ;; Propagate change to tags-file-name and tags-table-list.
267;; return tags-table-list and tags-table-list-pointer point to 359 (let ((tail (member file tags-table-list)))
268;; tags-file-name. 360 (if tail
269(defun visit-tags-file (put-in-list) 361 (setcar tail buffer-file-name))
270 (let ((file tags-file-name)) 362 (setq tags-file-name buffer-file-name)))
271 (if (file-directory-p file) 363 (initialize-new-tags-table))
272 (setq file (expand-file-name "TAGS" file))) 364
273 (if (or (get-file-buffer file) 365 ;; We have a valid tags table.
274 (file-exists-p file)) 366 (progn
275 (if (if (get-file-buffer file) 367 ;; Bury the tags table buffer so it
276 (let (win) 368 ;; doesn't get in the user's way.
277 (set-buffer (get-file-buffer file)) 369 (bury-buffer (current-buffer))
278 (setq win (or verify-tags-table-function
279 (initialize-new-tags-table)))
280 (if (or (verify-visited-file-modtime (current-buffer))
281 (not (yes-or-no-p
282 "Tags file has changed, read new contents? ")))
283 (and win (funcall verify-tags-table-function))
284 (revert-buffer t t)
285 (initialize-new-tags-table)))
286 (set-buffer (find-file-noselect file))
287 (or (string= file buffer-file-name)
288 ;; find-file-noselect has changed the file name.
289 ;; Propagate change to tags-file-name and tags-table-list.
290 (let ((tail (assoc file tags-table-list)))
291 (if tail
292 (setcar tail buffer-file-name))
293 (setq tags-file-name buffer-file-name)))
294 (initialize-new-tags-table))
295 370
296 (if (and put-in-list 371 (if cont
297 (not (equal file (car tags-table-list-pointer)))) 372 ;; No list frobbing required.
298 (let (elt) 373 nil
299 ;; Bury the tags table buffer so it 374
300 ;; doesn't get in the user's way. 375 ;; Look in the list for the table we chose.
301 (bury-buffer (current-buffer)) 376 (let ((elt (tags-table-list-member tags-file-name)))
302 ;; Look for this file in the current list of tags files. 377 (or elt
303 (if (setq elt (member file tags-table-list)) 378 ;; The table is not in the current set.
304 (if (eq elt tags-table-list) 379 ;; Try to find it in another previously used set.
305 ;; Already at the head of the list. 380 (let ((sets tags-table-set-list))
306 () 381 (while (and sets
307 ;; Rotate this element to the head of the search list. 382 (not (setq elt (tags-table-list-member
308 (setq tags-table-list-pointer 383 tags-file-name (car sets)))))
309 (nconc elt tags-table-list)) 384 (setq sets (cdr sets)))
310 (while (not (eq (cdr tags-table-list) elt)) 385 (if sets
311 (setq tags-table-list (cdr tags-table-list))) 386 (progn
312 (setcdr tags-table-list nil) 387 ;; Found in some other set. Switch to that set.
313 (setq tags-table-list tags-table-list-pointer))
314 ;; The table is not in the current set.
315 ;; Try to find it in another previously used set.
316 (let ((sets tags-table-set-list))
317 (while (and sets
318 (not (setq elt (member file
319 (car sets)))))
320 (setq sets (cdr sets)))
321 (if sets
322 (progn
323 ;; Found in some other set. Switch to that
324 ;; set, making the selected tags table the head
325 ;; of the search list.
326 (or (memq tags-table-list tags-table-set-list)
327 ;; Save the current list.
328 (setq tags-table-set-list
329 (cons tags-table-list
330 tags-table-set-list)))
331 (setq tags-table-list (car sets))
332 (if (eq elt tags-table-list)
333 ;; Already at the head of the list
334 ()
335 ;; Rotate this element to the head of the list.
336 (setq tags-table-list-pointer
337 (nconc elt tags-table-list))
338 (while (not (eq (cdr tags-table-list) elt))
339 (setq tags-table-list (cdr tags-table-list)))
340 (setcdr tags-table-list nil)
341 (setq tags-table-list tags-table-list-pointer)
342 (setcar sets tags-table-list)))
343 ;; Not found in any current set.
344 (if (and tags-table-list
345 (y-or-n-p
346 (concat "Add " file " to current list"
347 " of tags tables? ")))
348 ;; Add it to the current list.
349 (setq tags-table-list
350 (cons file tags-table-list))
351 ;; Make a fresh list, and store the old one.
352 (or (memq tags-table-list tags-table-set-list) 388 (or (memq tags-table-list tags-table-set-list)
389 ;; Save the current list.
353 (setq tags-table-set-list 390 (setq tags-table-set-list
354 (cons tags-table-list 391 (cons tags-table-list
355 tags-table-set-list))) 392 tags-table-set-list)))
356 (setq tags-table-list (cons file nil))) 393 (setq tags-table-list (car sets)))
357 (setq tags-table-list-pointer tags-table-list)))) 394
358 t) 395 ;; Not found in any existing set.
359 t) 396 (if (and tags-table-list
360 397 (y-or-n-p (concat "Add " tags-file-name
361 ;; The buffer was not valid. Don't use it again. 398 " to current list"
362 (kill-local-variable 'tags-file-name) 399 " of tags tables? ")))
363 (setq tags-file-name nil) 400 ;; Add it to the current list.
364 (error "File %s is not a valid tags table" buffer-file-name))))) 401 (setq tags-table-list (cons tags-file-name
402 tags-table-list))
403 ;; Make a fresh list, and store the old one.
404 (or (memq tags-table-list tags-table-set-list)
405 (setq tags-table-set-list
406 (cons tags-table-list tags-table-set-list)))
407 (setq tags-table-list (list tags-file-name)))
408 (setq elt tags-table-list))))
409
410 (setq tags-table-list-started-at elt
411 tags-table-list-pointer elt))))
412
413 ;; The buffer was not valid. Don't use it again.
414 (kill-local-variable 'tags-file-name)
415 (setq tags-file-name nil)
416 (error "File %s is not a valid tags table" buffer-file-name))))
365 417
366(defun file-of-tag () 418(defun file-of-tag ()
367 "Return the file name of the file whose tags point is within. 419 "Return the file name of the file whose tags point is within.
@@ -397,7 +449,7 @@ File names returned are absolute."
397 (save-excursion 449 (save-excursion
398 (while included 450 (while included
399 (let ((tags-file-name (car included))) 451 (let ((tags-file-name (car included)))
400 (visit-tags-file nil)) 452 (visit-tags-table-buffer 'same))
401 (if (tags-completion-table) 453 (if (tags-completion-table)
402 (mapatoms (function 454 (mapatoms (function
403 (lambda (sym) 455 (lambda (sym)
@@ -475,7 +527,7 @@ See documentation of variable `tags-file-name'."
475 (if next-p 527 (if next-p
476 (visit-tags-table-buffer 'same) 528 (visit-tags-table-buffer 'same)
477 (setq last-tag tagname) 529 (setq last-tag tagname)
478 (visit-tags-table-buffer 'reset)) 530 (visit-tags-table-buffer))
479 (prog1 531 (prog1
480 (find-tag-in-order (if next-p last-tag tagname) 532 (find-tag-in-order (if next-p last-tag tagname)
481 (if regexp-p 533 (if regexp-p
@@ -592,10 +644,12 @@ See documentation of variable `tags-file-name'."
592 goto-func 644 goto-func
593 ) 645 )
594 (save-excursion 646 (save-excursion
595 (or first-search 647 (or first-search ;find-tag-noselect has already done it.
596 (visit-tags-table-buffer)) 648 (visit-tags-table-buffer 'same))
649
597 ;; Get a qualified match. 650 ;; Get a qualified match.
598 (catch 'qualified-match-found 651 (catch 'qualified-match-found
652
599 (while (or first-table 653 (while (or first-table
600 (visit-tags-table-buffer t)) 654 (visit-tags-table-buffer t))
601 655
@@ -879,7 +933,7 @@ if the file was newly read in, the value is the filename."
879 (interactive "P") 933 (interactive "P")
880 (and initialize 934 (and initialize
881 (save-excursion 935 (save-excursion
882 (visit-tags-table-buffer 'reset) 936 (visit-tags-table-buffer)
883 (setq next-file-list (tags-table-files)))) 937 (setq next-file-list (tags-table-files))))
884 (or next-file-list 938 (or next-file-list
885 (save-excursion 939 (save-excursion
@@ -1012,7 +1066,7 @@ unless it has one in the tags table."
1012 (save-excursion 1066 (save-excursion
1013 (let ((first-time t) 1067 (let ((first-time t)
1014 (gotany nil)) 1068 (gotany nil))
1015 (while (visit-tags-table-buffer (if first-time 'reset t)) 1069 (while (visit-tags-table-buffer (not first-time))
1016 (if (funcall list-tags-function file) 1070 (if (funcall list-tags-function file)
1017 (setq gotany t))) 1071 (setq gotany t)))
1018 (or gotany 1072 (or gotany
@@ -1027,8 +1081,9 @@ unless it has one in the tags table."
1027 (prin1 regexp) 1081 (prin1 regexp)
1028 (terpri) 1082 (terpri)
1029 (save-excursion 1083 (save-excursion
1030 (let ((first-time nil)) 1084 (let ((first-time t))
1031 (while (visit-tags-table-buffer (if first-time 'reset t)) 1085 (while (visit-tags-table-buffer (not first-time))
1086 (setq first-time nil)
1032 (funcall tags-apropos-function)))))) 1087 (funcall tags-apropos-function))))))
1033 1088
1034;;; XXX Kludge interface. 1089;;; XXX Kludge interface.