首先要解释一下这里提到的重构主要是指变量名、方法名的修改,并不涉及到任何代码优化的部分(Emacs can't help you with that )。
作为一名(前)Android 开发者,对于这部分基本是属于被 Intellj IDEA ( Android Studio) 惯坏了,右键点点就帮你换好了,顺便还帮你提前检查了可能出现的编译错误。当然这也是受益于 Java 是个静态语言,所以当我的主要工作转移到 Emacs 写 js(没错) 之后。虽然没办法用到这么方便的工具了,但是也让我学会了更加通用的办法,是好事(F91 语气)。
当前文件的“查找替换”: iedit
最常见的情况是当前编辑的文件中有需要修改的变量名,比如说一个 typo,由于自动补全工具的强大(比如说我在用的company-mode),如果你写错一次,那么多半这个 typo 基本就会到处都是了。
最容易想到的办法是使用 (replace-string)
查找替换,不过这样的局限性也很强。一是不够直观,二是在手动输入查找替换字符串中难免再次出错导致需要再来一瓶。
而使用 iedit ,只需要选中需要修改的字符串并执行 (iedit-mode): C-;
,当前
Buffer 所有的相同字符串都会高亮:
这时候修改高亮的字符串,其他的字符串也会同步修改。
这个过程中随时都能看到全局的变化,也不容易再次犯错。
如果你觉得这样还不够清晰,也可以使用下文提到的 ivy-occur + wgrep 的方式修改,将搜索的范围限定到当前文件即可。
局部变量替换 narrowing
有些时候需要替换的是一个函数内部局部变量的名字,但是其他函数里面也有同名的变量我不想修改,这时候只用 iedit 的话就有点麻烦了,不过 Emacs 内置的 narrow 功能就派上了用场,需要注意的是这个功能默认是被禁用了,因为新手如果不小心按到快捷键会不知道发生了什么。第一次使用时 Emacs 弹出警告按下 y 即可。
简单来说, narrow
就是指限定当前编辑的区域,如果你按下 M-x
并输入
narrow<Tab> 会看到自动补全的三个方法分别是:
narrow-to-defun (C-x n d)
这个方法一般只在 emacs-lisp-mode 有用,将当前编辑区域限定为当前的 (defun ())
区域。
narrow-to-page (C-x n p)
将当前编辑区域限定为当前的 page(?),关于 Page 相关的定义我还没有完全理解,根据我的
use case 基本跟 widen
的功能一致。
narrow-to-region (C-x n n)
这个是我最常用到的,先选定一个区域然后将编辑区域限定为选定的区域。
当然还有恢复到完整显示的方法 widen (C-x n w)
。
处于 narrow 状态时,不管你怎么修改当前区域的内容都不会影响到文件的其余部分,所以就愉快的用 iedit 改掉局部变量的名字吧。
项目的查找替换 projectile & ivy & wgrep
最惨烈的情况当然是一个项目里多个文件里面都需要修改,(包括但不限于 leader 对你起的变量名不满意(x 等情况)。这里就需要一些额外的工具,包括和 ivy 。如果你还没用过 projectile 的话,建议花一点时间熟悉。另外 ivy 并不是必须的,不过非常推荐。
首先查找用 ivy 提供的 counsel-rg
配合 projectile
(defun projectile-smart-search() (interactive) (let ((text (substring-no-properties (or (thing-at-point 'symbol) "")))) (if (projectile-project-p) (counsel-rg text (projectile-project-root)) (counsel-rg text))))
Tips: text 部分的作用是将光标位置所在的单词直接当成搜索字符串,不过这不重要。
当搜索结果出现在 minibuffer 之后,执行 (ivy-occur): C-x C-o
将所有查找结果在另一个 buffer 显示。
如图的情况,假定我现在需要将 struct EmacsRime
改名为 ERime
, 而另一个类型
EmacsRimeCandidates
不需要修改。我需要做的是将光标移动到 EmacsRimeCandidates
行执行
(ivy-occur-delete-candidate): C-d
,保证剩下的都是需要修改的:
使用 (ivy-wgrep-change-to-wgrep-mode): w
切换到 wgrep-mode
使用 iedit
完成修改。按下 C-c C-c
保存即可。
Tips: 使用
C-x s
可以一次性保存所有修改过的 buffer。
通用性
虽然这边举例都是用修改代码来说明,不过这并不意味着这些工具只能在编写代码时有用。比如我需要将本文中的 Emacs 全部替换为 Vim,我需要的操作仅仅是:
- 移动光标到其中一个 Emacs
C-;
M-d
- Vim
C-;