vim-best-practice
Practice
.
命令
基本
.
命令可以让我们重复上次的 修改,它是 Vim 中最为强大的多面手。
要理解 .
命令的强大,我们需要意识到这一点:上次修改 可以指很多东西,一次修改的单位可以是字符、整行,甚至是整个文件。
同时这也代表着修改外的操作不会重复,比如 j ,j. 并不会移动两行
.
命令是一个微型宏:
- 重复普通模式的命令
- 重复插入模式的所有按键操作
我们进入插入模式时,也会形成一次修改。从进入插入模式的那一刻起(例如,输入 i),直到返回普通模式时为止(输入 <Esc>
),Vim 会记录每一个按键操作。做出这样一个修改后再用 . 命令的话,它将会重新执行所有这些按键操作(参见技巧 8 中的“在插入模式中移动光标会重置修改状态”部分中的补充说明)。
一键移动,另一键操作
在每行末尾插入分号,我们通过用 A 来代替 $a,大大提升了 . 命令的效率。我们不必再把光标移到行尾,只需保证它位于该行内就行了(可在任意位置)。现在我们可以重复执行足够多次的 j. ,完成对后续行的修改。
退一步然后前进三步
insert 类复合命令 最终都会进入到 insert 模式,这对 .
命令会造成什么影响?
s 命令把两个操作合并为一个:它先删除光标下的字符,然后进入插入模式。在删除 + 号后,我们先输入 空格 + 空格,然后退出插入模式。
先后退一步,然后前进三步,这是个奇怪的小花招,看起来可能不够直接。
但这样做最大的好处是:我们可以用 . 命令重复这一修改。我们所要做的只是把光标移到下一个 + 号处,然后用 . 命令重复这一操作即可。
查找并手动替换
当光标位于“content”的开头时,我们就可以着手修改它。这包括两步操作:首先要删除单词“content”,然后输入替代的单词。cw 命令会删除从光标位置到单词结尾间的字符,并进入插入模式,接下来我们就可以输入单词“copy”了。Vim 会把我们离开插入模式之前的全部按键操作都记录下来,因此整个 cwcopy<Esc>
会被当成一个修改。也就是说,执行 .
命令会删除从光标到当前单词结尾间的字符,并把它修改为“copy”。
如果我们想替换所有地方,就可以不加思考地一直按 n.n.n. 以完成所有的修改(但是,这种情况下也可以用 :%s/content/copy/g 命令)
所有可重复的命令
我们已经看到 . 命令会重复上次修改。由于很多操作都被当成一次修改,因此 . 命令已经证明了它的神通广大。
但有些命令能以其他的方式重复。例如,@: 可以用来重复任意 Ex 命令(在技巧 31 中讨论),或者我们也可以输入 & (参见技巧 92)来重复上次的:substitute 命令(它本身也是一条 E x 命令)。
.
范式
用一次按键移动,另一次按键执行,没有再比这更好的了,不是吗?这就是我们的理想解决方案。我们将会一次又一次地看到这一编辑模式,所以为了方便起见,我们把它叫做“. 范式”。
构造可重复的修改
Vim 对重复操作进行了优化,要利用这一点,我们必须考虑该如何构造修改。
在 Vim 中,要完成一件事,总是有不止一种方式。在评估哪种方式最好时,最显而易见的指标是效率,即哪种手段需要的按键次数最少(又名 VimGolf[插图])。然而,在平局时该如何选择获胜者呢?
最后的方案只调用一个操作:daw。这个操作不仅仅删除了该单词,它还会删除一个空格,因此光标最终会停在单词“is”的最后一个字符上。如果此时我们使用 .
命令,它会重复上次删除单词的命令。这一次,. 命令会做真正有用的事情(. = =daw)
能够重复,就别用次数
概括一下,我们的 3 种选择 d2w、2dw 或者 dw. 都是 3 次按键,不过哪一种最好呢?根据我们的讨论,d2w 和 2dw 是相同的,在执行完两者中的任一个后,我们可以按 u 键撤销,这样两个被删除的单词又会回来。或者,我们不是用撤销,而是用 .命令重复执行它,这就会删除后面的两个单词。
对于 dw. 的情形,按 u 或 . 的结果会有细微的差别。这里的修改是 dw,即删除一个单词。因此,如果想恢复这两个被删除的单词,必须撤销两次,按 uu(或者,如果你愿意,也可以按 2u)。按 . 则只删除后面的一个单词,而不是两个。
现在假设我们原本是想删除 3 个单词,而不是 2 个。由于判断出了点差错,我们执行了 d2w 而不是 d3w,那接下来怎么做?我们不能使用 . 命令,因为那会总共删除 4 个单词。因此,我们或是先撤销而后修正次数(ud3w),或是继续删除下一个单词(dw)。
现在考虑另一种方案,如果我们在第一处地方用的是 dw. 命令,那么我们只要再多重复一次 . 命令就行了。因为我们最初的修改只是简单的 dw,因此 u 命令和 . 命令都具有更细的粒度,每次只作用于一个单词。
现在假设我们想删除 7 个单词,我们可以运行 d7w,或是 dw......(即 dw 后面跟 6 次 . 命令)。计算一下按键的次数,哪个命令胜出是很显而易见的。不过你真地确信自己数对了次数吗?
计算次数很是讨厌,因此我宁愿按 6 次 . 命令,也不愿意只为减少按键的次数,而浪费同样的时间去统计次数。如果我多按了一次 . 命令怎么办?没关系,只要按一次 u 键就可以回退回来。
在此场景中,使用 . 命令的意义不大,我们可以删除一个单词,然后再用 . 命令删除另一个,但随后我们还得切换到插入模式(例如,使用 i 或 cw)。对我来说这么做很不顺手,我反而更愿意用次数。使用次数的另一个好处是:它保留了一个干净、连贯的撤销历史记录。完成这次修改后,我们按一下 u 键就可以撤销整个修改。
对于是用次数风格(d5w)还是用重复风格(dw....)也有同样的争论,因此我的偏好看起来似乎不太一致。对此,你要总结自己的观点,这取决于你怎么看保留干净撤销历史记录的价值,以及你是否觉得用次数令人生厌。
停顿时请移开画笔
普通模式看上去是一种奇怪的缺省状态
本节使用了一个比喻来说明为什么 Vim 要采用这种方式。你估计画家会花费多少时间用画笔在画布上作画?毫无疑问,这因人而异,但是,如果这占了画家全部工作时间的一半还要多的话,我会觉得非常诧异。
想一下除了画画外,画家还要做哪些事情。他们要研究主题,调整光线,把颜料混合成新的色彩。而且,在把颜料往画布上画时,谁说他们必须要用画笔?画家也许会换用刻刀来实现不同的质地,或是用棉签来对已经画好的地方进行润色。
画家在休息时不会把画笔放在画布上。对 Vim 而言也是这样,普通模式就是 Vim 的自然放松状态,其名字已经寓示了这一点。
就像画家只花一小部分时间涂色一样,程序员也只花一小部分时间编写代码。绝大多数时间用来思考、阅读,以及在代码中穿梭浏览。而且,当确实需要做修改时,谁说一定要切换到插入模式才行?我们可以重新调整已有代码的格式,复制它们,移动其位置,或是删除它们。
在普通模式中,我们有众多的工具可以利用。
把撤销单元切成块
u 键会触发撤销命令,它会撤销最新的修改。一次修改可以是改变文档内文本的任意操作,其中包括在普通模式、可视模式以及命令行模式中所触发的命令,而且一次修改也包括了在插入模式中输入(或删除)的文本,因此我们也可以说,i{insertsome text}<Esc>
是一次修改。
那么,应该多久离开一次插入模式呢?这是个人喜好的问题,不过我喜欢让每个“可撤销块”对应一次思考过程。在写这段文字时(当然是在 Vim 中写的),我经常在每句话的结尾停顿一下,想一想接下来该写什么。不管停顿的时间有多短,每次停顿都是一个自然的中断点,提示我该退出插入模式了。当我准备好继续写时,按 A 命令就可以回到原来的地方继续写作。
当处于插入模式时,如果光标位于行尾的话,另起一行最快的方式是按 <CR>
。不过有时我更喜欢按 <Esc>o
,这是因为我有预感,也许在撤销时我想拥有更细的粒度。如果听起来这不太好理解,不必担心,当你对 Vim 越来越熟悉时,就会感到切换模式越来越轻松。一般来讲,如果你停顿的时间长到足以问“我应该退出插入模式吗?”这个问题,那么就退出吧。
在插入模式中移动光标会重置修改状态
当我提到撤销命令会回退从进入插入模式到退出此模式期间输入(或删除)的全部字符时,我略过了一个小细节。如果在插入模式中使用了 <Up>
、<Down>
、<Left>
或 <Right>
这些光标键,将会产生一个新的撤销块。
你可以把这想象为先切换回普通模式,然后用 h、j、k 或 l 命令对光标进行了移动,唯一区别是我们并没有退出插入模式。这也会对 .
命令的操作产生影响。
操作符待决模式
概述
如果我们把 Vim 想象成有限状态机,那么操作符待决模式就是一个只接受动作命令的状态。
这个状态在我们调用操作符时被激活,然后什么也不做,直到我们提供了一个动作命令,完成整个操作。
当操作符待决模式被激活时,我们可以像平常一样按 <Esc>
中止该操作,返回到普通模式。
激活
很多命令都由两个或更多的按键来调用(查阅:h g、:h z、:h ctrl-w,或者:h [,可以看到一些例子),但在多数情况下,头一个按键只是第二个按键的前缀。
这些命令不会激活操作符待决模式,相反,可以把它们当成命名空间(namespace),用来扩充可用命令的数目。只有操作符才会激活操作符待决模式。
作用
你也许想知道,为什么要有一个完整的模式,专门用于操作符和动作命令之间的短暂瞬间,而命名空间命令则仅仅是普通模式的一个扩充?
好问题!这是因为我们能够创建自定义映射项来激活或终结操作符待决模式。
换句话说,它允许我们创建自定义的操作符及动作命令,从而让我们可以扩充 Vim 的词汇。
FAQ
Gvim 和 Neo Vim 原生 Vim 的区别?
gvim = gui + vim 可以使用用 Cmd-X 和 Cmd-V 与系统剪切板交互,也可以用 Cmd-S 保存文件,用 Cmd-W 关闭一个窗口。如果你能接受的话,可以用这些命令,不过你应该已意识到,还有更好的方法完成这些
neo vim 等于 vim refactor
Vim 对“i”及“a”键的约定 Vim
对于从普通模式切换到插入模式的命令有几个约定,i 命令和 a 命令都完成此切换,并分别把光标置于当前字符之前或之后。
I 命令和 A 命令的表现类似,只是它们分别把光标置于当前行的开头和结尾。
Vim 对于从列块可视模式切换到插入模式的命令也遵从类似的约定。I 命令和 A 命令都完成此切换,并分别把光标置于选区的开头和结尾。
那 i 和 a 命令呢,它们在可视模式里干什么?
在可视模式及操作符待决模式中,i 和 a 键沿用一个不同的约定。它们会被当作一个文本对象的组成,我们将在技巧 51 中深入探讨文本对象。如果你在列块可视模式里选中了一块区域,并且很奇怪为什么按 i 键没进入插入模式,那么换用 I 键试一下。
如何使用 Vim 的 Huge 功能集呢?
如何执行外部的快捷键?
比如 cmd + b 切换 vscode 侧边栏,我不想覆盖 vscode 的默认快捷键,最好是有一个 leader key 告诉 vim,我要执行外部的快捷键了
Mac 下和 Win 下 Vim 配置的同步是个难题
win 下经常需要设置各种环境变量,感觉挺麻烦的
目前的方法只能是减少配置,如果永远只使用原生配置,那无论是换成任何一台 win、mac 电脑都不用同步了
让 F 可以搜索全角、半角字符
不然每次中文搜索都得切换太麻烦了
Visual Mode Quick Highlight
how to highlight as fast as possible
Scroll Half Screen
how to scroll half screen and let mouse focus screen middle line