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中的关键字. 举个例子,我希望能做到
- 执行
M-x counsel-spotlight
然后输入caustic
会返回一堆内容中包含caustic
的文件. - 按下某个快捷键,会弹出一个新的counsel,输入
chandra
会搜索出文件名中包含chandra
的那些文件. - 选中文件后按下回车,Emacs会打开该文件,并用swiper搜索原始的那个搜索关键字
caustic
.
基于我目前lisp的能力,还难以实现这一功能,不过就是想想也不错!