home *** CD-ROM | disk | FTP | other *** search
/ OpenStep 4.2J (Developer) / os42jdev.iso / NextDeveloper / Source / GNU / emacs / lisp / tags.el < prev    next >
Lisp/Scheme  |  1992-07-02  |  10KB  |  305 lines

  1. ;; Tags facility for Emacs.
  2. ;; Copyright (C) 1985, 1986, 1988 Free Software Foundation, Inc.
  3.  
  4. ;; This file is part of GNU Emacs.
  5.  
  6. ;; GNU Emacs is free software; you can redistribute it and/or modify
  7. ;; it under the terms of the GNU General Public License as published by
  8. ;; the Free Software Foundation; either version 1, or (at your option)
  9. ;; any later version.
  10.  
  11. ;; GNU Emacs is distributed in the hope that it will be useful,
  12. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. ;; GNU General Public License for more details.
  15.  
  16. ;; You should have received a copy of the GNU General Public License
  17. ;; along with GNU Emacs; see the file COPYING.  If not, write to
  18. ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  
  20.  
  21. (provide 'tags)
  22.  
  23. (defvar tag-table-files nil
  24.   "List of file names covered by current tag table.
  25. nil means it has not been computed yet; do (tag-table-files) to compute it.")
  26.  
  27. (defvar last-tag nil
  28.   "Tag found by the last find-tag.")
  29.  
  30. (defun visit-tags-table (file)
  31.   "Tell tags commands to use tag table file FILE.
  32. FILE should be the name of a file created with the `etags' program.
  33. A directory name is ok too; it means file TAGS in that directory."
  34.   (interactive (list (read-file-name "Visit tags table: (default TAGS) "
  35.                      default-directory
  36.                      (concat default-directory "TAGS")
  37.                      t)))
  38.   (setq file (expand-file-name file))
  39.   (if (file-directory-p file)
  40.       (setq file (concat file "TAGS")))
  41.   (setq tag-table-files nil
  42.     tags-file-name file))
  43.  
  44. (defun visit-tags-table-buffer ()
  45.   "Select the buffer containing the current tag table.
  46. This is a file whose name is in the variable tags-file-name."
  47.   (or tags-file-name
  48.       (call-interactively 'visit-tags-table))
  49.   (set-buffer (or (get-file-buffer tags-file-name)
  50.           (progn
  51.             (setq tag-table-files nil)
  52.             (find-file-noselect tags-file-name))))
  53.   (setq tags-file-name buffer-file-name)
  54.   (or (verify-visited-file-modtime (get-file-buffer tags-file-name))
  55.       (cond ((yes-or-no-p "Tags file has changed, read new contents? ")
  56.          (revert-buffer t t)
  57.          (setq tag-table-files nil))))
  58.   (or (eq (char-after 1) ?\^L)
  59.       (error "File %s not a valid tag table" tags-file-name)))
  60.  
  61. (defun file-of-tag ()
  62.   "Return the file name of the file whose tags point is within.
  63. Assumes the tag table is the current buffer.
  64. File name returned is relative to tag table file's directory."
  65.   (let ((opoint (point))
  66.     prev size)
  67.     (save-excursion
  68.      (goto-char (point-min))
  69.      (while (< (point) opoint)
  70.        (forward-line 1)
  71.        (end-of-line)
  72.        (skip-chars-backward "^,\n")
  73.        (setq prev (point))
  74.        (setq size (read (current-buffer)))
  75.        (goto-char prev)
  76.        (forward-line 1)
  77.        (forward-char size))
  78.      (goto-char (1- prev))
  79.      (buffer-substring (point)
  80.                (progn (beginning-of-line) (point))))))
  81.  
  82. (defun tag-table-files ()
  83.   "Return a list of files in the current tag table.
  84. File names returned are absolute."
  85.   (save-excursion
  86.    (visit-tags-table-buffer)
  87.    (or tag-table-files
  88.        (let (files)
  89.     (goto-char (point-min))
  90.     (while (not (eobp))
  91.       (forward-line 1)
  92.       (end-of-line)
  93.       (skip-chars-backward "^,\n")
  94.       (setq prev (point))
  95.       (setq size (read (current-buffer)))
  96.       (goto-char prev)
  97.       (setq files (cons (expand-file-name
  98.                  (buffer-substring (1- (point))
  99.                            (save-excursion
  100.                          (beginning-of-line)
  101.                          (point)))
  102.                  (file-name-directory tags-file-name))
  103.                 files))
  104.       (forward-line 1)
  105.       (forward-char size))
  106.     (setq tag-table-files (nreverse files))))))
  107.  
  108. ;; Return a default tag to search for, based on the text at point.
  109. (defun find-tag-default ()
  110.   (save-excursion
  111.     (while (looking-at "\\sw\\|\\s_")
  112.       (forward-char 1))
  113.     (if (re-search-backward "\\sw\\|\\s_" nil t)
  114.     (progn (forward-char 1)
  115.            (buffer-substring (point)
  116.                  (progn (forward-sexp -1)
  117.                     (while (looking-at "\\s'")
  118.                       (forward-char 1))
  119.                     (point))))
  120.       nil)))
  121.  
  122. (defun find-tag-tag (string)
  123.   (let* ((default (find-tag-default))
  124.      (spec (read-string
  125.         (if default
  126.             (format "%s(default %s) " string default)
  127.           string))))
  128.     (list (if (equal spec "")
  129.           default
  130.         spec))))
  131.  
  132. (defun find-tag (tagname &optional next other-window)
  133.   "Find tag (in current tag table) whose name contains TAGNAME.
  134.  Selects the buffer that the tag is contained in
  135. and puts point at its definition.
  136.  If TAGNAME is a null string, the expression in the buffer
  137. around or before point is used as the tag name.
  138.  If second arg NEXT is non-nil (interactively, with prefix arg),
  139. searches for the next tag in the tag table
  140. that matches the tagname used in the previous find-tag.
  141.  
  142. See documentation of variable tags-file-name."
  143.   (interactive (if current-prefix-arg
  144.            '(nil t)
  145.          (find-tag-tag "Find tag: ")))
  146.   (let (buffer file linebeg startpos)
  147.     (save-excursion
  148.      (visit-tags-table-buffer)
  149.      (if (not next)
  150.      (goto-char (point-min))
  151.        (setq tagname last-tag))
  152.      (setq last-tag tagname)
  153.      (while (progn
  154.           (if (not (search-forward tagname nil t))
  155.           (error "No %sentries containing %s"
  156.              (if next "more " "") tagname))
  157.           (not (looking-at "[^\n\177]*\177"))))
  158.      (search-forward "\177")
  159.      (setq file (expand-file-name (file-of-tag)
  160.                   (file-name-directory tags-file-name)))
  161.      (setq linebeg
  162.        (buffer-substring (1- (point))
  163.                  (save-excursion (beginning-of-line) (point))))
  164.      (search-forward ",")
  165.      (setq startpos (read (current-buffer))))
  166.     (if other-window
  167.     (find-file-other-window file)
  168.       (find-file file))
  169.     (widen)
  170.     (push-mark)
  171.     (let ((offset 1000)
  172.       found
  173.       (pat (concat "^" (regexp-quote linebeg))))
  174.       (or startpos (setq startpos (point-min)))
  175.       (while (and (not found)
  176.           (progn
  177.            (goto-char (- startpos offset))
  178.            (not (bobp))))
  179.     (setq found
  180.           (re-search-forward pat (+ startpos offset) t))
  181.     (setq offset (* 3 offset)))
  182.       (or found
  183.       (re-search-forward pat nil t)
  184.       (error "%s not found in %s" pat file)))
  185.     (beginning-of-line))
  186.   (setq tags-loop-form '(find-tag nil t))
  187.   ;; Return t in case used as the tags-loop-form.
  188.   t)
  189.  
  190. (defun find-tag-other-window (tagname &optional next)
  191.   "Find tag (in current tag table) whose name contains TAGNAME.
  192.  Selects the buffer that the tag is contained in in another window
  193. and puts point at its definition.
  194.  If TAGNAME is a null string, the expression in the buffer
  195. around or before point is used as the tag name.
  196.  If second arg NEXT is non-nil (interactively, with prefix arg),
  197. searches for the next tag in the tag table
  198. that matches the tagname used in the previous find-tag.
  199.  
  200. See documentation of variable tags-file-name."
  201.   (interactive (if current-prefix-arg
  202.            '(nil t)
  203.            (find-tag-tag "Find tag other window: ")))
  204.   (find-tag tagname next t))
  205.  
  206. (defvar next-file-list nil
  207.   "List of files for next-file to process.")
  208.  
  209. (defun next-file (&optional initialize)
  210.   "Select next file among files in current tag table.
  211. Non-nil argument (prefix arg, if interactive)
  212. initializes to the beginning of the list of files in the tag table."
  213.   (interactive "P")
  214.   (if initialize
  215.       (setq next-file-list (tag-table-files)))
  216.   (or next-file-list
  217.       (error "All files processed."))
  218.   (find-file (car next-file-list))
  219.   (setq next-file-list (cdr next-file-list)))
  220.  
  221. (defvar tags-loop-form nil
  222.   "Form for tags-loop-continue to eval to process one file.
  223. If it returns nil, it is through with one file; move on to next.")
  224.  
  225. (defun tags-loop-continue (&optional first-time)
  226.   "Continue last \\[tags-search] or \\[tags-query-replace] command.
  227. Used noninteractively with non-nil argument
  228. to begin such a command.  See variable tags-loop-form."
  229.   (interactive)
  230.   (if first-time
  231.       (progn (next-file t)
  232.          (goto-char (point-min))))
  233.   (while (not (eval tags-loop-form))
  234.     (next-file)
  235.     (message "Scanning file %s..." buffer-file-name)
  236.     (goto-char (point-min))))
  237.  
  238. (defun tags-search (regexp)
  239.   "Search through all files listed in tag table for match for REGEXP.
  240. Stops when a match is found.
  241. To continue searching for next match, use command \\[tags-loop-continue].
  242.  
  243. See documentation of variable tags-file-name."
  244.   (interactive "sTags search (regexp): ")
  245.   (if (and (equal regexp "")
  246.        (eq (car tags-loop-form) 're-search-forward))
  247.       (tags-loop-continue nil)
  248.     (setq tags-loop-form
  249.       (list 're-search-forward regexp nil t))
  250.     (tags-loop-continue t)))
  251.  
  252. (defun tags-query-replace (from to &optional delimited)
  253.   "Query-replace-regexp FROM with TO through all files listed in tag table.
  254. Third arg DELIMITED (prefix arg) means replace only word-delimited matches.
  255. If you exit (C-G or ESC), you can resume the query-replace
  256. with the command \\[tags-loop-continue].
  257.  
  258. See documentation of variable tags-file-name."
  259.   (interactive "sTags query replace (regexp): \nsTags query replace %s by: \nP")
  260.   (setq tags-loop-form
  261.     (list 'and (list 'save-excursion
  262.              (list 're-search-forward from nil t))
  263.           (list 'not (list 'perform-replace from to t t 
  264.                    (not (null delimited))))))
  265.   (tags-loop-continue t))
  266.  
  267. (defun list-tags (string)
  268.   "Display list of tags in file FILE.
  269. FILE should not contain a directory spec
  270. unless it has one in the tag table."
  271.   (interactive "sList tags (in file): ")
  272.   (with-output-to-temp-buffer "*Tags List*"
  273.     (princ "Tags in file ")
  274.     (princ string)
  275.     (terpri)
  276.     (save-excursion
  277.      (visit-tags-table-buffer)
  278.      (goto-char 1)
  279.      (search-forward (concat "\f\n" string ","))
  280.      (forward-line 1)
  281.      (while (not (or (eobp) (looking-at "\f")))
  282.        (princ (buffer-substring (point)
  283.                 (progn (skip-chars-forward "^\177")
  284.                        (point))))
  285.        (terpri)
  286.        (forward-line 1)))))
  287.  
  288. (defun tags-apropos (string)
  289.   "Display list of all tags in tag table REGEXP matches."
  290.   (interactive "sTag apropos (regexp): ")
  291.   (with-output-to-temp-buffer "*Tags List*"
  292.     (princ "Tags matching regexp ")
  293.     (prin1 string)
  294.     (terpri)
  295.     (save-excursion
  296.      (visit-tags-table-buffer)
  297.      (goto-char 1)
  298.      (while (re-search-forward string nil t)
  299.        (beginning-of-line)
  300.        (princ (buffer-substring (point)
  301.                 (progn (skip-chars-forward "^\177")
  302.                        (point))))
  303.        (terpri)
  304.        (forward-line 1)))))
  305.