PageRenderTime 26ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 1ms

/old-archive/packages/tagify.el

https://github.com/emacsmirror/ohio-archive
Emacs Lisp | 385 lines | 239 code | 51 blank | 95 comment | 11 complexity | 6a0fd93da7e07713d4e6793ccd443abb MD5 | raw file
  1. ;From hallvard@ifi.uio.no Tue May 15 22:09:46 1990
  2. ;Date: Mon, 12 Feb 90 21:18:18 +0100
  3. ;From: hallvard@ifi.uio.no (Hallvard B Furuseth)
  4. ;Sender: hallvard@ifi.uio.no
  5. ;To: dsill@relay
  6. ;Subject: tagify.el.Z
  7. ;
  8. ;The file /pub/gnu/emacs/elisp-archive/as-is/tagify.el.Z on
  9. ;tut.cis.ohio-state.edu is corrupted. I am sending it to you for
  10. ;Daniel LaLiberte, because his mail to you failed (my fault, I spelled
  11. ;you wrong for him).
  12. ;
  13. ;
  14. ;Hallvard Furuseth
  15. ;hallvard@ifi.uio.no
  16. ;; tagify.el - make TAGS files.
  17. ;; Copyright (C) 1989 Daniel LaLiberte
  18. ;; This file is not yet part of GNU Emacs.
  19. ;; GNU Emacs is distributed in the hope that it will be useful,
  20. ;; but WITHOUT ANY WARRANTY. No author or distributor
  21. ;; accepts responsibility to anyone for the consequences of using it
  22. ;; or for whether it serves any particular purpose or works at all,
  23. ;; unless he says so in writing. Refer to the GNU Emacs General Public
  24. ;; License for full details.
  25. ;; Everyone is granted permission to copy, modify and redistribute
  26. ;; GNU Emacs, but only under the conditions described in the
  27. ;; GNU Emacs General Public License. A copy of this license is
  28. ;; supposed to have been given to you along with GNU Emacs so you
  29. ;; can know your rights and responsibilities. It should be in a
  30. ;; file named COPYING. Among other things, the copyright notice
  31. ;; and this notice must be preserved on all copies.
  32. ;;-----------------------------------------------------------------
  33. ;; To build a TAGS file for a set of files, first make sure there is a
  34. ;; make-tag function associated with the major mode for each file.
  35. ;; These are stored in tagify-mode-alist. Then call tagify-files. You
  36. ;; will be asked for a list of file names and the TAGS file. The TAGS
  37. ;; file is saved for you after it is created. If a major-mode does
  38. ;; not have a make-tag function, you will be asked to name one that
  39. ;; will be used for the remainder of the files.
  40. ;; To update the TAGS file, use retagify-files. You are asked to
  41. ;; specify the TAGS file. retagify-files will then regenerate
  42. ;; tags for just those files in the TAGS file that are newer than the TAGS
  43. ;; file.
  44. ;; Daniel LaLiberte
  45. ;; uiucdcs!liberte
  46. ;; liberte@cs.uiuc.edu
  47. ;; liberte%a.cs.uiuc.edu@uiucvmd.bitnet
  48. ;; Need:
  49. ;; add-file-tags filenames
  50. ;; delete-file-tags filenames
  51. (provide 'tagify)
  52. (defconst tagify-mode-alist '
  53. ((texinfo-mode . make-texinfo-tag)
  54. (c-mode . make-c-tag)
  55. (emacs-lisp-mode . make-elisp-tag)
  56. )
  57. "Association list between major modes and tag matching functions.
  58. The function should find the next tag and return it, or return nil if
  59. there are no more tags for the current buffer. The tag is only used
  60. to sort the entries for each file. The function should leave point
  61. after the tag.")
  62. ;; -----------------------------------------------
  63. ;; Example make-tag functions
  64. (defun make-texinfo-tag ()
  65. "Function to make next texinfo tag."
  66. (if (re-search-forward
  67. "^@def\\(un\\|var\\|opt\\|const\\|cmd\\|spec\\) \\([^ \n]+\\) ?\\|^@node \\([^,]+\\)" nil t)
  68. (if (match-beginning 2)
  69. (buffer-substring (match-beginning 2)
  70. (match-end 2))
  71. ;; @node found
  72. (buffer-substring (match-beginning 3)
  73. (match-end 3)))
  74. ))
  75. (defun make-info-tag ()
  76. "Function to make next tag for an info file."
  77. (if (re-search-forward
  78. "^\\* \\(Function\\|Command\\|Macro\\|Special form\\|Variable\\|Option\\|Constant\\): \\([^ \n]+\\) ?" nil t)
  79. (buffer-substring (match-beginning 2)
  80. (match-end 2))
  81. ))
  82. (defun make-elisp-tag ()
  83. "Function to make the next tag for an elisp file."
  84. (if (re-search-forward
  85. "^ ?(def\\(un\\|var\\|const\\) \\([^ \n]+\\) ?" nil t)
  86. (buffer-substring (match-beginning 2)
  87. (match-end 2))
  88. ))
  89. (defun make-c-tag-not-done ()
  90. "Function to make next c tag."
  91. ;; #defines are the easy part
  92. ;; I dont know how to match function declarations
  93. (if (re-search-forward
  94. "^[ \t]*#define[ \t]+\\([a-zA-Z_]+\\)")
  95. (buffer-substring (match-beginning 1)
  96. (match-end 1))))
  97. ;;-----------------------------------------------------------
  98. (defun find-tags-table (file)
  99. "Tell tags commands to use tag table file FILE.
  100. FILE should be the name of a file created with the `etags' program,
  101. or tagify-files, or it may be a new file.
  102. A directory name is ok too; it means file TAGS in that directory."
  103. (interactive (list (read-file-name "Find tags table: (default TAGS) "
  104. default-directory
  105. (concat default-directory "TAGS")
  106. nil)))
  107. (setq file (expand-file-name file))
  108. (if (file-directory-p file)
  109. (setq file (concat file "TAGS")))
  110. (setq tag-table-files nil
  111. tags-file-name file))
  112. (defconst find-tags-table-hook 'find-tags-table
  113. "Function to call to find the TAGS file.")
  114. (defun tagify-files (filenames)
  115. "Make a tags file from files listed in FILENAMES.
  116. The existing tags file, if any, is replaced.
  117. FILENAMES are files to search for tags. The FILENAMES argument may
  118. actually specify several files, with shell wildcards, e.g. \"*.c *.h\".
  119. Paths may be either absolute or relative to the current directory.
  120. How to make tags is determined from tagify-mode-alist and the major mode
  121. of each file."
  122. (interactive "sMake TAGS for files: ")
  123. (let (TAGS-buffer
  124. tag-entries
  125. file
  126. (file-list (files-matching filenames))
  127. tagifier
  128. (local-tagify-alist tagify-mode-alist) ; may be added to
  129. )
  130. (save-excursion
  131. ;; find and erase the TAGS file
  132. (call-interactively find-tags-table-hook)
  133. (set-buffer (or (get-file-buffer tags-file-name)
  134. (progn
  135. (setq tag-table-files nil)
  136. (find-file-noselect tags-file-name))))
  137. (setq TAGS-buffer (current-buffer))
  138. (erase-buffer) ;; to add new files, just dont erase
  139. ;; tagify each file
  140. (while file-list
  141. (setq file (car file-list))
  142. (setq file-list (cdr file-list))
  143. (save-excursion
  144. (set-buffer
  145. (find-file-noselect file))
  146. (message "Tagify: %s" file)
  147. (if (setq tagifier (cdr (assq major-mode local-tagify-alist)))
  148. nil
  149. (if (setq tagifier (tagify-read-tagifier))
  150. (setq local-tagify-alist
  151. (cons (cons major-mode tagifier) local-tagify-alist))
  152. (error "Abort tagifying.")
  153. ))
  154. (setq tag-entries (tagify-current-buffer tagifier)))
  155. (finish-tagging-file file tag-entries TAGS-buffer)
  156. )
  157. ;; finish off by writing the TAGS file
  158. (message "Saving %s" tags-file-name)
  159. (save-excursion
  160. (set-buffer TAGS-buffer)
  161. (write-file tags-file-name))
  162. )))
  163. (defun retagify-files ()
  164. "Update the TAGS file replacing entries only for files that
  165. have changed since the TAGS file was saved."
  166. ;; try combining this with tagify-files
  167. (interactive)
  168. (let (TAGS-buffer
  169. file
  170. tag-entries
  171. startpt size
  172. tagifier
  173. (local-tagify-alist tagify-mode-alist) ; may be added to
  174. )
  175. (save-some-buffers)
  176. (save-excursion
  177. ;; find the TAGS file
  178. (call-interactively find-tags-table-hook)
  179. (visit-tags-table-buffer)
  180. (setq TAGS-buffer (current-buffer))
  181. (goto-char (point-min))
  182. ;; check each file
  183. (while (not (eobp))
  184. ;; get the next file name
  185. (forward-line 1)
  186. (end-of-line)
  187. (skip-chars-backward "^,\n")
  188. (save-excursion (setq size (read (current-buffer))))
  189. (setq file (buffer-substring (1- (point))
  190. (progn (beginning-of-line) (point))))
  191. (setq startpt (- (point) 2)) ; before leading \^L
  192. (forward-line 1)
  193. (forward-char size) ; at end of tags for file
  194. (if (file-newer-than-file-p file tags-file-name)
  195. (progn
  196. ;; strip out old entries for this file
  197. (delete-region startpt (point))
  198. (save-excursion
  199. (set-buffer
  200. (find-file-noselect file))
  201. (message "Retagify: %s" file)
  202. (if (setq tagifier (cdr (assq major-mode local-tagify-alist)))
  203. nil
  204. (if (setq tagifier (tagify-read-tagifier))
  205. (setq local-tagify-alist
  206. (cons (cons major-mode tagifier)
  207. local-tagify-alist))
  208. (error "Abort tagifying.")
  209. ))
  210. (setq tag-entries (tagify-current-buffer tagifier)))
  211. (finish-tagging-file file tag-entries TAGS-buffer)
  212. )))
  213. ;; finish off by writing the TAGS file
  214. (message "Saving %s" tags-file-name)
  215. (save-excursion
  216. (set-buffer TAGS-buffer)
  217. (write-file tags-file-name))
  218. )))
  219. (defun tagify-read-tagifier ()
  220. "Read a tagifier function for the current mode."
  221. (let ((name
  222. (completing-read (format "Specify tagifier for %s (RET to exit): "
  223. major-mode)
  224. obarray 'fboundp 'match)))
  225. (if (> (length name) 0)
  226. (intern name)
  227. nil)))
  228. (defun tagify-current-buffer (make-tag)
  229. "Return the list of tag entries for the current buffer.
  230. Tags are found with the MAKE-TAG function.
  231. See tagify-mode-alist."
  232. (let ((tag-entries nil)
  233. (last-line 1)
  234. (last-char 1)
  235. tag text line char)
  236. (save-excursion
  237. (goto-char (point-min))
  238. ;; find all tags in the file
  239. (while (setq tag (funcall make-tag))
  240. (save-excursion
  241. (setq text
  242. (buffer-substring
  243. (point)
  244. (progn
  245. (beginning-of-line)
  246. (point))))
  247. (setq line (+ last-line
  248. (count-lines last-char (point))))
  249. (setq char (point))
  250. (setq last-line line)
  251. (setq last-char char)
  252. (setq tag-entries
  253. (cons (list tag text line char) tag-entries))
  254. )))
  255. tag-entries
  256. ))
  257. ;;---------------------------------------------------
  258. ;; Format of a TAGS file
  259. ;; A TAGS file consists of a sequence of file sections.
  260. ;; Each file section begins with \014 (^L).
  261. ;; The file name may be relative to the directory that the
  262. ;; TAGS file is in. The file name is followed by ",n", where
  263. ;; n is the length, in chars, of the tag entry lines for this file.
  264. ;; \014
  265. ;; filename,n
  266. ;; <n chars of entries>
  267. ;; <including newlines>
  268. ;; \014
  269. ;; nextfile ...
  270. ;; Each entry is the text at the start of the tagged line,
  271. ;; including the text of the tag itself.
  272. ;; Following that is "\177n,m", where n is the line number
  273. ;; of the tagged line and m is the character number of the
  274. ;; newline before the tagged line. Exact numbers do not matter
  275. ;; since find-tag looks in the neighborhood.
  276. ;; examples:
  277. ;; text of line before tag\17713,400
  278. ;; text of another line before tag\1775,30
  279. ;; The entries are sorted by the tags of all entries for each file.
  280. ;;-----------------------------------------------------------------
  281. (defun finish-tagging-file (filename tag-entries TAGS-buffer)
  282. "Finish tagging FILENAME by inserting all TAG-ENTRIES to the TAGS-BUFFER.
  283. Insertion is at point and may be in middle of buffer."
  284. ;; could make it more general by just returning a string that may be
  285. ;; inserted anywhere
  286. (setq tag-entries
  287. (sort tag-entries
  288. (function (lambda (e1 e2)
  289. (string< (car e1) (car e2))))))
  290. (let (startp endp entry length)
  291. (set-buffer TAGS-buffer)
  292. (insert ?\^L ?\n filename ?\n)
  293. (setq startpt (point))
  294. ;; insert the tag entries
  295. (while tag-entries
  296. (setq entry (car tag-entries))
  297. (insert (nth 1 entry) ?\177
  298. (format "%d,%d\n"
  299. (nth 2 entry)
  300. (nth 3 entry)))
  301. (setq tag-entries (cdr tag-entries)))
  302. (setq endpt (point))
  303. (goto-char (1- startpt)) ; end of filename line
  304. (setq length (format ",%d" (- endpt startpt)))
  305. (insert length)
  306. (goto-char (+ endpt (length length)))
  307. ))
  308. ;;--------------------------------------------------
  309. ;; Handy utility section
  310. (defun files-matching (&rest filenames)
  311. "Return a list of files matching FILENAMES.
  312. FILENAMES may include shell wildcards.
  313. ls is used."
  314. (interactive "sFilenames: ")
  315. (let (filename
  316. file-list)
  317. (save-excursion
  318. (with-output-to-temp-buffer "*Directory*"
  319. (buffer-flush-undo standard-output)
  320. (funcall 'call-process (getenv "SHELL")
  321. nil standard-output nil "-c"
  322. (concat "ls " (mapconcat 'identity filenames " ")))
  323. (set-buffer "*Directory*")
  324. (goto-char (point-min))
  325. (while (not (eobp))
  326. (setq file-list (cons
  327. (buffer-substring (point)
  328. (progn (end-of-line) (point)))
  329. file-list))
  330. (if (not (eobp))
  331. (forward-char 1))))
  332. (kill-buffer "*Directory*"))
  333. (nreverse file-list)))