I'm looking for some help developing what I think should be an easy program.
I want something similar to Emacs tags-search command, but I want to collect all search results into a buffer. (I want to see all results of M-,)
I'm thinking this python style pseudo code should work, but I have no idea how to do this in emacs lisp? Any help would be greatly appreciated.
def myTagsGrep(searchValue):
for aFile in the tag list:
result = grep aFile seachValue
if len(result) > 0:
print aFile # to the buffer
print result # to the buffer
I would like to be able to browse through the buffer with the same features tags-apropos does.
Note that a similar question has been asked before: Is there a way to get emacs tag-search command to output all results to a buffer?
Since I'm such a fan of igrep
, I'd use it as the building block. From there it's two simple routines and you're done. With that library and these two functions, all you have to do is:
M-x igrep-tags ^SomeRegexp.*Here RET
Here's the code:
(require 'igrep)
(defun igrep-tags (regex)
(interactive "sTAGS Regexp: ")
(igrep igrep-program regex (tags-file-names)))
(defun tags-file-names ()
(save-excursion
(visit-tags-table-buffer)
(mapcar (lambda (f) (file-truename f))
(tags-table-files))))
And, because the list of files can get really long, and you likely don't care what that list is, you can add these two pieces of code which will make the filenames invisible after the grep has finished:
(add-hook 'compilation-finish-functions 'igrep-tags-hide-filenames)
(defun igrep-tags-hide-filenames (buffer stat)
"hide the filenames b/c they can get long"
(save-excursion
(set-buffer buffer)
(save-match-data
(goto-char (point-min))
(if (search-forward (combine-and-quote-strings (tags-file-names))
nil
(save-excursion (forward-line 10) (point)))
(let ((display-string "..<files from TAGS>.."))
(put-text-property (match-beginning 0) (match-end 0) 'invisible t)
(put-text-property (match-beginning 0) (match-end 0) 'display display-string))))))
To avoid the really long command line, you can use the following code (which creates a temporary file containing all the names of files from TAGS file and uses that instead):
(defun igrep-tags (regex)
(interactive "sTAGS Regexp: ")
(let ((igrep-find t)
(igrep-use-file-as-containing-files t))
(igrep igrep-program regex nil)))
(defvar igrep-use-file-as-containing-files nil)
(defadvice igrep-format-find-command (around igrep-format-find-command-use-filename-instead activate)
"use the second argument as a file containing filenames"
(if igrep-use-file-as-containing-files
(progn (with-temp-file
(setq igrep-use-file-as-containing-files (make-temp-file "tags-files"))
(insert (combine-and-quote-strings (tags-file-names))))
(setq ad-return-value (format "cat %s | xargs -e %s"
igrep-use-file-as-containing-files
(ad-get-arg 0))))
ad-do-it))
And, for those using Emacs 22 or earlier, you'll need the routine that's shipped with Emacs 23 (from subr.el)
(defun combine-and-quote-strings (strings &optional separator)
"Concatenate the STRINGS, adding the SEPARATOR (default \" \").
This tries to quote the strings to avoid ambiguity such that
(split-string-and-unquote (combine-and-quote-strings strs)) == strs
Only some SEPARATORs will work properly."
(let* ((sep (or separator " "))
(re (concat "[\\\"]" "\\|" (regexp-quote sep))))
(mapconcat
(lambda (str)
(if (string-match re str)
(concat "\"" (replace-regexp-in-string "[\\\"]" "\\\\\\&" str) "\"")
str))
strings sep)))
Here is the code I use to create a tag system for my personal notes. It uses bookmarks and treats each word in a bookmark as a single tag. Its not quite what you're looking for but it might get you started.
The first couple of functions are probably already implemented in emacs, but I wrote my own for reasons that I no longer recall.
;; FILTER keeps only elements of li for which pred returns true
(defun filter (pred li)
(let (acc)
(dolist (elem li)
(if (funcall pred elem)
(setq acc (cons elem acc))))
(reverse acc)))
(defun string-match-all-p (str li)
(if li
(if (string-match-p (car li) str)
(string-match-all-p str (cdr li))
nil)
t))
;;bookmarks as tags
(defun lookup-bookmark-tags (tagstring)
(interactive "s")
(let ((taglist (split-string tagstring " ")))
(let ((bookmark-alist (filter
(lambda (elem)
(string-match-all-p (car elem) taglist))
bookmark-alist)))
(call-interactively 'list-bookmarks))))
I then bind the 'tagging' behavior to a key (F11) and the 'lookup' behavior to another (F12).
(global-set-key [f11] 'bookmark-set)
(global-set-key [f12] 'lookup-bookmark-tags))
Hope that is useful to you.
This is what you want:
http://www.emacswiki.org/emacs/Icicles_-_Emacs_Tags_Enhancements#icicle-tags-search
This is the doc string for icicle-tags-search
:
Search all source files listed in tags tables for matches for REGEXP. You are prompted for the REGEXP to match. Enter REGEXP with `RET'. You do not need `M-,' - you see all matches as search hits to visit. All tags in a tags file are used, including duplicate tags from the same or different source files. By default, all tags files are used, but if you provide a prefix argument then only the current tag table is used. If your TAGS file references source files that no longer exist, those files are listed. In that case, you might want to update your TAGS file. You can alternatively choose to search, not the search contexts as defined by the context regexp you provide, but the non-contexts, that is, the text in the files that does not match the regexp. To do this, use `C-M-~' during completion. (This is a toggle, and it affects only future search commands, not the current one.)
See also this page for more explanation about Icicles search:
http://www.emacswiki.org/emacs/Icicles_-_Search_Commands%2c_Overview
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With