怎样给 Ivy 添加拼音支持呢?
比如下面这样:
在 org 中,只要输入 rw
就可以过滤出“任务”
这个应该不难吧,我记得以前 ido 还是什么有类似的功能
这个有没有已经造好的轮子?
第三方库 pinyinlib.el
可以建立这样的正则表达式:
(require 'pinyinlib)
;; => pinyinlib
(string-match (pinyinlib-build-regexp-string "rw") "任务")
;; => 0
不过我不用 Ivy,不清楚怎么结合起来用。
等有时间了研究一下,看来又得自己造轮子了
不是很了解 ivy
和 pinyinlib
,可能有更好的方法,先来抛个砖:
(ivy-read "test: " '("张三和李四" "foo张三" "bar李四" "baz王五")
:re-builder #'pinyinlib-build-regexp-string)
输入zs可以匹配到“张三和李四”和“foo张三”,但是这样做不能像一般的命令那样用单个空格表示任意数量字符,两个空格表示真正的单个空格。
用以下代码可以(临时)解决上述问题,输入zs ls匹配到“张三和李四”:
(defun ivy--regex-pinyin (str)
(ivy--regex (pinyinlib-build-regexp-string str)))
(ivy-read "test: " '("张三和李四" "foo张三" "bar李四" "baz王五")
:re-builder #'ivy--regex-pinyin)
但是看了一下 ivy--regex
和 pinyinlib-build-regexp-string
的实现,隐隐觉得 ivy--regex-hash
可能会爆掉!所以最好还是自己参考 ivy--regex
实现一个不用 hashtable 的版本,可能会慢一些?也可能是这个整合拼音的方案行不通
要在 swiper
等命令中使用 ivy--regex-pinyin
,可以设置变量 ivy-re-builders-alist
,用法可以参考文档 Ivy - Completion Styles 部分(优先级那里我有点看不懂):
(add-to-list 'ivy-re-builders-alist
'(swiper . ivy--regex-pinyin))
在我这里这样还不行,参考 swiper--re-builder
的实现,需要设置 search-default-mode
为非 'char-fold-to-regexp
(不清楚这么用是否合适)。
pinyinlib
的作者更有发言权,以上仅供参考
这个确实可以有。
谢谢!我就感觉肯定有人已经造过这个轮子了。有点疑问,请问为啥要多输入一个感叹号?
如果开头是叹号,就用拼音查找规则。
(use-package pyim
:after ivy
:config
(defun eh-ivy-cregexp (str)
(if (string-match-p "^\\." str)
(pyim-cregexp-build (substring str 1))
(ivy--regex-plus str)))
(setq ivy-re-builders-alist
'((t . eh-ivy-cregexp))))
谈不上造轮子吧,以 ivy-read
为例,就是把喂给 ivy--regex-function
的数据改一下而已:
(ivy-read
"[拼音] "
(lambda (input)
(cl-remove-if-not
(lambda (cmd)
(string-match-p (funcall ivy--regex-function
-- input
++ (pinyinlib-build-regexp-string input)
) cmd))
'("标题" "任务" "子任务")))
:dynamic-collection t)
这样写相当于 advise 了 ivy--regex-plus
,如果不用 ivy--regex-plus
就得再写新的函数,比如我就用的是 ivy--regex-ignore-order
。不能向 ivy-re-builders-alist
中添加一条规则吗?这样不管使用哪个函数都可以用,会不会更 clean 一些?
感谢大家的回复,我没想到 ivy 的可定制性这么强,这么多方法都可以实现这一目的。
@fontux 和 @tumashu 的方案比较接近,也比较 clean,一个用到 pinyinlib,一个用 pyim,目前我比较倾向于这两位的方法。这两个包我都用到,所以依赖不成问题。稍后我会把比较的结果发上来。
Edit:
@tumashu 的方法在我这不 work,@fontux 的方法就是我要的,非常 nice!
根据 @fontux 的稍微修改了一下:
目前使用还没有发现什么问题,赞一个!
Edit 2:
看来这样全局修改还是有一定问题的,重启之后我的 M-x 等等都没有候选项了。我还是单个函数修改吧。
修改单个函数(用Ivy 自带的 :re-builder
property,谢谢 @fontux)
我用的前缀是· 而不是问号
难怪我没试出来,我最后采用只修改一个函数的方式,所以没有用前缀。
我现在更新了我的拼音搜索设置,有兴趣的可以试试,中文英文同时搜出,支持首字母搜索或者全拼搜索
(use-package pyim
:after ivy
:config
(defun eh-ivy-cregexp (str)
(let ((a (ivy--regex-plus str))
(b (let ((case-fold-search nil))
(pyim-cregexp-build str))))
(if (and a (stringp a))
(concat a "\\|" b)
a)))
(setq ivy-re-builders-alist
'((t . eh-ivy-cregexp))))
我也遇到了M-x没有候选项的情况,请问兄弟最后是如何解决的?
今天又更新了一下 ivy pinyin 搜索支持,感觉更好用了,不过要配合最新的 pyim,可能 melpa 还没有更新
(defun eh-ivy-cregexp (str)
(let ((x (ivy--regex-plus str))
(case-fold-search nil))
(if (listp x)
(mapcar (lambda (y)
(if (cdr y)
y
(list (pyim-cregexp-build (car y))))
x))
(pyim-cregexp-build x))))
(setq ivy-re-builders-alist
'((t . eh-ivy-cregexp)))
现在得用pyim-cregexp-build-1
才可以了
用了这个配置,当同时搜索多个词时,为啥中间部分被阴影覆盖了呀?