home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #19 / NN_1992_19.iso / spool / comp / sources / misc / 3875 < prev    next >
Encoding:
Text File  |  1992-08-26  |  22.2 KB  |  642 lines

  1. Newsgroups: comp.sources.misc
  2. Path: sparky!kent
  3. From: kendall@centerline.com (Sam Kendall)
  4. Subject:  v31i125:  tags++ - etags/ctags for C and C++, version 1.1, Part02/03
  5. Message-ID: <1992Aug26.144927.3261@sparky.imd.sterling.com>
  6. Followup-To: comp.sources.d
  7. X-Md4-Signature: b3dab4dac18d416ab8bee0f012d3e5e0
  8. Sender: kent@sparky.imd.sterling.com (Kent Landfield)
  9. Organization: CenterLine Software, Inc.
  10. References: <csm-v31i124=tags++.094745@sparky.IMD.Sterling.COM>
  11. Date: Wed, 26 Aug 1992 14:49:27 GMT
  12. Approved: kent@sparky.imd.sterling.com
  13. Lines: 627
  14.  
  15. Submitted-by: kendall@centerline.com (Sam Kendall)
  16. Posting-number: Volume 31, Issue 125
  17. Archive-name: tags++/part02
  18. Environment: UNIX, GNU Emacs, vi
  19.  
  20. #! /bin/sh
  21. # This is a shell archive.  Remove anything before this line, then unpack
  22. # it by saving it into a file and typing "sh file".  To overwrite existing
  23. # files, type "sh file -c".  You can also feed this as standard input via
  24. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  25. # will see the following message at the end:
  26. #        "End of archive 2 (of 3)."
  27. # Contents:  tags.el
  28. # Wrapped by kendall@pen on Tue Aug 25 13:34:19 1992
  29. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  30. if test -f 'tags.el' -a "${1}" != "-c" ; then 
  31.   echo shar: Will not clobber existing file \"'tags.el'\"
  32. else
  33. echo shar: Extracting \"'tags.el'\" \(20187 characters\)
  34. sed "s/^X//" >'tags.el' <<'END_OF_FILE'
  35. X;; $Id: tags.el,v 1.14 1992/08/25 17:28:36 kendall Exp $
  36. X
  37. X;; Tags facility for Emacs.
  38. X;; Copyright (C) 1985, 1986, 1988 Free Software Foundation, Inc.
  39. X
  40. X;; GNU Emacs is distributed in the hope that it will be useful,
  41. X;; but WITHOUT ANY WARRANTY.  No author or distributor
  42. X;; accepts responsibility to anyone for the consequences of using it
  43. X;; or for whether it serves any particular purpose or works at all,
  44. X;; unless he says so in writing.  Refer to the GNU Emacs General Public
  45. X;; License for full details.
  46. X
  47. X;; Everyone is granted permission to copy, modify and redistribute
  48. X;; GNU Emacs, but only under the conditions described in the
  49. X;; GNU Emacs General Public License.   A copy of this license is
  50. X;; supposed to have been given to you along with GNU Emacs so you
  51. X;; can know your rights and responsibilities.  It should be in a
  52. X;; file named COPYING.  Among other things, the copyright notice
  53. X;; and this notice must be preserved on all copies.
  54. X
  55. X;; This version is maintained by Sam Kendall, CenterLine Software Inc.,
  56. X;; 10 Fawcett Street, Cambridge, MA 02138 USA.  Email is
  57. X;; kendall@CenterLine.COM or uunet!saber!kendall.
  58. X
  59. X;; NOTE:
  60. X;;     "Quick fix" inserted for C users.  The problem is that in the tags line
  61. X;;
  62. X;;        typedef char *string^?...
  63. X;;
  64. X;;    `string' won't be an exact match, because the `*' is a word character
  65. X;;    in the TAGS buffer (although not in a C source file).  The quick fix is
  66. X;;    in tag-exact-match-p; look for "HACK 7/19/89". -kendall@centerline.com
  67. X
  68. X(provide 'tags)
  69. X
  70. X;; Tag table state.
  71. X
  72. X(defun initialize-new-tag-table ()
  73. X  "Call when the tag table changes."
  74. X  (setq tag-table-files nil
  75. X    find-tag-state nil
  76. X    tag-order nil
  77. X    tag-lines-already-matched nil)
  78. X  (make-local-variable 'tags-completion-alist))
  79. X
  80. X(defun save-tags-state ()
  81. X  "Returns an object that can later be passed to `restore-tags-state'."
  82. X  (vector tag-order
  83. X      tag-lines-already-matched
  84. X      tag-table-files
  85. X      find-tag-state
  86. X      next-file-list))
  87. X
  88. X(defun restore-tags-state (state)
  89. X  "Restore from an object created by `save-tags-state'."
  90. X  (setq tag-order (aref state 0)
  91. X    tag-lines-already-matched (aref state 1)
  92. X    tag-table-files (aref state 2)
  93. X    find-tag-state (aref state 3)
  94. X    next-file-list (aref state 4)))
  95. X
  96. X(defvar tag-order nil
  97. X  "List of functions to use in partitioning the set of tag matches.")
  98. X
  99. X(defvar tag-lines-already-matched nil
  100. X  "List of lines within the tag table that are already matched.")
  101. X
  102. X(defvar tag-table-files nil
  103. X  "List of file names covered by current tags table.
  104. Xnil means it has not been computed yet; do (tag-table-files) to compute it.")
  105. X
  106. X(defvar tags-completion-alist nil
  107. X  "Alist of tag names defined in current tags table.")
  108. X
  109. X(defvar find-tag-state nil
  110. X  "Some of the state of the last find-tag, find-tag-other-window, or
  111. Xfind-tag-regexp.  This is a vector whose 0th element is the last tagname
  112. Xor regexp used.")
  113. X
  114. X(defvar tags-table-file-list nil
  115. X  "Alist of tags table file names for \\[select-tags-table].
  116. XEach element is a list containing one element, a file name.
  117. XAny tags table file you visit is automatically added to this list.
  118. XYou can also add names yourself.")
  119. X
  120. X(defvar next-file-list nil
  121. X  "List of files for \\[next-file] to process.")
  122. X
  123. X
  124. X
  125. X(defun visit-tags-table (file)
  126. X  "Tell tags commands to use tags table file FILE.
  127. XFILE should be the name of a file created with the `etags' program.
  128. XA directory name is ok too; it means file TAGS in that directory."
  129. X  (interactive (list (read-file-name "Visit tags table: (default TAGS) "
  130. X                     default-directory
  131. X                     (expand-file-name "TAGS" default-directory)
  132. X                     t)))
  133. X  (setq file (expand-file-name file default-directory))
  134. X  (if (file-directory-p file)
  135. X      (setq file (expand-file-name "TAGS" file)))
  136. X  ;; Add an element to TAGS-TABLE-FILE-LIST.
  137. X  (or (assoc file tags-table-file-list)
  138. X      (setq tags-table-file-list
  139. X        (cons (list file) tags-table-file-list)))
  140. X  (setq tags-file-name file)
  141. X  (save-excursion
  142. X    (visit-tags-table-buffer)
  143. X    (initialize-new-tag-table)        ;; must occur within correct buffer
  144. X    (or tags-completion-alist
  145. X    (setq tags-completion-alist (tags-completion-alist)))))
  146. X
  147. X(defun visit-tags-table-buffer ()
  148. X  "Select the buffer containing the current tags table.
  149. XThis is a file whose name is in the variable tags-file-name."
  150. X  (or tags-file-name
  151. X      (call-interactively 'visit-tags-table))
  152. X  (set-buffer (or (get-file-buffer tags-file-name)
  153. X          (progn
  154. X            (initialize-new-tag-table)
  155. X            (find-file-noselect tags-file-name))))
  156. X  (or (verify-visited-file-modtime (get-file-buffer tags-file-name))
  157. X      (cond ((yes-or-no-p "Tags file has changed, read new contents? ")
  158. X         (revert-buffer t t)
  159. X         (initialize-new-tag-table)
  160. X         (setq tags-completion-alist (tags-completion-alist)))))
  161. X  (or (eq (char-after 1) ?\^L)
  162. X      (error "File %s not a valid tag table" tags-file-name)))
  163. X
  164. X(defun file-of-tag ()
  165. X  "Return the file name of the file whose tags point is within.
  166. XAssumes the tag table is the current buffer.
  167. XFile name returned is relative to tag table file's directory."
  168. X  (save-excursion
  169. X    (search-backward "\f\n")
  170. X    (forward-char 2)
  171. X    (buffer-substring (point)
  172. X              (progn (skip-chars-forward "^,") (point)))))
  173. X
  174. X(defun tag-table-files ()
  175. X  "Return a list of files in the current tag table.
  176. XFile names returned are absolute."
  177. X  (or tag-table-files
  178. X      (save-excursion
  179. X    (visit-tags-table-buffer)
  180. X    (let (files)
  181. X      (goto-char (point-min))
  182. X      (while (search-forward "\f\n" nil t)
  183. X        (setq files (cons (expand-file-name
  184. X                (buffer-substring
  185. X                  (point)
  186. X                  (progn (skip-chars-forward "^,\n") (point)))
  187. X                (file-name-directory tags-file-name))
  188. X                  files)))
  189. X      (setq tag-table-files (nreverse files))))))
  190. X
  191. X(defun tags-completion-alist ()
  192. X  "Return an alist of tags in the current buffer, which is a tag table."
  193. X  (let (alist next)
  194. X    (message "Making tags completion alist...")
  195. X    (save-excursion
  196. X      (goto-char (point-min))
  197. X    (while (search-forward "\177" nil t)
  198. X      (if (save-excursion
  199. X        (skip-chars-forward "^\001\n")
  200. X        (setq next (1+ (point)))
  201. X        (= (following-char) ?\001))
  202. X          ;;; If there are ^A's, get tags after them.
  203. X          (progn
  204. X        (goto-char next)    ;; after the first ^A
  205. X        (while (= (preceding-char) ?\001)
  206. X          (setq alist
  207. X            (cons (cons (buffer-substring
  208. X                     (point)
  209. X                     (progn (skip-chars-forward "^\001\n")
  210. X                        (point)))
  211. X                    nil)
  212. X                  alist))
  213. X          (forward-char 1)))
  214. X        ;;; If no ^A's, get tags from before the ^?.
  215. X        (skip-chars-backward "^-A-Za-z0-9_$\n")
  216. X        (or (bolp)
  217. X        (setq alist
  218. X              (cons (cons (buffer-substring
  219. X                   (point)
  220. X                   (progn
  221. X                     (skip-chars-backward "-A-Za-z0-9_$")
  222. X                     ;;; `::' in the middle of a C++ tag.
  223. X                     (while (and (= (preceding-char) ?:)
  224. X                         (= (char-after (- (point) 2)) ?:))
  225. X                       (progn (backward-char 2)
  226. X                          (skip-chars-backward
  227. X                           "-A-Za-z0-9_$")))
  228. X                     (point)))
  229. X                  nil)
  230. X                alist)))
  231. X        (goto-char next)        ; next line
  232. X        )))
  233. X    (message "Making tags completion alist...done")
  234. X    alist))
  235. X
  236. X(defun prompt-for-tag (prompt)
  237. X  "Prompt for a tag to find.  Default is determined by find-tag-default."
  238. X  (let* ((default (find-tag-default))
  239. X     (alist (save-excursion (visit-tags-table-buffer)
  240. X                tags-completion-alist))
  241. X     (spec (completing-read
  242. X        (if default
  243. X            (format "%s(default %s) " prompt default)
  244. X          prompt)
  245. X        ;;; completing-read craps out if given a nil table
  246. X        (or alist '((""))))))
  247. X    (if (equal spec "")
  248. X    (or default (error "There is no default tag."))
  249. X      spec)))
  250. X
  251. X;; Return a default tag to search for, based on the text at point, or nil.
  252. X(defun find-tag-default ()
  253. X  (save-excursion
  254. X    (while (looking-at "\\sw\\|\\s_")
  255. X      (forward-char 1))
  256. X    (if (re-search-backward "\\sw\\|\\s_" nil t)
  257. X    (progn (forward-char 1)
  258. X           (buffer-substring (point)
  259. X                 (progn (forward-sexp -1)
  260. X                    (while (looking-at "\\s'")
  261. X                      (forward-char 1))
  262. X                    (point))))
  263. X      nil)))
  264. X
  265. X(defun find-tag (tagname &optional next-p other-window regexp-p)
  266. X  "Find tag (in current tag table) whose name contains TAGNAME;
  267. Xmore exact matches are found first.
  268. XSelect the buffer containing the tag's definition and move point there.
  269. XThe default for TAGNAME is the expression in the buffer after or around point.
  270. X
  271. XIf second arg NEXT-P is non-nil (interactively, with prefix arg), search
  272. Xfor another tag that matches the last tagname or regexp used.
  273. X
  274. XIf third arg OTHER-WINDOW is non-nil, select the buffer in another window.
  275. X
  276. XIf fourth arg REGEXP-P is non-nil, treat TAGNAME as a regexp.
  277. X
  278. XSee documentation of variable `tags-file-name'."
  279. X  (interactive (if current-prefix-arg
  280. X           '(nil t)
  281. X           (list (prompt-for-tag "Find tag: "))))
  282. X  (cond
  283. X   (next-p (find-tag-in-order nil nil nil nil nil other-window))
  284. X   (regexp-p (find-tag-in-order tagname
  285. X                're-search-forward
  286. X                '(tag-re-match-p)
  287. X                t
  288. X                "matching"
  289. X                other-window))
  290. X   (t (find-tag-in-order
  291. X       tagname
  292. X       'search-forward
  293. X       '(tag-exact-match-p tag-word-match-p tag-any-match-p)
  294. X       nil
  295. X       "containing"
  296. X       other-window))))
  297. X
  298. X(defun find-tag-other-window (tagname &optional next-p)
  299. X  "Find tag (in current tag table) whose name contains TAGNAME;
  300. Xmore exact matches are found first.
  301. XSelect the buffer containing the tag's definition
  302. Xin another window, and move point there.
  303. XThe default for TAGNAME is the expression in the buffer around or before point.
  304. X
  305. XIf second arg NEXT-P is non-nil (interactively, with prefix arg), search
  306. Xfor another tag that matches the last tagname used.
  307. X
  308. XSee documentation of variable `tags-file-name'."
  309. X  (interactive (if current-prefix-arg
  310. X           '(nil t)
  311. X           (list (prompt-for-tag "Find tag other window: "))))
  312. X  (find-tag tagname next-p t))
  313. X
  314. X(defun find-tag-regexp (regexp &optional next-p other-window)
  315. X  "Find tag (in current tag table) whose name matches REGEXP.
  316. XSelect the buffer containing the tag's definition and move point there.
  317. X
  318. XIf second arg NEXT-P is non-nil (interactively, with prefix arg), search
  319. Xfor another tag that matches the last tagname used.
  320. X
  321. XIf third arg OTHER-WINDOW is non-nil, select the buffer in another window.
  322. X
  323. XSee documentation of variable `tags-file-name'."
  324. X  (interactive (if current-prefix-arg
  325. X           '(nil t)
  326. X         (list (read-string "Find tag regexp: "))))
  327. X  (find-tag regexp next-p other-window t))
  328. X
  329. X(defun find-tag-in-order
  330. X  (pattern search-forward-func order next-line-after-failure-p matching other-window)
  331. X  "Internal tag finding function.  PATTERN is a string to pass to
  332. Xsecond arg SEARCH-FORWARD-FUNC, and to any member of the function list
  333. XORDER (third arg).  If ORDER is nil, use saved state to continue a
  334. Xprevious search.
  335. X
  336. XFourth arg MATCHING is a string, an English '-ing' word, to be used in
  337. Xan error message.
  338. X
  339. XFifth arg NEXT-LINE-AFTER-FAILURE-P is non-nil if after a failed match,
  340. Xpoint should be moved to the next line.
  341. X
  342. XIf sixth arg OTHER-WINDOW is non-nil, select the buffer in another window.
  343. X
  344. XAlgorithm is as follows.  For each qualifier-func in ORDER, go to
  345. Xbeginning of tags file, and perform inner loop: for each naive match for
  346. XPATTERN found using SEARCH-FORWARD-FUNC, qualify the naive match using
  347. Xqualifier-func.  If it qualifies, go to the specified line in the
  348. Xspecified source file and return.  Qualified matches are remembered to
  349. Xavoid repetition.  State is saved so that the loop can be continued."
  350. X  (let (file linebeg startpos)
  351. X    (save-excursion
  352. X      (visit-tags-table-buffer)
  353. X      (if order
  354. X      (progn
  355. X        ;; Save state.
  356. X        (setq find-tag-state (vector pattern search-forward-func matching)
  357. X          tag-order order
  358. X          tag-lines-already-matched nil)
  359. X        ;; Start at beginning of tags file.
  360. X        (goto-char (point-min)))
  361. X    (progn
  362. X      ;; Restore state.
  363. X      (setq pattern (aref find-tag-state 0)
  364. X        search-forward-func (aref find-tag-state 1)
  365. X        matching (aref find-tag-state 2))))
  366. X
  367. X      ;; Get a qualified match.
  368. X      (catch 'qualified-match-found
  369. X    (while (car tag-order)
  370. X      (while (funcall search-forward-func pattern nil t)
  371. X        ;; Naive match found.
  372. X        (if (and
  373. X         ;; Qualify the match.
  374. X         (funcall (car tag-order) pattern)
  375. X         ;; Make sure it is not a previous qualified match.
  376. X         ;; Use of `memq' depends on numbers being eq.
  377. X         (not (memq (save-excursion (beginning-of-line) (point))
  378. X                tag-lines-already-matched)))
  379. X        (throw 'qualified-match-found nil))
  380. X        (if next-line-after-failure-p (forward-line 1)))
  381. X      (setq tag-order (cdr tag-order))
  382. X      (goto-char (point-min)))
  383. X    (error "No %stags %s %s" (if order "" "more ") matching pattern))
  384. X
  385. X      ;; Found a tag; extract location info.
  386. X      (beginning-of-line)
  387. X      (setq tag-lines-already-matched (cons (point) tag-lines-already-matched))
  388. X      (search-forward "\177")
  389. X      (setq file (expand-file-name (file-of-tag)
  390. X                   (file-name-directory tags-file-name)))
  391. X      (setq linebeg
  392. X        (buffer-substring (1- (point))
  393. X                  (save-excursion (beginning-of-line) (point))))
  394. X      (search-forward ",")
  395. X      (setq startpos (string-to-int (buffer-substring
  396. X                      (point)
  397. X                      (progn (skip-chars-forward "0-9")
  398. X                         (point)))))
  399. X      ;; Leave point on next line of tags file.
  400. X      (forward-line 1))
  401. X
  402. X    ;; Find the right line in the specified file.
  403. X    (if other-window
  404. X    (find-file-other-window file)
  405. X      (find-file file))
  406. X    (widen)
  407. X    (push-mark)
  408. X    (let ((offset 16)    ;; this constant is 1/2 the initial search window
  409. X      found
  410. X      (pat (concat "^" (regexp-quote linebeg))))
  411. X      (or startpos (setq startpos (point-min)))
  412. X      (while (and (not found)
  413. X          (progn
  414. X           (goto-char (- startpos offset))
  415. X           (not (bobp))))
  416. X    (setq found
  417. X          (re-search-forward pat (+ startpos offset) t))
  418. X    (setq offset (* 4 offset)))    ;; expand search window
  419. X      (or found
  420. X      (re-search-forward pat nil t)
  421. X      (error "\"%s\" not found in %s; time to rerun etags" pat file)))
  422. X    (beginning-of-line))
  423. X  (setq tags-loop-form '(find-tag-in-order nil nil nil nil nil nil))
  424. X  ;; Return t in case used as the tags-loop-form.
  425. X  t)
  426. X
  427. X;;; Match qualifier functions for tagnames.
  428. X
  429. X(defun tag-exact-match-p (tag)
  430. X  "Did we find an exact match for TAG?  Assume point is in a tags file,
  431. Ximmediately after an occurence of TAG."
  432. X  (let ((tag-length (length tag)))
  433. X    (or (and (looking-at "[ \t();,]?\177")
  434. X         (save-excursion (backward-char tag-length)
  435. X                 (or (bolp)
  436. X                 (let ((c (preceding-char)))
  437. X                   (or (= c ? ) (= c ?\t)
  438. X                       (= c ?*)    ;; HACK 7/19/89
  439. X                       )))))
  440. X    (and (looking-at "[\001\n]")
  441. X         (save-excursion (backward-char tag-length)
  442. X                 (= (preceding-char) ?\001))))))
  443. X
  444. X(defun tag-word-match-p (tag)
  445. X  "Did we find a word match for TAG?  Assume point is in a tags file,
  446. Ximmediately after an occurence of TAG."
  447. X  (let ((tag-length (length tag)))
  448. X    (or (and (looking-at "\\b.*\177")
  449. X         (save-excursion (backward-char tag-length)
  450. X                 (looking-at "\\b")))
  451. X    (and (looking-at "\\b.*[\001\n]")
  452. X         (save-excursion (backward-char tag-length)
  453. X                 (and
  454. X                  (looking-at "\\b")
  455. X                  (progn
  456. X                (skip-chars-backward "^\001\n")
  457. X                (= (preceding-char) ?\001))))))))
  458. X
  459. X(defun tag-any-match-p (tag)
  460. X  "Did we find any match for TAG?  Assume point is in a tags file,
  461. Ximmediately after an occurence of TAG."
  462. X  (or (looking-at ".*\177")
  463. X      (save-excursion
  464. X    (backward-char (length tag))
  465. X    (skip-chars-backward "^\001\n")
  466. X    (= (preceding-char) ?\001))))
  467. X
  468. X;;; Match qualifier function for regexps.
  469. X
  470. X(defun tag-re-match-p (re)
  471. X  "Is point (in a tags file) on a line with a match for RE?"
  472. X  (save-excursion
  473. X    (beginning-of-line)
  474. X    (catch 'done
  475. X      (let* ((bol (point))
  476. X         (eol (save-excursion (end-of-line) (point)))
  477. X         (del (save-excursion (if (search-forward "\177" eol t)
  478. X                      (point)
  479. X                    (throw 'done nil)))))
  480. X     (if (search-forward "\001" eol t)
  481. X         ;; There are ^A's: try to match in each tag after a ^A
  482. X         (let ((bot (point))
  483. X           eot)
  484. X           (while (< bot eol)
  485. X         (save-excursion
  486. X           (setq eot (if (search-forward "\001" eol t)
  487. X                    (1- (point))
  488. X                  eol))
  489. X           (if (re-search-forward re eot t)
  490. X               (throw 'done t))
  491. X           (setq bot (1+ eot))
  492. X           (goto-char bot))))
  493. X       ;; No ^A: try to match the line before the ^?
  494. X       (goto-char bol)
  495. X       (re-search-forward re (1- del) t))))))
  496. X
  497. X(defun next-file (&optional initialize)
  498. X  "Select next file among files in current tag table.
  499. XNon-nil argument (prefix arg, if interactive)
  500. Xinitializes to the beginning of the list of files in the tag table."
  501. X  (interactive "P")
  502. X  (if initialize
  503. X      (setq next-file-list (tag-table-files)))
  504. X  (or next-file-list
  505. X      (error "All files processed."))
  506. X  (find-file (car next-file-list))
  507. X  (setq next-file-list (cdr next-file-list)))
  508. X
  509. X(defvar tags-loop-form nil
  510. X  "Form for tags-loop-continue to eval to process one file.
  511. XIf it returns nil, it is through with one file; move on to next.")
  512. X
  513. X(defun tags-loop-continue (&optional first-time)
  514. X  "Continue last \\[find-tag], \\[tags-search], or
  515. X\\[tags-query-replace] command.  Used noninteractively with non-nil
  516. Xargument to begin such a command.  See variable `tags-loop-form'."
  517. X  (interactive)
  518. X  (if first-time
  519. X      (progn (next-file t)
  520. X         (goto-char (point-min))))
  521. X  (while (not (eval tags-loop-form))
  522. X    (next-file)
  523. X    (message "Scanning file %s..." buffer-file-name)
  524. X    (goto-char (point-min))))
  525. X
  526. X(defun tags-search (regexp)
  527. X  "Search through all files listed in tag table for match for REGEXP.
  528. XStops when a match is found.
  529. XTo continue searching for next match, use command \\[tags-loop-continue].
  530. X
  531. XSee documentation of variable tags-file-name."
  532. X  (interactive "sTags search (regexp): ")
  533. X  (if (and (equal regexp "")
  534. X       (eq (car tags-loop-form) 're-search-forward))
  535. X      (tags-loop-continue nil)
  536. X    (setq tags-loop-form
  537. X      (list 're-search-forward regexp nil t))
  538. X    (tags-loop-continue t)))
  539. X
  540. X(defun tags-query-replace (from to)
  541. X  "Query-replace-regexp FROM with TO through all files listed in tag table.
  542. XIf you exit (C-G or ESC), you can resume the query-replace
  543. Xwith the command \\[tags-loop-continue].
  544. X
  545. XSee documentation of variable tags-file-name."
  546. X  (interactive "sTags query replace (regexp): \nsTags query replace %s by: ")
  547. X  (setq tags-loop-form
  548. X    (list 'and (list 'save-excursion
  549. X             (list 're-search-forward from nil t))
  550. X          (list 'not (list 'perform-replace from to t t nil))))
  551. X  (tags-loop-continue t))
  552. X
  553. X(defun list-tags (string)
  554. X  "Display list of tags in file FILE.
  555. XFILE should not contain a directory spec
  556. Xunless it has one in the tag table."
  557. X  (interactive "sList tags (in file): ")
  558. X  (with-output-to-temp-buffer "*Tags List*"
  559. X    (princ "Tags in file ")
  560. X    (princ string)
  561. X    (terpri)
  562. X    (save-excursion
  563. X     (visit-tags-table-buffer)
  564. X     (goto-char 1)
  565. X     (search-forward (concat "\f\n" string ","))
  566. X     (forward-line 1)
  567. X     (while (not (looking-at "\f"))
  568. X       (princ (buffer-substring (point)
  569. X                (progn (skip-chars-forward "^\177")
  570. X                       (point))))
  571. X       (terpri)
  572. X       (forward-line 1)))))
  573. X
  574. X(defun tags-apropos (string)
  575. X  "Display list of all tags in tag table REGEXP matches."
  576. X  (interactive "sTag apropos (regexp): ")
  577. X  (with-output-to-temp-buffer "*Tags List*"
  578. X    (princ "Tags matching regexp ")
  579. X    (prin1 string)
  580. X    (terpri)
  581. X    (save-excursion
  582. X     (visit-tags-table-buffer)
  583. X     (goto-char 1)
  584. X     (while (re-search-forward string nil t)
  585. X       (beginning-of-line)
  586. X       (princ (buffer-substring (point)
  587. X                (progn (skip-chars-forward "^\177")
  588. X                       (point))))
  589. X       (terpri)
  590. X       (forward-line 1)))))
  591. X
  592. X(defun select-tags-table ()
  593. X  "Select a tags table file from a menu of those you have already used.
  594. XThe list of tags tables to select from is stored in `tags-table-file-list';
  595. Xsee the doc of that variable if you want to add names to the list."
  596. X  (interactive)
  597. X  (switch-to-buffer "*Tags Table List*")
  598. X  (erase-buffer)
  599. X  (let ((list tags-table-file-list))
  600. X    (while list
  601. X      (insert (car (car list)) "\n")
  602. X      (setq list (cdr list))))
  603. X  (goto-char 1)
  604. X  (insert "Type `t' to select a tag table:\n\n")
  605. X  (set-buffer-modified-p nil)
  606. X  (let ((map (make-sparse-keymap)))
  607. X    (define-key map "t" 'select-tags-table-select)
  608. X    (use-local-map map)))
  609. X  
  610. X(defun select-tags-table-select ()
  611. X  "Select the tag table named on this line."
  612. X  (interactive)
  613. X  (let ((name (buffer-substring (point)
  614. X                (save-excursion (end-of-line) (point)))))
  615. X    (visit-tags-table name)
  616. X    (message "Tag table now %s" name)))
  617. END_OF_FILE
  618. if test 20187 -ne `wc -c <'tags.el'`; then
  619.     echo shar: \"'tags.el'\" unpacked with wrong size!
  620. fi
  621. # end of 'tags.el'
  622. fi
  623. echo shar: End of archive 2 \(of 3\).
  624. cp /dev/null ark2isdone
  625. MISSING=""
  626. for I in 1 2 3 ; do
  627.     if test ! -f ark${I}isdone ; then
  628.     MISSING="${MISSING} ${I}"
  629.     fi
  630. done
  631. if test "${MISSING}" = "" ; then
  632.     echo You have unpacked all 3 archives.
  633.     rm -f ark[1-9]isdone
  634. else
  635.     echo You still need to unpack the following archives:
  636.     echo "        " ${MISSING}
  637. fi
  638. ##  End of shell archive.
  639. exit 0
  640.  
  641. exit 0 # Just in case...
  642.