(next-file): If arg is neither t nor nil, then eval it to return initial
[bpt/emacs.git] / lisp / progmodes / etags.el
index 70dcd9a..452d9ad 100644 (file)
@@ -259,6 +259,10 @@ file the tag was in."
     (setq list (cdr list)))
   list)
 
+;; Local var in visit-tags-table-buffer-cont
+;; which is set by tags-table-including.
+(defvar visit-tags-table-buffer-cont)
+
 ;; Subroutine of visit-tags-table-buffer.  Frobs its local vars.
 ;; Search TABLES for one that has tags for THIS-FILE.  Recurses on
 ;; included tables.  Returns the tail of TABLES (or of an inner
@@ -312,10 +316,11 @@ file the tag was in."
                                        tags-table-parent-pointer-list)
                                       tags-table-list-pointer found
                                       tags-table-list-started-at found
-                                      ;; CONT is a local variable of
+                                      ;; Set a local variable of
                                       ;; our caller, visit-tags-table-buffer.
                                       ;; Set it so we won't frob lists later.
-                                      cont 'included)))
+                                      visit-tags-table-buffer-cont
+                                      'included)))
                         (or recursing
                             ;; tags-table-parent-pointer-list now describes
                             ;; the path of included tables taken by recursive
@@ -343,160 +348,163 @@ If arg is nil or absent, choose a first buffer from information in
 Returns t if it visits a tags table, or nil if there are no more in the list."
 
   ;; Set tags-file-name to the tags table file we want to visit.
-  (cond ((eq cont 'same)
-        ;; Use the ambient value of tags-file-name.
-        (or tags-file-name
-            (error (substitute-command-keys
-                    (concat "No tags table in use!  "
-                            "Use \\[visit-tags-table] to select one."))))
-        ;; Set CONT to nil so the code below will make sure tags-file-name
-        ;; is in tags-table-list.
-        (setq cont nil))
-
-       (cont
-        ;; Find the next table.
-        (if (tags-next-table)
-            ;; Skip over nonexistent files.
-            (while (and (let ((file (tags-expand-table-name tags-file-name)))
-                          (not (or (get-file-buffer file)
-                                   (file-exists-p file))))
-                        (tags-next-table)))))
+  (let ((visit-tags-table-buffer-cont cont))
+    (cond ((eq visit-tags-table-buffer-cont 'same)
+          ;; Use the ambient value of tags-file-name.
+          (or tags-file-name
+              (error (substitute-command-keys
+                      (concat "No tags table in use!  "
+                              "Use \\[visit-tags-table] to select one."))))
+          ;; Set VISIT-TAGS-TABLE-BUFFER-CONT to nil
+          ;; so the code below will make sure tags-file-name
+          ;; is in tags-table-list.
+          (setq visit-tags-table-buffer-cont nil))
+
+         (visit-tags-table-buffer-cont
+          ;; Find the next table.
+          (if (tags-next-table)
+              ;; Skip over nonexistent files.
+              (while (and (let ((file (tags-expand-table-name tags-file-name)))
+                            (not (or (get-file-buffer file)
+                                     (file-exists-p file))))
+                          (tags-next-table)))))
 
-       (t
-        ;; Pick a table out of our hat.
-        (setq tags-file-name
-              (or
-               ;; First, try a local variable.
-               (cdr (assq 'tags-file-name (buffer-local-variables)))
-               ;; Second, try a user-specified function to guess.
-               (and default-tags-table-function
-                    (funcall default-tags-table-function))
-               ;; Third, look for a tags table that contains
-               ;; tags for the current buffer's file.
-               ;; If one is found, the lists will be frobnicated,
-               ;; and CONT will be set non-nil so we don't do it below.
-               (car (or 
-                     ;; First check only tables already in buffers.
-                     (save-excursion (tags-table-including buffer-file-name
-                                                              tags-table-list
-                                                              t))
-                     ;; Since that didn't find any, now do the
-                     ;; expensive version: reading new files.
-                     (save-excursion (tags-table-including buffer-file-name
-                                                           tags-table-list
-                                                           nil))))
-               ;; Fourth, use the user variable tags-file-name, if it is not
-               ;; already in tags-table-list.
-               (and tags-file-name
-                    (not (tags-table-list-member tags-file-name))
-                    tags-file-name)
-               ;; Fifth, use the user variable giving the table list.
-               ;; Find the first element of the list that actually exists.
-               (let ((list tags-table-list)
-                     file)
-                 (while (and list
-                             (setq file (tags-expand-table-name (car list)))
-                             (not (get-file-buffer file))
-                             (not (file-exists-p file)))
-                   (setq list (cdr list)))
-                 (car list))
-               ;; Finally, prompt the user for a file name.
-               (expand-file-name
-                (read-file-name "Visit tags table: (default TAGS) "
-                                default-directory
-                                "TAGS"
-                                t))))))
-
-  ;; Expand the table name into a full file name.
-  (setq tags-file-name (tags-expand-table-name tags-file-name))
-
-  (if (and (eq cont t) (null tags-table-list-pointer))
-      ;; All out of tables.
-      nil
-
-    ;; Verify that tags-file-name is a valid tags table.
-    (if (if (get-file-buffer tags-file-name)
-           ;; The file is already in a buffer.  Check for the visited file
-           ;; having changed since we last used it.
-           (let (win)
-             (set-buffer (get-file-buffer tags-file-name))
-             (setq win (or verify-tags-table-function
-                           (initialize-new-tags-table)))
-             (if (or (verify-visited-file-modtime (current-buffer))
-                     (not (yes-or-no-p
-                           "Tags file has changed, read new contents? ")))
-                 (and win (funcall verify-tags-table-function))
-               (revert-buffer t t)
-               (initialize-new-tags-table)))
-         (set-buffer (find-file-noselect tags-file-name))
-         (or (string= tags-file-name buffer-file-name)
-             ;; find-file-noselect has changed the file name.
-             ;; Propagate the change to tags-file-name and tags-table-list.
-             (let ((tail (member tags-file-name tags-table-list)))
-               (if tail
-                   (setcar tail buffer-file-name))
-               (setq tags-file-name buffer-file-name)))
-         (initialize-new-tags-table))
-
-       ;; We have a valid tags table.
-       (progn
-         ;; Bury the tags table buffer so it
-         ;; doesn't get in the user's way.
-         (bury-buffer (current-buffer))
-       
-         (if cont
-             ;; No list frobbing required.
-             nil
-
-           ;; Look in the list for the table we chose.
-           (let ((elt (tags-table-list-member tags-file-name)))
-             (or elt
-                 ;; The table is not in the current set.
-                 ;; Try to find it in another previously used set.
-                 (let ((sets tags-table-set-list))
-                   (while (and sets
-                               (not (setq elt (tags-table-list-member
-                                               tags-file-name (car sets)))))
-                     (setq sets (cdr sets)))
-                   (if sets
-                       ;; Found in some other set.  Switch to that set.
-                       (progn
+         (t
+          ;; Pick a table out of our hat.
+          (setq tags-file-name
+                (or
+                 ;; First, try a local variable.
+                 (cdr (assq 'tags-file-name (buffer-local-variables)))
+                 ;; Second, try a user-specified function to guess.
+                 (and default-tags-table-function
+                      (funcall default-tags-table-function))
+                 ;; Third, look for a tags table that contains
+                 ;; tags for the current buffer's file.
+                 ;; If one is found, the lists will be frobnicated,
+                 ;; and VISIT-TAGS-TABLE-BUFFER-CONT
+                 ;; will be set non-nil so we don't do it below.
+                 (car (or 
+                       ;; First check only tables already in buffers.
+                       (save-excursion (tags-table-including buffer-file-name
+                                                                tags-table-list
+                                                                t))
+                       ;; Since that didn't find any, now do the
+                       ;; expensive version: reading new files.
+                       (save-excursion (tags-table-including buffer-file-name
+                                                             tags-table-list
+                                                             nil))))
+                 ;; Fourth, use the user variable tags-file-name, if it is not
+                 ;; already in tags-table-list.
+                 (and tags-file-name
+                      (not (tags-table-list-member tags-file-name))
+                      tags-file-name)
+                 ;; Fifth, use the user variable giving the table list.
+                 ;; Find the first element of the list that actually exists.
+                 (let ((list tags-table-list)
+                       file)
+                   (while (and list
+                               (setq file (tags-expand-table-name (car list)))
+                               (not (get-file-buffer file))
+                               (not (file-exists-p file)))
+                     (setq list (cdr list)))
+                   (car list))
+                 ;; Finally, prompt the user for a file name.
+                 (expand-file-name
+                  (read-file-name "Visit tags table: (default TAGS) "
+                                  default-directory
+                                  "TAGS"
+                                  t))))))
+
+    ;; Expand the table name into a full file name.
+    (setq tags-file-name (tags-expand-table-name tags-file-name))
+
+    (if (and (eq visit-tags-table-buffer-cont t) (null tags-table-list-pointer))
+       ;; All out of tables.
+       nil
+
+      ;; Verify that tags-file-name is a valid tags table.
+      (if (if (get-file-buffer tags-file-name)
+             ;; The file is already in a buffer.  Check for the visited file
+             ;; having changed since we last used it.
+             (let (win)
+               (set-buffer (get-file-buffer tags-file-name))
+               (setq win (or verify-tags-table-function
+                             (initialize-new-tags-table)))
+               (if (or (verify-visited-file-modtime (current-buffer))
+                       (not (yes-or-no-p
+                             "Tags file has changed, read new contents? ")))
+                   (and win (funcall verify-tags-table-function))
+                 (revert-buffer t t)
+                 (initialize-new-tags-table)))
+           (set-buffer (find-file-noselect tags-file-name))
+           (or (string= tags-file-name buffer-file-name)
+               ;; find-file-noselect has changed the file name.
+               ;; Propagate the change to tags-file-name and tags-table-list.
+               (let ((tail (member tags-file-name tags-table-list)))
+                 (if tail
+                     (setcar tail buffer-file-name))
+                 (setq tags-file-name buffer-file-name)))
+           (initialize-new-tags-table))
+
+         ;; We have a valid tags table.
+         (progn
+           ;; Bury the tags table buffer so it
+           ;; doesn't get in the user's way.
+           (bury-buffer (current-buffer))
+
+           (if visit-tags-table-buffer-cont
+               ;; No list frobbing required.
+               nil
+
+             ;; Look in the list for the table we chose.
+             (let ((elt (tags-table-list-member tags-file-name)))
+               (or elt
+                   ;; The table is not in the current set.
+                   ;; Try to find it in another previously used set.
+                   (let ((sets tags-table-set-list))
+                     (while (and sets
+                                 (not (setq elt (tags-table-list-member
+                                                 tags-file-name (car sets)))))
+                       (setq sets (cdr sets)))
+                     (if sets
+                         ;; Found in some other set.  Switch to that set.
+                         (progn
+                           (or (memq tags-table-list tags-table-set-list)
+                               ;; Save the current list.
+                               (setq tags-table-set-list
+                                     (cons tags-table-list
+                                           tags-table-set-list)))
+                           (setq tags-table-list (car sets)))
+
+                       ;; Not found in any existing set.
+                       (if (and tags-table-list
+                                (y-or-n-p (concat "Add " tags-file-name
+                                                  " to current list"
+                                                  " of tags tables? ")))
+                           ;; Add it to the current list.
+                           (setq tags-table-list (cons tags-file-name
+                                                       tags-table-list))
+                         ;; Make a fresh list, and store the old one.
                          (or (memq tags-table-list tags-table-set-list)
-                             ;; Save the current list.
                              (setq tags-table-set-list
-                                   (cons tags-table-list
-                                         tags-table-set-list)))
-                         (setq tags-table-list (car sets)))
-
-                     ;; Not found in any existing set.
-                     (if (and tags-table-list
-                              (y-or-n-p (concat "Add " tags-file-name
-                                                " to current list"
-                                                " of tags tables? ")))
-                         ;; Add it to the current list.
-                         (setq tags-table-list (cons tags-file-name
-                                                     tags-table-list))
-                       ;; Make a fresh list, and store the old one.
-                       (or (memq tags-table-list tags-table-set-list)
-                           (setq tags-table-set-list
-                                 (cons tags-table-list tags-table-set-list)))
-                       (setq tags-table-list (list tags-file-name)))
-                     (setq elt tags-table-list))))
-
-             ;; Set the tags table list state variables to point at the table
-             ;; we want to use first.
-             (setq tags-table-list-started-at elt
-                   tags-table-list-pointer elt)))
-
-         ;; Return of t says the tags table is valid.
-         t)
-
-      ;; The buffer was not valid.  Don't use it again.
-      (let ((file tags-file-name))
-       (kill-local-variable 'tags-file-name)
-       (if (eq file tags-file-name)
-           (setq tags-file-name nil)))
-      (error "File %s is not a valid tags table" buffer-file-name))))
+                                   (cons tags-table-list tags-table-set-list)))
+                         (setq tags-table-list (list tags-file-name)))
+                       (setq elt tags-table-list))))
+
+               ;; Set the tags table list state variables to point at the table
+               ;; we want to use first.
+               (setq tags-table-list-started-at elt
+                     tags-table-list-pointer elt)))
+
+           ;; Return of t says the tags table is valid.
+           t)
+
+       ;; The buffer was not valid.  Don't use it again.
+       (let ((file tags-file-name))
+         (kill-local-variable 'tags-file-name)
+         (if (eq file tags-file-name)
+             (setq tags-file-name nil)))
+       (error "File %s is not a valid tags table" buffer-file-name)))))
 \f
 (defun file-of-tag ()
   "Return the file name of the file whose tags point is within.
@@ -910,17 +918,17 @@ See documentation of variable `tags-file-name'."
       ;;   \1 is the string to match;
       ;;   \2 is not interesting;
       ;;   \3 is the guessed tag name; XXX guess should be better eg DEFUN
-      ;;   \4 is the char to start searching at;
-      ;;   \5 is the line to start searching at;
-      ;;   \6 is not interesting;
-      ;;   \7 is the explicitly-specified tag name.
+      ;;   \4 is not interesting;
+      ;;   \5 is the explicitly-specified tag name.
+      ;;   \6 is the line to start searching at;
+      ;;   \7 is the char to start searching at.
       (while (re-search-forward
-             "^\\(\\(.+[ \t]+\\)?\\([-a-zA-Z0-9_$]+\\)[^-a-zA-Z0-9_$]*\\)\177\
-\\([0-9]+\\),\\([0-9]+\\)\\(,\001\\([^\n]+\\)\\)?\n"
+             "^\\(\\(.+[^-a-zA-Z0-9_$]+\\)?\\([-a-zA-Z0-9_$]+\\)\
+\[^-a-zA-Z0-9_$]*\\)\177\\(\\([^\n\001]+\\)\001\\)?\\([0-9]+\\),\\([0-9]+\\)\n"
              nil t)
-       (intern (if (match-beginning 6)
+       (intern (if (match-beginning 5)
                    ;; There is an explicit tag name.
-                   (buffer-substring (match-beginning 6) (match-end 6))
+                   (buffer-substring (match-beginning 5) (match-end 5))
                  ;; No explicit tag name.  Best guess.
                  (buffer-substring (match-beginning 3) (match-end 3)))
                table)))
@@ -932,6 +940,8 @@ See documentation of variable `tags-file-name'."
     (setq tag-text (buffer-substring (1- (point))
                                     (save-excursion (beginning-of-line)
                                                     (point))))
+    ;; Skip explicit tag name if present.
+    (search-forward "\001" (save-excursion (forward-line 1) (point)) t)
     (search-forward ",")
     (setq startpos (string-to-int (buffer-substring
                                   (point)
@@ -949,7 +959,9 @@ See documentation of variable `tags-file-name'."
        ;; costs about as much as searching 2000 chars.
        (offset 1000)
        (found nil)
-       (pat (concat "^" (regexp-quote (car tag-info)))))
+       (pat (concat (if (eq selective-display t)
+                        "\\(^\\|\^m\\)" "^")
+                    (regexp-quote (car tag-info)))))
     (or startpos
        (setq startpos (point-min)))
     (while (and (not found)
@@ -963,6 +975,11 @@ See documentation of variable `tags-file-name'."
        (re-search-forward pat nil t)
        (error "`%s' not found in %s; time to rerun etags"
               pat buffer-file-name)))
+  ;; Position point at the right place
+  ;; if the search string matched an extra Ctrl-m at the beginning.
+  (and (eq selective-display t)
+       (looking-at "\^m")
+       (forward-char 1))
   (beginning-of-line))
 
 (defun etags-list-tags (file)
@@ -1080,8 +1097,10 @@ See documentation of variable `tags-file-name'."
 ;;;###autoload
 (defun next-file (&optional initialize novisit)
   "Select next file among files in current tags table.
-Non-nil first argument (prefix arg, if interactive)
-initializes to the beginning of the list of files in the tags table.
+
+A first argument of t (prefix arg, if interactive) initializes to the
+beginning of the list of files in the tags table.  If the argument is
+neither nil nor t, it is evalled to initialize the list of files.
 
 Non-nil second argument NOVISIT means use a temporary buffer
  to save time and avoid uninteresting warnings.
@@ -1089,11 +1108,18 @@ Non-nil second argument NOVISIT means use a temporary buffer
 Value is nil if the file was already visited;
 if the file was newly read in, the value is the filename."
   (interactive "P")
-  (and initialize
-       (save-excursion
-        ;; Visit the tags table buffer to get its list of files.
-        (visit-tags-table-buffer)
-        (setq next-file-list (tags-table-files))))
+  (cond ((not initialize)
+        ;; Not the first run.
+        )
+       ((eq initialize t)
+        ;; Initialize the list from the tags table.
+        (save-excursion
+          ;; Visit the tags table buffer to get its list of files.
+          (visit-tags-table-buffer)
+          (setq next-file-list (tags-table-files))))
+       (t
+        ;; Initialize the list by evalling the argument.
+        (setq next-file-list (eval initialize))))
   (or next-file-list
       (save-excursion
        ;; Get the files from the next tags table.
@@ -1131,7 +1157,8 @@ If it returns non-nil, this file needs processing by evalling
 ;;;###autoload
 (defun tags-loop-continue (&optional first-time)
   "Continue last \\[tags-search] or \\[tags-query-replace] command.
-Used noninteractively with non-nil argument to begin such a command.
+Used noninteractively with non-nil argument to begin such a command (the
+argument is passed to `next-file', which see).
 Two variables control the processing we do on each file:
 the value of `tags-loop-scan' is a form to be executed on each file
 to see if it is interesting (it returns non-nil if so)
@@ -1177,7 +1204,7 @@ If the latter returns non-nil, we exit; otherwise we scan the next file."
 ;;;###autoload (define-key esc-map "," 'tags-loop-continue)
 
 ;;;###autoload
-(defun tags-search (regexp)
+(defun tags-search (regexp &optional file-list-form)
   "Search through all files listed in tags table for match for REGEXP.
 Stops when a match is found.
 To continue searching for next match, use command \\[tags-loop-continue].
@@ -1192,10 +1219,10 @@ See documentation of variable `tags-file-name'."
     (setq tags-loop-scan
          (list 're-search-forward regexp nil t)
          tags-loop-operate nil)
-    (tags-loop-continue t)))
+    (tags-loop-continue (or file-list-form t))))
 
 ;;;###autoload
-(defun tags-query-replace (from to &optional delimited)
+(defun tags-query-replace (from to &optional delimited file-list-form)
   "Query-replace-regexp FROM with TO through all files listed in tags table.
 Third arg DELIMITED (prefix arg) means replace only word-delimited matches.
 If you exit (\\[keyboard-quit] or ESC), you can resume the query-replace
@@ -1211,7 +1238,7 @@ See documentation of variable `tags-file-name'."
                                   ;; will see it.
                                   '(goto-char (match-beginning 0))))
        tags-loop-operate (list 'perform-replace from to t t delimited))
-  (tags-loop-continue t))
+  (tags-loop-continue (or file-list-form t)))
 \f
 ;;;###autoload
 (defun list-tags (file)