EMACS-DOCUMENT

=============>集思广益

基于counsel的超级好用的高亮搜索功能

abo-abo写过一篇博文, 阐述了如何利用 counsel, ivy 以及 swiper来搜索由recoll(一种搜索工具) 索引过的文件的内容. 受此文的影响,我也尝试将之迁移到Mac上. 下面是我的尝试说明.

使用counsel能够让我们以递增的方式更新搜索结果(该搜索结果由命令行工具mdfind返回). 选中一个文件后,emacs会打开它,并且若该文件不是pdf的话,还会调用swiper来搜索该文件.

一切都很顺利. 唯一的问题是,我想优先显示org文件,然后再是tex文件.但是不知道为何,我的排序函数在ivy中不太正常. 我的Lisp水平不是很高,希望其他人可以帮忙看出问题所在! UPDATE: 在问题在更新ivy和counsel后已经被修复了,下面的排序命令可以正常是用了.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; counsel-spotlight                                                      ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Incrementally search the Mac spotlight database and open matching
;; files with a swiper search on the query text.
;; Based on http://oremacs.com/2015/07/27/counsel-recoll/

(require 'counsel)

;; Function to be called by counsel-spotlight
;; The onlyin option limits results to my home directory
;; and directories below that
;; mdfind is the command-line interface to spotlight
(defun counsel-mdfind-function (string &rest _unused)
  "Issue mdfind for STRING."
  (if (< (length string) 4)
      (counsel-more-chars 4)
    (counsel--async-command
     (format "mdfind -onlyin ~/ '%s'" string))
    nil))

;; Main function
(defun counsel-spotlight (&optional initial-input)
  "Search for a string in the mdfind database.
You'll be given a list of files that match.
Selecting a file will launch `swiper' for that file.
INITIAL-INPUT can be given as the initial minibuffer input."
  (interactive)
  (ivy-read "spotlight: " 'counsel-mdfind-function
            :initial-input initial-input
            :dynamic-collection t
            :sort t
            :action (lambda (x)
                      (when (string-match "\\(\/.*\\)\\'" x)
                        (let ((file-name (match-string 1 x)))
                          (find-file file-name)
                          (unless (string-match "pdf$" x)
                            (swiper ivy-text)))))))

;; Define my sort function
(defun bjm-counsel-mdfind-sort-function (x y)
  "Compare two files X and Y. Prioritise org then tex."
  (if (string-match "org$" x)
      t
    (if (string-match "tex$" x)
        (if (string-match "org$" y)
            nil
          t)
      nil)))

;; Add to list of ivy sorting functions
(add-to-list 'ivy-sort-functions-alist
             '(counsel-mdfind-function . bjm-counsel-mdfind-sort-function))

在理想情况下,我希望能够实现用另一个counsel来减少mdfind搜索出文件名的匹配项. 然后在第二个counsel中选中的文件会通过swiper搜索第一个counsel中的关键字. 举个例子,我希望能做到

  1. 执行 M-x counsel-spotlight 然后输入 caustic 会返回一堆内容中包含 caustic 的文件.
  2. 按下某个快捷键,会弹出一个新的counsel,输入 chandra 会搜索出文件名中包含 chandra 的那些文件.
  3. 选中文件后按下回车,Emacs会打开该文件,并用swiper搜索原始的那个搜索关键字 caustic.

基于我目前lisp的能力,还难以实现这一功能,不过就是想想也不错!