Table of Contents
ivy默认的配置已经足够了,但还是可以通过一些技巧来提升使用体验
ivy中的tab
ivy提供了好几个有关补全的命令,分别是ivy-done, ivy-partial-or-done, ivy-immediate-done, ivy-dispatching-done, 但不幸,想要获得高效的补全,我不得不记住这n多个命令,这常常使效率变得更低,
所以,我自定义了一个 maple/ivy-done, 仅使用 tab 这一个按键就可以获得以上所有的体验
(defun maple/ivy-done()
  (interactive)
  (let ((dir ivy--directory))
    (ivy-partial-or-done)
    (when (string= dir ivy--directory)
      (ivy-insert-current)
      (when (and (eq (ivy-state-collection ivy-last) #'read-file-name-internal)
                 (setq dir (ivy-expand-file-if-directory (ivy-state-current ivy-last))))
        (ivy--cd dir)
        (setq this-command 'ivy-cd)))))
- 预设场景一
dirs目录下有 init-a.el init-b.el init-c.el 等多个文件, 我需要把init-c.el重命名为init-c.el.bak, 默认的ivy会怎么做呢 - 输入 init c 进行查找
- 使用 C-M-j(ivy-immediate-done) 插入当前选中项
- 修改
 而使用 maple/ivy-done 后呢 - 输入 init c 进行查找
- 使用 tab插入当前选中项
- 修改
 
- 预设场景二
有一个n级子目录,需要切换到第n个子目录下, 默认的ivy会怎么做呢 - 使用 tab选中
- 再次使用 tab切换目录
 而使用 maple/ivy-done 后呢 - 使用 tab选中并切换目录
 
- 使用 
ivy中的C-h
由于我是邪恶的 evil 用户, 所以我正常情况会使用 C-j, C-k来选择待选项,同样的,我希望能够使用 C-h 来进行某些操作,比如在counsel-ag中使用C-h代替backspace删除输入的字符,而在counsel-find-file中使用C-h切换到上一级目录
ivy默认提供了 counsel-up-directory 命令可以切换到上级目录, 我希望能更进一步,当有插入的字符时, 调用C-h能够直接清除插入的字符,再次调用才切换到上一级目录
(defun maple/ivy-c-h ()
  (interactive)
  (if (eq (ivy-state-collection ivy-last) #'read-file-name-internal)
      (if (string-equal (ivy--input) "")
          (counsel-up-directory)
        (delete-minibuffer-contents))
    (ivy-backward-delete-char)))
ivy-occur批量操作
自动打开wgrep-mode
ivy默认调用ivy-occur后, 还需要调用ivy-wgrep-change-to-wgrep-mode才能进行批量修改
;; ivy-occur custom (defun maple/ivy-edit () "Edit the current search results in a buffer using wgrep." (interactive) (run-with-idle-timer 0 nil 'ivy-wgrep-change-to-wgrep-mode) (ivy-occur))
批量修改文件名
预设场景: 当某个项目下有许多使用 aaa.py的文件,我需要把 aaa.py 全部修改为 bbb.py, 也许某个 aaa.py 需要修改成 ccc.py,我在使用 projectile-find-file 搜索完全部的 aaa.py 后,打开ivy默认的ivy-occur并不能对文件进行修改(提示Text read only), 所以我采用 find-name-dired 来批量修改文件名(目前还有些问题)
(defun maple/ivy-dired-occur()
  (interactive)
  (find-name-dired
   (or (projectile-project-root) default-directory) (concat (ivy--input) "*"))
  (ivy-exit-with-action
   (lambda (_)
     (pop-to-buffer (get-buffer "*Find*"))
     (dired-hide-details-mode)
     (wdired-change-to-wdired-mode)
     (when (bound-and-true-p evil-local-mode) (evil-normal-state)))))
counsel-find-file
重命名
预设场景: 有一个dirs目录, 我需要在同级目录下创建一个 dirs-aa.el 的文件, 默认的ivy会怎么做呢
- 切换到 dirs 目录的上级目录
- 使用 ivy-immediate-done 插入目录名
- 新建文件
但还有一种方式
- 切换到 dirs 目录
- 使用 backspace键删除目录末尾的 =/=
- 新建文件
不幸的是,ivy中 backspace 的按键绑定了 ivy-backward-delete-char, 在 counsel-find-file 中使用 ivy会直接返回上级目录, 所以需要对 ivy-backward-delete-char 作简单的修改
(defun maple/ivy-backward-delete-char ()
  (interactive)
  (let ((dir ivy--directory)
        (p (and ivy--directory (= (minibuffer-prompt-end) (point)))))
    (ivy-backward-delete-char)
    (when p (insert (file-name-nondirectory (directory-file-name dir))))))
自动创建不存在的目录
不仅用于ivy, 其它文件操作命令也需要
(defun maple/ivy-make-directory-maybe ()
  "Create parent directory if not exists while visiting file."
  (let ((dir (file-name-directory buffer-file-name)))
    (unless (file-exists-p dir)
      (if (y-or-n-p (format "Directory %s does not exist,do you want you create it? " dir))
          (make-directory dir t)
        (keyboard-quit)))))
(add-to-list 'find-file-not-found-functions 'maple/ivy-make-directory-maybe nil #'eq)
ivy自动使用选中的内容
在使用 counsel-ag 或者 swiper, 我需要快速搜索选中的关键词,然而,ivy默认并不支持这么做,ivy需要打开counsel-ag后使用 M-n 插入选中的关键词,当然,也许是作者认为这样的方式很方便,但我并不认同,我为何需要重复一次操作呢,为何还需要记住 M-n 这样的按键呢?
(defun maple/region-string()
  "Get region string."
  (if (not (use-region-p)) ""
    (let* ((beg (region-beginning))
           (end (region-end))
           (eol (save-excursion (goto-char beg) (line-end-position))))
      (deactivate-mark) (buffer-substring-no-properties beg (min end eol)))))
;; custom counsel-ag
(defun maple/counsel-ag(-counsel-ag &optional initial-input initial-directory extra-ag-args ag-prompt)
  (funcall -counsel-ag
           (or initial-input (maple/region-string))
           (or initial-directory default-directory)
           extra-ag-args
           ag-prompt))
(advice-add 'counsel-ag :around #'maple/counsel-ag)
这样,调用 counsel-ag 时,如何已经有选中的关键词,就会直接调用该关键词进行查找,避免重复操作, 同样的对于swiper 也可以使用另一种方式
(defun maple/ivy-search-at-point (func)
  (let ((ivy-initial-inputs-alist (list (cons func (maple/region-string)))))
    (funcall func)))
(defun maple/swiper()
  (interactive)
  (maple/ivy-search-at-point 'swiper))
搜索某个目录
counsel-ag默认搜索当前目录,想要搜索某个目录,需要切换到该目录下调用counsel-ag,无疑的,这非常不方便,所以,我希望可以选择某个目录进行搜索
(defun maple/counsel-ag-directory() (interactive) (counsel-ag nil (read-directory-name "Search in directory: ")))
ivy的显示避免出现在视线外
详见 自定义helm式的ivy.html 中的
吐嘈六: minibuffer
