--- /dev/null
+;;; multifile.el --- Operations on multiple files -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2018 Free Software Foundation, Inc.
+
+;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
+
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation, either version 3 of the License, or
+;; (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; Support functions for operations like search or query&replace applied to
+;; several files. This code was largely inspired&extracted from an earlier
+;; version of etags.el.
+
+;; TODO:
+;; - Maybe it would make sense to replace the multifile--* vars with a single
+;; global var holding a struct, and then stash those structs into a history
+;; of past operations, so you can perform a multifile-search while in the
+;; middle of a multifile-replace and later go back to that
+;; multifile-replace.
+;; - Make multi-isearch work on top of this library (might require changes
+;; to this library, of course).
+
+;;; Code:
+
+(require 'generator)
+
+(defgroup multifile nil
+ "Operations on multiple files."
+ :group 'tools)
+
+(defcustom multifile-revert-buffers 'silent
+ "Whether to revert files during multifile operation.
+ `silent' means to only do it if `revert-without-query' is applicable;
+ t means to offer to do it for all applicable files;
+ nil means never to do it"
+ :type '(choice (const silent) (const t) (const nil)))
+
+;; FIXME: This already exists in GNU ELPA's iterator.el. Maybe it should move
+;; to generator.el?
+(iter-defun multifile--list-to-iterator (list)
+ (while list (iter-yield (pop list))))
+
+(defvar multifile--iterator iter-empty)
+(defvar multifile--scan-function
+ (lambda () (user-error "No operation in progress")))
+(defvar multifile--operate-function #'ignore)
+(defvar multifile--freshly-initialized nil)
+
+;;;###autoload
+(defun multifile-initialize (files scan-function operate-function)
+ "Initialize a new round of operation on several files.
+FILES can be either a list of file names, or an iterator (used with `iter-next')
+which returns a file name at each step.
+SCAN-FUNCTION is a function called with no argument inside a buffer
+and it should return non-nil if that buffer has something on which to operate.
+OPERATE-FUNCTION is a function called with no argument; it is expected
+to perform the operation on the current file buffer and when done
+should return non-nil to mean that we should immediately continue
+operating on the next file and nil otherwise."
+ (setq multifile--iterator
+ (if (and (listp files) (not (functionp files)))
+ (multifile--list-to-iterator files)
+ files))
+ (setq multifile--scan-function scan-function)
+ (setq multifile--operate-function operate-function)
+ (setq multifile--freshly-initialized t))
+
+(defun multifile-next-file (&optional novisit)
+ ;; FIXME: Should we provide an interactive command, like tags-next-file?
+ (let ((next (condition-case nil
+ (iter-next multifile--iterator)
+ (iter-end-of-sequence nil))))
+ (unless next
+ (and novisit
+ (get-buffer " *next-file*")
+ (kill-buffer " *next-file*"))
+ (user-error "All files processed"))
+ (let* ((buffer (get-file-buffer next))
+ (new (not buffer)))
+ ;; Optionally offer to revert buffers
+ ;; if the files have changed on disk.
+ (and buffer multifile-revert-buffers
+ (not (verify-visited-file-modtime buffer))
+ (if (eq multifile-revert-buffers 'silent)
+ (and (not (buffer-modified-p buffer))
+ (let ((revertible nil))
+ (dolist (re revert-without-query)
+ (when (string-match-p re next)
+ (setq revertible t)))
+ revertible))
+ (y-or-n-p
+ (format
+ (if (buffer-modified-p buffer)
+ "File %s changed on disk. Discard your edits? "
+ "File %s changed on disk. Reread from disk? ")
+ next)))
+ (with-current-buffer buffer
+ (revert-buffer t t)))
+ (if (not (and new novisit))
+ (set-buffer (find-file-noselect next))
+ ;; Like find-file, but avoids random warning messages.
+ (set-buffer (get-buffer-create " *next-file*"))
+ (kill-all-local-variables)
+ (erase-buffer)
+ (setq new next)
+ (insert-file-contents new nil))
+ new)))
+
+(defun multifile-continue ()
+ "Continue last multi-file operation."
+ (interactive)
+ (let (new
+ ;; Non-nil means we have finished one file
+ ;; and should not scan it again.
+ file-finished
+ original-point
+ (messaged nil))
+ (while
+ (progn
+ ;; Scan files quickly for the first or next interesting one.
+ ;; This starts at point in the current buffer.
+ (while (or multifile--freshly-initialized file-finished
+ (save-restriction
+ (widen)
+ (not (funcall multifile--scan-function))))
+ ;; If nothing was found in the previous file, and
+ ;; that file isn't in a temp buffer, restore point to
+ ;; where it was.
+ (when original-point
+ (goto-char original-point))
+
+ (setq file-finished nil)
+ (setq new (multifile-next-file t))
+
+ ;; If NEW is non-nil, we got a temp buffer,
+ ;; and NEW is the file name.
+ (when (or messaged
+ (and (not multifile--freshly-initialized)
+ (> baud-rate search-slow-speed)
+ (setq messaged t)))
+ (message "Scanning file %s..." (or new buffer-file-name)))
+
+ (setq multifile--freshly-initialized nil)
+ (setq original-point (if new nil (point)))
+ (goto-char (point-min)))
+
+ ;; If we visited it in a temp buffer, visit it now for real.
+ (if new
+ (let ((pos (point)))
+ (erase-buffer)
+ (set-buffer (find-file-noselect new))
+ (setq new nil) ;No longer in a temp buffer.
+ (widen)
+ (goto-char pos))
+ (push-mark original-point t))
+
+ (switch-to-buffer (current-buffer))
+
+ ;; Now operate on the file.
+ ;; If value is non-nil, continue to scan the next file.
+ (save-restriction
+ (widen)
+ (funcall multifile--operate-function)))
+ (setq file-finished t))))
+
+;;;###autoload
+(defun multifile-initialize-search (regexp files case-fold)
+ (let ((last-buffer (current-buffer)))
+ (multifile-initialize
+ files
+ (lambda ()
+ (let ((case-fold-search
+ (if (memq case-fold '(t nil)) case-fold case-fold-search)))
+ (re-search-forward regexp nil t)))
+ (lambda ()
+ (unless (eq last-buffer (current-buffer))
+ (setq last-buffer (current-buffer))
+ (message "Scanning file %s...found" buffer-file-name))
+ nil))))
+
+;;;###autoload
+(defun multifile-initialize-replace (from to files case-fold &optional delimited)
+ "Initialize a new round of query&replace on several files.
+FROM is a regexp and TO is the replacement to use.
+FILES describes the file, as in `multifile-initialize'.
+CASE-FOLD can be t, nil, or `default', the latter one meaning to obey
+the default setting of `case-fold-search'.
+DELIMITED if non-nil means replace only word-delimited matches."
+ ;; FIXME: Not sure how the delimited-flag interacts with the regexp-flag in
+ ;; `perform-replace', so I just try to mimic the old code.
+ (multifile-initialize
+ files
+ (lambda ()
+ (let ((case-fold-search
+ (if (memql case-fold '(nil t)) case-fold case-fold-search)))
+ (if (re-search-forward from nil t)
+ ;; When we find a match, move back
+ ;; to the beginning of it so perform-replace
+ ;; will see it.
+ (goto-char (match-beginning 0)))))
+ (lambda ()
+ (perform-replace from to t t delimited nil multi-query-replace-map))))
+
+(provide 'multifile)
+;;; multifile.el ends here
;;; Code:
+;; The namespacing of this package is a mess:
+;; - The file name is "etags", but the "exported" functionality doesn't use
+;; this name
+;; - Uses "etags-", "tags-", and "tag-" prefixes.
+;; - Many functions use "-tag-" or "-tags-", or even "-etags-" not as
+;; prefixes but somewhere within the name.
+
(require 'ring)
(require 'button)
(require 'xref)
+(require 'multifile)
;;;###autoload
(defvar tags-file-name nil
"Whether tags operations should be case-sensitive.
A value of t means case-insensitive, a value of nil means case-sensitive.
Any other value means use the setting of `case-fold-search'."
- :group 'etags
:type '(choice (const :tag "Case-sensitive" nil)
(const :tag "Case-insensitive" t)
(other :tag "Use default" default))
To switch to a new list of tags tables, setting this variable is sufficient.
If you set this variable, do not also set `tags-file-name'.
Use the `etags' program to make a tags table file."
- :group 'etags
:type '(repeat file))
;;;###autoload
"List of extensions tried by etags when `auto-compression-mode' is on.
An empty string means search the non-compressed file."
:version "24.1" ; added xz
- :type '(repeat string)
- :group 'etags)
+ :type '(repeat string))
;; !!! tags-compression-info-list should probably be replaced by access
;; to directory list and matching jka-compr-compression-info-list. Currently,
t means do; nil means don't (always start a new list).
Any other value means ask the user whether to add a new tags table
to the current list (as opposed to starting a new list)."
- :group 'etags
:type '(choice (const :tag "Do" t)
(const :tag "Don't" nil)
(other :tag "Ask" ask-user)))
(defcustom tags-revert-without-query nil
"Non-nil means reread a TAGS table without querying, if it has changed."
- :group 'etags
:type 'boolean)
(defvar tags-table-computed-list nil
"Hook to be run by \\[find-tag] after finding a tag. See `run-hooks'.
The value in the buffer in which \\[find-tag] is done is used,
not the value in the buffer \\[find-tag] goes to."
- :group 'etags
:type 'hook)
;;;###autoload
If nil, and the symbol that is the value of `major-mode'
has a `find-tag-default-function' property (see `put'), that is used.
Otherwise, `find-tag-default' is used."
- :group 'etags
:type '(choice (const nil) function))
(define-obsolete-variable-alias 'find-tag-marker-ring-length
(defcustom tags-tag-face 'default
"Face for tags in the output of `tags-apropos'."
- :group 'etags
:type 'face
:version "21.1")
(defcustom tags-apropos-verbose nil
"If non-nil, print the name of the tags file in the *Tags List* buffer."
- :group 'etags
:type 'boolean
:version "21.1")
((\"Emacs Lisp\" Info-goto-emacs-command-node obarray)
(\"Common Lisp\" common-lisp-hyperspec common-lisp-hyperspec-obarray)
(\"SCWM\" scwm-documentation scwm-obarray))"
- :group 'etags
:type '(repeat (list (string :tag "Title")
function
(sexp :tag "Tags to search")))
(defvar tags-included-tables nil
"List of tags tables included by the current tags table.")
-
-(defvar next-file-list nil
- "List of files for \\[next-file] to process.")
\f
;; Hooks for file formats.
(defun tags-table-check-computed-list ()
"Compute `tags-table-computed-list' from `tags-table-list' if necessary."
- (let ((expanded-list (mapcar 'tags-expand-table-name tags-table-list)))
+ (let ((expanded-list (mapcar #'tags-expand-table-name tags-table-list)))
(or (equal tags-table-computed-list-for expanded-list)
;; The list (or default-directory) has changed since last computed.
- (let* ((compute-for (mapcar 'copy-sequence expanded-list))
+ (let* ((compute-for (mapcar #'copy-sequence expanded-list))
(tables (copy-sequence compute-for)) ;Mutated in the loop.
(computed nil)
table-buffer)
(if (tags-included-tables)
;; Insert the included tables into the list we
;; are processing.
- (setcdr tables (nconc (mapcar 'tags-expand-table-name
+ (setcdr tables (nconc (mapcar #'tags-expand-table-name
(tags-included-tables))
(cdr tables))))))
;; This table is not in core yet. Insert a placeholder
;; Select the tags table buffer and get the file list up to date.
(let ((tags-file-name (car tables)))
(visit-tags-table-buffer 'same)
- (if (member this-file (mapcar 'expand-file-name
+ (if (member this-file (mapcar #'expand-file-name
(tags-table-files)))
;; Found it.
(setq found tables))))
(defun find-tag--default ()
(funcall (or find-tag-default-function
(get major-mode 'find-tag-default-function)
- 'find-tag-default)))
+ #'find-tag-default)))
(defvar last-tag nil
"Last tag found by \\[find-tag].")
(let ((bol (point)))
(and (search-forward "\177" (line-end-position) t)
(re-search-backward re bol t)))))
-\f
-(defcustom tags-loop-revert-buffers nil
- "Non-nil means tags-scanning loops should offer to reread changed files.
-These loops normally read each file into Emacs, but when a file
-is already visited, they use the existing buffer.
-When this flag is non-nil, they offer to revert the existing buffer
-in the case where the file has changed since you visited it."
- :type 'boolean
- :group 'etags)
+(define-obsolete-variable-alias 'tags-loop-revert-buffers 'multifile-revert-buffers "27.1")
;;;###autoload
-(defun next-file (&optional initialize novisit)
+(defalias 'next-file 'tags-next-file)
+(make-obsolete 'next-file
+ "use tags-next-file or multifile-initialize and multifile-next-file instead" "27.1")
+;;;###autoload
+(defun tags-next-file (&optional initialize novisit)
"Select next file among files in current tags table.
A first argument of t (prefix arg, if interactive) initializes to the
if the file was newly read in, the value is the filename."
;; Make the interactive arg t if there was any prefix arg.
(interactive (list (if current-prefix-arg t)))
- (cond ((not initialize)
- ;; Not the first run.
- )
- ((eq initialize t)
- ;; Initialize the list from the tags table.
- (save-excursion
- (let ((cbuf (current-buffer)))
- ;; Visit the tags table buffer to get its list of files.
- (visit-tags-table-buffer)
- ;; Copy the list so we can setcdr below, and expand the file
- ;; names while we are at it, in this buffer's default directory.
- (setq next-file-list (mapcar 'expand-file-name (tags-table-files)))
- ;; Iterate over all the tags table files, collecting
- ;; a complete list of referenced file names.
- (while (visit-tags-table-buffer t cbuf)
- ;; Find the tail of the working list and chain on the new
- ;; sublist for this tags table.
- (let ((tail next-file-list))
- (while (cdr tail)
- (setq tail (cdr tail)))
- ;; Use a copy so the next loop iteration will not modify the
- ;; list later returned by (tags-table-files).
- (if tail
- (setcdr tail (mapcar 'expand-file-name (tags-table-files)))
- (setq next-file-list (mapcar 'expand-file-name
- (tags-table-files)))))))))
- (t
- ;; Initialize the list by evalling the argument.
- (setq next-file-list (eval initialize))))
- (unless next-file-list
- (and novisit
- (get-buffer " *next-file*")
- (kill-buffer " *next-file*"))
- (user-error "All files processed"))
- (let* ((next (car next-file-list))
- (buffer (get-file-buffer next))
- (new (not buffer)))
- ;; Advance the list before trying to find the file.
- ;; If we get an error finding the file, don't get stuck on it.
- (setq next-file-list (cdr next-file-list))
- ;; Optionally offer to revert buffers
- ;; if the files have changed on disk.
- (and buffer tags-loop-revert-buffers
- (not (verify-visited-file-modtime buffer))
- (y-or-n-p
- (format
- (if (buffer-modified-p buffer)
- "File %s changed on disk. Discard your edits? "
- "File %s changed on disk. Reread from disk? ")
- next))
- (with-current-buffer buffer
- (revert-buffer t t)))
- (if (not (and new novisit))
- (find-file next)
- ;; Like find-file, but avoids random warning messages.
- (switch-to-buffer (get-buffer-create " *next-file*"))
- (kill-all-local-variables)
- (erase-buffer)
- (setq new next)
- (insert-file-contents new nil))
- new))
+ (when initialize ;; Not the first run.
+ (tags--compat-initialize initialize))
+ (multifile-next-file novisit)
+ (switch-to-buffer (current-buffer)))
+(defun tags--all-files ()
+ (save-excursion
+ (let ((cbuf (current-buffer))
+ (files nil))
+ ;; Visit the tags table buffer to get its list of files.
+ (visit-tags-table-buffer)
+ ;; Copy the list so we can setcdr below, and expand the file
+ ;; names while we are at it, in this buffer's default directory.
+ (setq files (mapcar #'expand-file-name (tags-table-files)))
+ ;; Iterate over all the tags table files, collecting
+ ;; a complete list of referenced file names.
+ (while (visit-tags-table-buffer t cbuf)
+ ;; Find the tail of the working list and chain on the new
+ ;; sublist for this tags table.
+ (let ((tail files))
+ (while (cdr tail)
+ (setq tail (cdr tail)))
+ ;; Use a copy so the next loop iteration will not modify the
+ ;; list later returned by (tags-table-files).
+ (setf (if tail (cdr tail) files)
+ (mapcar #'expand-file-name (tags-table-files)))))
+ files)))
+
+(make-obsolete-variable 'tags-loop-operate 'multifile-initialize "27.1")
(defvar tags-loop-operate nil
"Form for `tags-loop-continue' to eval to change one file.")
+(make-obsolete-variable 'tags-loop-scan 'multifile-initialize "27.1")
(defvar tags-loop-scan
'(user-error "%s"
(substitute-command-keys
case-fold-search)))
(eval form)))
+(defun tags--compat-files (files)
+ (cond
+ ((eq files t) (tags--all-files)) ;; Initialize the list from the tags table.
+ ((functionp files) files)
+ ((stringp (car-safe files)) files)
+ (t
+ ;; Backward compatibility <27.1
+ ;; Initialize the list by evalling the argument.
+ (eval files))))
+
+(defun tags--compat-initialize (initialize)
+ (multifile-initialize
+ (tags--compat-files initialize)
+ (if tags-loop-operate
+ (lambda () (tags-loop-eval tags-loop-operate))
+ (lambda () (message "Scanning file %s...found" buffer-file-name) nil))
+ (lambda () (tags-loop-eval tags-loop-scan))))
;;;###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 (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) and `tags-loop-operate' is a form to
-evaluate to operate on an interesting file. If the latter evaluates to
-nil, we exit; otherwise we scan the next file."
+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) and `tags-loop-operate' is a form to
+ ;; evaluate to operate on an interesting file. If the latter evaluates to
+ ;; nil, we exit; otherwise we scan the next file.
+ (declare (obsolete multifile-continue "27.1"))
(interactive)
- (let (new
- ;; Non-nil means we have finished one file
- ;; and should not scan it again.
- file-finished
- original-point
- (messaged nil))
- (while
- (progn
- ;; Scan files quickly for the first or next interesting one.
- ;; This starts at point in the current buffer.
- (while (or first-time file-finished
- (save-restriction
- (widen)
- (not (tags-loop-eval tags-loop-scan))))
- ;; If nothing was found in the previous file, and
- ;; that file isn't in a temp buffer, restore point to
- ;; where it was.
- (when original-point
- (goto-char original-point))
-
- (setq file-finished nil)
- (setq new (next-file first-time t))
-
- ;; If NEW is non-nil, we got a temp buffer,
- ;; and NEW is the file name.
- (when (or messaged
- (and (not first-time)
- (> baud-rate search-slow-speed)
- (setq messaged t)))
- (message "Scanning file %s..." (or new buffer-file-name)))
-
- (setq first-time nil)
- (setq original-point (if new nil (point)))
- (goto-char (point-min)))
+ (when first-time ;; Backward compatibility.
+ (tags--compat-initialize first-time))
+ (multifile-continue))
- ;; If we visited it in a temp buffer, visit it now for real.
- (if new
- (let ((pos (point)))
- (erase-buffer)
- (set-buffer (find-file-noselect new))
- (setq new nil) ;No longer in a temp buffer.
- (widen)
- (goto-char pos))
- (push-mark original-point t))
-
- (switch-to-buffer (current-buffer))
-
- ;; Now operate on the file.
- ;; If value is non-nil, continue to scan the next file.
- (save-restriction
- (widen)
- (tags-loop-eval tags-loop-operate)))
- (setq file-finished t))
- (and messaged
- (null tags-loop-operate)
- (message "Scanning file %s...found" buffer-file-name))))
+;; We use it to detect when the last loop was a tags-search.
+(defvar tags--last-search-operate-function nil)
;;;###autoload
-(defun tags-search (regexp &optional file-list-form)
+(defun tags-search (regexp &optional files)
"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].
-If FILE-LIST-FORM is non-nil, it should be a form that, when
-evaluated, will return a list of file names. The search will be
-restricted to these files.
+If FILES if non-nil should be a list or an iterator returning the files to search.
+The search will be restricted to these files.
Also see the documentation of the `tags-file-name' variable."
(interactive "sTags search (regexp): ")
- (if (and (equal regexp "")
- (eq (car tags-loop-scan) 're-search-forward)
- (null tags-loop-operate))
- ;; Continue last tags-search as if by M-,.
- (tags-loop-continue nil)
- (setq tags-loop-scan `(re-search-forward ',regexp nil t)
- tags-loop-operate nil)
- (tags-loop-continue (or file-list-form t))))
+ (unless (and (equal regexp "")
+ ;; FIXME: If some other multifile operation took place,
+ ;; rather than search for "", we should repeat the last search!
+ (eq multifile--operate-function
+ tags--last-search-operate-function))
+ (multifile-initialize-search
+ regexp
+ (tags--compat-files (or files t))
+ tags-case-fold-search)
+ ;; Store it, so we can detect if some other multifile operation took
+ ;; place since the last search!
+ (setq tags--last-search-operate-function multifile--operate-function))
+ (multifile-continue))
;;;###autoload
-(defun tags-query-replace (from to &optional delimited file-list-form)
+(defun tags-query-replace (from to &optional delimited files)
"Do `query-replace-regexp' of FROM with TO on all files listed in tags table.
Third arg DELIMITED (prefix arg) means replace only word-delimited matches.
If you exit (\\[keyboard-quit], RET or q), you can resume the query replace
with the command \\[tags-loop-continue].
-Fourth arg FILE-LIST-FORM non-nil means initialize the replacement loop.
-
-If FILE-LIST-FORM is non-nil, it is a form to evaluate to
-produce the list of files to search.
-
-See also the documentation of the variable `tags-file-name'."
+For non-interactive use, superceded by `multifile-initialize-replace'."
+ (declare (advertised-calling-convention (from to &optional delimited) "27.1"))
(interactive (query-replace-read-args "Tags query replace (regexp)" t t))
- (setq tags-loop-scan `(let ,(unless (equal from (downcase from))
- '((case-fold-search nil)))
- (if (re-search-forward ',from nil t)
- ;; When we find a match, move back
- ;; to the beginning of it so perform-replace
- ;; will see it.
- (goto-char (match-beginning 0))))
- tags-loop-operate `(perform-replace ',from ',to t t ',delimited
- nil multi-query-replace-map))
- (tags-loop-continue (or file-list-form t)))
-\f
+ (multifile-initialize-replace
+ from to
+ (tags--compat-files (or files t))
+ (if (equal from (downcase from)) nil 'default)
+ delimited)
+ (multifile-continue))
+
(defun tags-complete-tags-table-file (string predicate what) ; Doc string?
(save-excursion
;; If we need to ask for the tag table, allow that.
(funcall tags-apropos-function regexp))))
(etags-tags-apropos-additional regexp))
(with-current-buffer "*Tags List*"
- (eval-and-compile (require 'apropos))
+ (require 'apropos)
+ (declare-function apropos-mode "apropos")
(apropos-mode)
;; apropos-mode is derived from fundamental-mode and it kills
;; all local variables.
(when tags-table-list
(setq desired-point (point-marker))
(setq b (point))
- (princ (mapcar 'abbreviate-file-name tags-table-list) (current-buffer))
+ (princ (mapcar #'abbreviate-file-name tags-table-list) (current-buffer))
(make-text-button b (point) 'type 'tags-select-tags-table
'etags-table (car tags-table-list))
(insert "\n"))
(while set-list
(unless (eq (car set-list) tags-table-list)
(setq b (point))
- (princ (mapcar 'abbreviate-file-name (car set-list)) (current-buffer))
+ (princ (mapcar #'abbreviate-file-name (car set-list)) (current-buffer))
(make-text-button b (point) 'type 'tags-select-tags-table
'etags-table (car (car set-list)))
(insert "\n"))
'etags-table tags-file-name)
(insert "\n"))
(setq set-list (delete tags-file-name
- (apply 'nconc (cons (copy-sequence tags-table-list)
- (mapcar 'copy-sequence
- tags-table-set-list)))))
+ (apply #'nconc (cons (copy-sequence tags-table-list)
+ (mapcar #'copy-sequence
+ tags-table-set-list)))))
(while set-list
(setq b (point))
(insert (abbreviate-file-name (car set-list)))