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