Mercurial > emacs
changeset 342:8bfd98a0dcdd
Initial revision
author | Jim Blandy <jimb@redhat.com> |
---|---|
date | Sun, 21 Jul 1991 11:19:26 +0000 |
parents | 84ec93d39015 |
children | 5d45fc2b81e9 |
files | lisp/progmodes/etags.el |
diffstat | 1 files changed, 303 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lisp/progmodes/etags.el Sun Jul 21 11:19:26 1991 +0000 @@ -0,0 +1,303 @@ +;; Tags facility for Emacs. +;; Copyright (C) 1985, 1986, 1988 Free Software Foundation, Inc. + +;; This file is part of GNU Emacs. + +;; GNU Emacs 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 1, or (at your option) +;; any later version. + +;; GNU Emacs 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 GNU Emacs; see the file COPYING. If not, write to +;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + + +(provide 'tags) + +(defvar tag-table-files nil + "List of file names covered by current tag table. +nil means it has not been computed yet; do (tag-table-files) to compute it.") + +(defvar last-tag nil + "Tag found by the last find-tag.") + +(defun visit-tags-table (file) + "Tell tags commands to use tag table file FILE. +FILE should be the name of a file created with the `etags' program. +A directory name is ok too; it means file TAGS in that directory." + (interactive (list (read-file-name "Visit tags table: (default TAGS) " + default-directory + (concat default-directory "TAGS") + t))) + (setq file (expand-file-name file)) + (if (file-directory-p file) + (setq file (concat file "TAGS"))) + (setq tag-table-files nil + tags-file-name file)) + +(defun visit-tags-table-buffer () + "Select the buffer containing the current tag table. +This is a file whose name is in the variable tags-file-name." + (or tags-file-name + (call-interactively 'visit-tags-table)) + (set-buffer (or (get-file-buffer tags-file-name) + (progn + (setq tag-table-files nil) + (find-file-noselect tags-file-name)))) + (or (verify-visited-file-modtime (get-file-buffer tags-file-name)) + (cond ((yes-or-no-p "Tags file has changed, read new contents? ") + (revert-buffer t t) + (setq tag-table-files nil)))) + (or (eq (char-after 1) ?\^L) + (error "File %s not a valid tag table" tags-file-name))) + +(defun file-of-tag () + "Return the file name of the file whose tags point is within. +Assumes the tag table is the current buffer. +File name returned is relative to tag table file's directory." + (let ((opoint (point)) + prev size) + (save-excursion + (goto-char (point-min)) + (while (< (point) opoint) + (forward-line 1) + (end-of-line) + (skip-chars-backward "^,\n") + (setq prev (point)) + (setq size (read (current-buffer))) + (goto-char prev) + (forward-line 1) + (forward-char size)) + (goto-char (1- prev)) + (buffer-substring (point) + (progn (beginning-of-line) (point)))))) + +(defun tag-table-files () + "Return a list of files in the current tag table. +File names returned are absolute." + (save-excursion + (visit-tags-table-buffer) + (or tag-table-files + (let (files) + (goto-char (point-min)) + (while (not (eobp)) + (forward-line 1) + (end-of-line) + (skip-chars-backward "^,\n") + (setq prev (point)) + (setq size (read (current-buffer))) + (goto-char prev) + (setq files (cons (expand-file-name + (buffer-substring (1- (point)) + (save-excursion + (beginning-of-line) + (point))) + (file-name-directory tags-file-name)) + files)) + (forward-line 1) + (forward-char size)) + (setq tag-table-files (nreverse files)))))) + +;; Return a default tag to search for, based on the text at point. +(defun find-tag-default () + (save-excursion + (while (looking-at "\\sw\\|\\s_") + (forward-char 1)) + (if (re-search-backward "\\sw\\|\\s_" nil t) + (progn (forward-char 1) + (buffer-substring (point) + (progn (forward-sexp -1) + (while (looking-at "\\s'") + (forward-char 1)) + (point)))) + nil))) + +(defun find-tag-tag (string) + (let* ((default (find-tag-default)) + (spec (read-string + (if default + (format "%s(default %s) " string default) + string)))) + (list (if (equal spec "") + default + spec)))) + +(defun find-tag (tagname &optional next other-window) + "Find tag (in current tag table) whose name contains TAGNAME. + Selects the buffer that the tag is contained in +and puts point at its definition. + If TAGNAME is a null string, the expression in the buffer +around or before point is used as the tag name. + If second arg NEXT is non-nil (interactively, with prefix arg), +searches for the next tag in the tag table +that matches the tagname used in the previous find-tag. + +See documentation of variable tags-file-name." + (interactive (if current-prefix-arg + '(nil t) + (find-tag-tag "Find tag: "))) + (let (buffer file linebeg startpos) + (save-excursion + (visit-tags-table-buffer) + (if (not next) + (goto-char (point-min)) + (setq tagname last-tag)) + (setq last-tag tagname) + (while (progn + (if (not (search-forward tagname nil t)) + (error "No %sentries containing %s" + (if next "more " "") tagname)) + (not (looking-at "[^\n\177]*\177")))) + (search-forward "\177") + (setq file (expand-file-name (file-of-tag) + (file-name-directory tags-file-name))) + (setq linebeg + (buffer-substring (1- (point)) + (save-excursion (beginning-of-line) (point)))) + (search-forward ",") + (setq startpos (read (current-buffer)))) + (if other-window + (find-file-other-window file) + (find-file file)) + (widen) + (push-mark) + (let ((offset 1000) + found + (pat (concat "^" (regexp-quote linebeg)))) + (or startpos (setq startpos (point-min))) + (while (and (not found) + (progn + (goto-char (- startpos offset)) + (not (bobp)))) + (setq found + (re-search-forward pat (+ startpos offset) t)) + (setq offset (* 3 offset))) + (or found + (re-search-forward pat nil t) + (error "%s not found in %s" pat file))) + (beginning-of-line)) + (setq tags-loop-form '(find-tag nil t)) + ;; Return t in case used as the tags-loop-form. + t) + +(defun find-tag-other-window (tagname &optional next) + "Find tag (in current tag table) whose name contains TAGNAME. + Selects the buffer that the tag is contained in in another window +and puts point at its definition. + If TAGNAME is a null string, the expression in the buffer +around or before point is used as the tag name. + If second arg NEXT is non-nil (interactively, with prefix arg), +searches for the next tag in the tag table +that matches the tagname used in the previous find-tag. + +See documentation of variable tags-file-name." + (interactive (if current-prefix-arg + '(nil t) + (find-tag-tag "Find tag other window: "))) + (find-tag tagname next t)) + +(defvar next-file-list nil + "List of files for next-file to process.") + +(defun next-file (&optional initialize) + "Select next file among files in current tag table. +Non-nil argument (prefix arg, if interactive) +initializes to the beginning of the list of files in the tag table." + (interactive "P") + (if initialize + (setq next-file-list (tag-table-files))) + (or next-file-list + (error "All files processed.")) + (find-file (car next-file-list)) + (setq next-file-list (cdr next-file-list))) + +(defvar tags-loop-form nil + "Form for tags-loop-continue to eval to process one file. +If it returns nil, it is through with one file; move on to next.") + +(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. See variable tags-loop-form." + (interactive) + (if first-time + (progn (next-file t) + (goto-char (point-min)))) + (while (not (eval tags-loop-form)) + (next-file) + (message "Scanning file %s..." buffer-file-name) + (goto-char (point-min)))) + +(defun tags-search (regexp) + "Search through all files listed in tag table for match for REGEXP. +Stops when a match is found. +To continue searching for next match, use command \\[tags-loop-continue]. + +See documentation of variable tags-file-name." + (interactive "sTags search (regexp): ") + (if (and (equal regexp "") + (eq (car tags-loop-form) 're-search-forward)) + (tags-loop-continue nil) + (setq tags-loop-form + (list 're-search-forward regexp nil t)) + (tags-loop-continue t))) + +(defun tags-query-replace (from to &optional delimited) + "Query-replace-regexp FROM with TO through all files listed in tag table. +Third arg DELIMITED (prefix arg) means replace only word-delimited matches. +If you exit (C-G or ESC), you can resume the query-replace +with the command \\[tags-loop-continue]. + +See documentation of variable tags-file-name." + (interactive "sTags query replace (regexp): \nsTags query replace %s by: \nP") + (setq tags-loop-form + (list 'and (list 'save-excursion + (list 're-search-forward from nil t)) + (list 'not (list 'perform-replace from to t t + (not (null delimited)))))) + (tags-loop-continue t)) + +(defun list-tags (string) + "Display list of tags in file FILE. +FILE should not contain a directory spec +unless it has one in the tag table." + (interactive "sList tags (in file): ") + (with-output-to-temp-buffer "*Tags List*" + (princ "Tags in file ") + (princ string) + (terpri) + (save-excursion + (visit-tags-table-buffer) + (goto-char 1) + (search-forward (concat "\f\n" string ",")) + (forward-line 1) + (while (not (or (eobp) (looking-at "\f"))) + (princ (buffer-substring (point) + (progn (skip-chars-forward "^\177") + (point)))) + (terpri) + (forward-line 1))))) + +(defun tags-apropos (string) + "Display list of all tags in tag table REGEXP matches." + (interactive "sTag apropos (regexp): ") + (with-output-to-temp-buffer "*Tags List*" + (princ "Tags matching regexp ") + (prin1 string) + (terpri) + (save-excursion + (visit-tags-table-buffer) + (goto-char 1) + (while (re-search-forward string nil t) + (beginning-of-line) + (princ (buffer-substring (point) + (progn (skip-chars-forward "^\177") + (point)))) + (terpri) + (forward-line 1)))))