自定义helm式的ivy


n 个月前, 我曾写过 helm与ivy简单对比, 并吐嘈了ivy细节打磨不够,以至于我切换到ivy不到几天后, 又回到了helm的拥抱, 但在n个月后,本着生命不止,折腾不息的精神, “狠狠地”的折腾了一把ivy, 让ivy也能像helm一样“如丝般润滑”,适应我平时的操作

吐嘈一: counsel-find-file

我在dired中移动文件, 即使已经设置了

:map counsel-find-file-map
("C-h" . counsel-up-directory)

C-h返回上级目录还是无效

无意中从spacemacs中找到了解决办法(我电脑上常备 spacemacs 的配置,当看到 spacemacs 有什么更新都会切换过去尝试一番, 遇到适合自己的配置会"参考"一下, 哈), spacemacs 并没有遇到上述问题,在经过查找后,发现有这个一行

(define-key ivy-minibuffer-map (kbd "C-h") (kbd "DEL"))

转换成我自己的配置就是

:map ivy-minibuffer-map
("C-h" . [backspace])

吐嘈二: tab 键

tab 键我只想要complete, 而不是complete and done, 虽然ivy提供了另外的选项ivy-partial-or-done,但不是我想要的效果,尤其是把aaa.py重命名为aaa.py.bak

关于这一条,真的是“狠狠”地折腾了一把, 最终以胜利告终

(defun maple/ivy-done()
  (interactive)
  (ivy-partial-or-done)
  (delete-minibuffer-contents)
  (let ((ivy-text (ivy-state-current ivy-last)) dir)
    (insert ivy-text)
    (when (and (eq (ivy-state-collection ivy-last) #'read-file-name-internal)
               (setq dir (ivy-expand-file-if-directory ivy-text)))
      (ivy--cd dir))))

主要思路就是插入当前选中项, 如果是read-file-name-internal(文件操作), 并且选中项是一个目录,则列出这个目录的文件,避免选中tab两次才能列出文件, 这样一来,第一次tab就是complete, 第二次tab才是done, 最终效果超出预期(V 字手)

吐嘈三: 记忆多个按键

ivy 有这样一个问题,它不会像 helm 一样在第一行显示用户输入的字符,在 ivy 的很多 issue 中都有人提了这个问题,如果当前目录下有名为aaa的目录,这是我想要创建一个aaa.py的文件,ivy 会列出 aaa 这个目录,那是我该怎么创建 aaa.py 文件。方法是一个新的命令ivy-immediate-done,而不是ivy-alt-done

现在的ivy已经支持可选择用户输入

(setq ivy-use-selectable-prompt t)

吐嘈四: 模糊搜索

在 helm 中我可以很容易的使用模糊搜索,ivy 中也一样,只要简单的设置

(setq ivy-re-builders-alist
      '((t . ivy--regex-fuzzy)))

但 ivy 中有这样一个问题,空格键不能在模糊匹配中使用,/汗,作为从 helm 转入 ivy 的人,经常会不经意间在输入时按下空格键,然后,What? ivy 中搜索变成空了

其实我想要混合使用空格与非空格, 但最终还是没能找到解决办法, 因为我已经适应的使用空格分隔, 所以暂时使用

(setq ivy-re-builders-alist
'((t   . ivy--regex-ignore-order))

吐嘈五: 候选词按使用频率排序

这个。。。

吐嘈六: minibuffer

helm 从当前 buffer 中弹出 helm-buffer 是多么明智的选择,视野不会移动到当前 buffer 以外的地方,尤其是在屏幕较大的时候, 而 ivy 使用 minibuffer 总是从屏幕左下方弹出

经过多次试验, 最终也找到的解决办法

;; custom ivy display function
(defvar maple/ivy-format-padding nil)

(defun maple/ivy-read-around (-ivy-read &rest args)
  "Advice ivy-read `-IVY-READ` `ARGS`."
  (let ((maple/ivy-format-padding (make-string (window-left-column) ?\s)))
    (setcar args (concat maple/ivy-format-padding (car args)))
    (apply -ivy-read args)))

(defun maple/ivy-format-function (cands)
  "Transform CANDS into a string for minibuffer."
  (ivy--format-function-generic
   (lambda (str)
     (concat maple/ivy-format-padding (ivy--add-face str 'ivy-current-match)))
   (lambda (str)
     (concat maple/ivy-format-padding str))
   cands "\n"))

(advice-add 'ivy-read :around #'maple/ivy-read-around)
(setq ivy-count-format ""
      ivy-format-function 'maple/ivy-format-function)

主要思路就是在各个collections前添加空格, 空格宽度为 (window-left-column), window-left-column 按照 help 文档来说就是Return left column of window WINDOW, 与屏幕左边缘的距离; 然后自定义 ivy-format-function,即可, 需要注意的一点, 不仅collections前需要添加空格, prompt前也需要添加空格

最终效果

吐嘈七: dired 中复制或重命名文件

我之前想要复制或重命名一个文件,只要进入dired中按CR,然后选择目标就行,但不知道为什么,使用 ivy 时复制重命名总是报错,不成功

经过测试, 现在的ivy表现正常

吐嘈八: sudo edit

使用ivy时, sudo edit 不成功

目前已正常

吐嘈九: counsel-ag 默认不会使用已选的单词

counsel-ag, 默认不会使用已选的单词, 想要查找已选单词, 需要在激活counsel-ag后使用M-n, 很麻烦,不像helm默认就可以选择region里的单词, 另外counsel-ag默认会使用含.git目录的目录作为根目录进行查找, 这与counsel-projectile-ag功能上有些冲突了

解决办法很简单, defadvice counsel-ag 即可

(defun maple/counsel-ag(-counsel-ag &optional initial-input initial-directory extra-ag-args ag-prompt)
  (when (and (not initial-input) (region-active-p))
    (setq initial-input (buffer-substring-no-properties
                         (region-beginning) (region-end))))
  (unless initial-directory (setq initial-directory default-directory))
  (funcall -counsel-ag initial-input initial-directory extra-ag-args ag-prompt))

(advice-add 'counsel-ag :around #'maple/counsel-ag)

总结

  • 说一说为什么想要折腾ivy:
    1. 在使用helm时, 首次打开会很慢(我在打开 emacs 后,习惯使用helm-recentf打开最近文件, 但不知道为什么,第一次会非常慢);另外, 打开 emacs 后, 必须先使用helm-recentf才能激活helm, 如果使用其它helm命令, 比如helm-M-x或者helm-projectile只会使用默认的ido, 并不能激活helm
    2. helm真的为用户做出太多选择, 想要自定义非常难, 即使成功也不是从源头解决,而是用了取巧的办法
    3. 速度,不知道是不是我的感觉错误,最新版本的helm速度慢了很多
  • 还得吐嘈ivy:

    ivy 细节上果然打磨不够, 不过经过调(折)教(腾), 大致上和我之前使用helm的习惯一样了

    最终吐嘈点: ivy-occur, ivy-occur 使用了wgrep作为多文件编辑, 但说实话, 我觉得很难用, 和helm-ag自己实现的helm-ag-edit比起来更是难受, 一会就要切换一下ivy-wgrep-change-to-wgrep-mode, 不切用不了, 这个等有时间再折腾吧!

ok,就这样

There are comments.