Help writing emacs lisp for emacs etags search

前端 未结 3 743
北荒
北荒 2021-01-05 17:17

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

3条回答
  •  礼貌的吻别
    2021-01-05 17:45

    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 "...."))
                (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)))
    

提交回复
热议问题