怎样给 Ivy 添加拼音支持

谈不上造轮子吧,以 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)

00_AM 20_AM

1 个赞

这样写相当于 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))))
6 个赞

我也遇到了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)))
6 个赞

6 个赞

现在得用pyim-cregexp-build-1才可以了

用了这个配置,当同时搜索多个词时,为啥中间部分被阴影覆盖了呀?

ivy

不用的时候是这样的

ivy2

我现在用的版本是:

(defun eh-ivy-cregexp (str)
  (let ((x (ivy--regex-plus str))
        (case-fold-search nil))
    (if (listp x)
        (mapcar (lambda (y)
                  (if (cdr y)
                      (list (if (equal (car y) "")
                                ""
                              (pyim-cregexp-build (car y)))
                            (cdr y))
                    (list (pyim-cregexp-build (car y)))))
                x)
      (pyim-cregexp-build x))))

5 个赞

我把第二行的ivy--regex-plus改成ivy--regex-ignore-order就好了

ivy--regex-ignore-order会把空格当成分隔符,ivy--regex-plus会匹配空格

1 个赞

在doom下,由于使用了ivy-prescient,采用增加advice方式支持pinyin:

  (defun pinyin/around (old-fun query &rest args)
    (let ((result (apply old-fun query args))
          (pinyin nil))
      (when (and (> (length query) 0)
                 (equal (substring query 0 1) ":"))
        (setq pinyin (evil-pinyin--build-regexp (substring query 1)))
        (setq result (list (concat pinyin ".*"))))
      result))
  (advice-add 'prescient-filter-regexps :around #'pinyin/around)

发现一个不是bug的问题。 我在使用这个代码之后, org-insert-link 行为发生了变化。 在用之前, 我先 org-store-link 然后 org-insert-link 会先定位到最后链接这个选项。 使用之后,… 不再定位到链接这里,而是选项列表的第一个。

这个问题能修复么?我看了下代码,也没有进行排序。为啥默认就变了呢?

解决了

(defun pyim--ivy-cregexp (str)
    (let ((regex-sequence (ivy--regex-plus str)) ;; (ivy--regex-ignore-order str)
          (case-fold-search nil))
      (if (listp regex-sequence)
          (mapcar (lambda (regex)
                    (if (cdr regex)
                        (list (if (equal (car regex) "")
                                  ""
                                (pyim-cregexp-build (car regex)))
                              (cdr regex))
                      (list (pyim-cregexp-build (car regex)))))
                  regex-sequence)
        (pyim-cregexp-build regex-sequence))))
  (setq ivy-re-builders-alist '((read-file-name-internal . pyim--ivy-cregexp)
                                (ivy-read . pyim--ivy-cregexp)
                                (t . ivy--regex-plus)))

指定key就好了

key???

就是上面 ivy-re-builders-alist 里面的key

得空看了下,大概是这样,原先空字符串""经过转换之后变成了"\\(?:\\)",虽然从正则角度来说貌似是一致的,不过加下判断应该就可以了:

  (defun ivy--cregex-plus (str)
    (let ((x (ivy--regex-plus str))
          (case-fold-search nil))
      (if (listp x)
          (mapcar (lambda (y)
                    (cons (pyim-cregexp-build (car y))
                          (cdr y)))
                  x)
        (if (string= "" x) x (pyim-cregexp-build x)))))