Files
CategoryResourceRepost/极客时间专栏/研发效率破局之道/个人效能/24 | VIM:如何高性价比地学习VIM的实用技巧?.md
louzefeng d3828a7aee mod
2024-07-11 05:50:32 +00:00

335 lines
21 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<audio id="audio" title="24 | VIM如何高性价比地学习VIM的实用技巧" controls="" preload="none"><source id="mp3" src="https://static001.geekbang.org/resource/audio/1d/cf/1daf168653a172ae2e7bf014242d06cf.mp3"></audio>
你好我是葛俊。今天我来和你聊聊VIM的使用技巧。
在“[特别放送 | 每个开发人员都应该学一些VIM](https://time.geekbang.org/column/article/144470)”这篇文章中我和你详细介绍了VIM提高研发效能背后的原因。我推荐每个开发者都应该学一些VIM的原因主要有两个
- 独特的命令模式,可以大量减少按键次数,使得编辑更高效;
- 支持跨平台同时可以在很多其他IDE、编辑器中作为插件使用真正做到一次学习处处使用。
VIM确实可以帮助我们提高效率但面对这样一个学习曲线长而且陡的编辑器我们很容易因为上手太难而放弃。所以如何性价比高地学习VIM的使用技巧非常重要。
我推荐你按照以下三步来高效地学习如何使用VIM
1. 学习VIM的命令模式和命令组合方式
1. 学习VIM最常用的命令
1. 在自己的工作环境中使用VIM比如与命令行环境的集成使用。
接下来,我们分别看看这三步吧。
## VIM的模式机制
VIM的基本模式是命令模式在命令模式中敲击主体键的效果不是直接插入字符而是执行命令实现对文本的修改。
### 使用VIM的最佳工作流
在我看来,在命令模式下工作,效率高、按键少,所以我推荐你**尽量让VIM处于命令模式使用各种命令进行工作。进入编辑模式完成编辑工作之后也立即返回命令模式。**
事实上我们从命令模式进入编辑模式修改文件之后再返回命令模式的全过程就是一个编辑命令。它跟其他的命令比如使用dd删除一行并没有本质区别。接下来我们一起看个具体的例子吧。
比如,我要在一行文字后面加上一个大括号,后面再写一行代码。开始编辑时,光标处于这一行的开头。
```
config =
^
```
修改的目标是这样:
```
config = {
timeout: 1000ms,
}
```
在VIM中我的操作是首先敲击大写字母A将光标移到这一行的末尾并进入编辑模式
```
config =
^
```
然后,输入“{ timeout: 1000ms,回车}”在文件中插入内容。最后敲击Esc键回到命令模式。编辑完成。
```
config = {
timeout: 1000ms,
}
^
```
实际上整个过程就是执行了一条“在本行末尾插入文字”的命令。整条命令的输入是“A{ timeout: 1000ms,回车}Esc”。虽然比较长但仍然是一条文本编辑命令。
所以实际上,**我们在VIM中的工作正是在命令模式里执行一条条的命令完成的**。理解了这一点,你就可以有意识地学习、设计命令来高效地完成工作了。
为了让命令更加高效VIM还提供了强大的命令组合功能使得命令的功能效果呈指数级增长。
### 命令的组合方式
在VIM中有相当一部分命令可以扩展为3部分
- 开头的部分是一个数字,代表重复次数;
- 中间的部分是命令;
- 最后的部分,代表命令的对象。
比如命令3de中3表示执行3次d是删除命令e表示从当前位置到单词的末尾。整条命令的意思就是从当前位置向后删除3个单词。类似的命令3ce表示从当前位置向后删除三个单词然后进入编辑模式。
可以看到,命令组合的前两个部分比较简单,但第三个部分也就是命令对象,技巧就比较多了。所以接下来,我就与你详细介绍下到底有**哪些命令对象可以使用。**
其实,对命令对象并没有一个完整的分类。但我根据经验,将其总结为光标移动命令和文本对象两种。
**第一种是光标移动命令**。比如,`$`命令是移动光标到本行末尾,那么`d$`就表示删除到本行末尾;再比如,`4}`表示向下移动4个由空行隔开的段落那么`d4}`就是删除这4个段落。
这一类命令功能很强大,我们也很熟悉了,但它有一个缺陷,就是选择的出发点始终是当前光标所在位置。而我们在处理文本的过程中,尤其是在编写程序的时候,光标所在位置常常是处于需要修改内容的中间,而不是开头。比如,我们常常在写一个注释字符串的时候,需要修改整个字符串:
```
comment: 'this is standalone mode',
^
```
如果使用上面的光标移动作为命令对象的话我们需要执行bbbct命令也就是向左移动三个单词之后再向右删除到第一个单引号的地方操作起来很麻烦。
针对这种情况VIM提供了第二种命令对象**文本对象**。具体来说就是用字符代表一定的文字单位。比如i"代表两个双引号之间的字符串aw表示当前的单词。使用这种文本对象很方便比如上面的编辑例子我们只需要命令ci"就可以实现比bbbct命令方便了很多。
具体来说,文本对象命令由两部分组成:
- 第一部分只能是字符i或者a表示是否包含对象边界。比如i"表示不包括两边的引号而a"就包括引号;
- 第二部分选择比较多,表示各种不同的文本对象。比如
<img src="https://static001.geekbang.org/resource/image/17/22/17ef1f7dba10731966b0048dac716c22.jpg" alt="">
如果你要查看完整的文本对象,可以使用:help text-objects。
这一组文本对象选择功能很强大而且是VIM自带功能不需要安装任何插件。神奇的是不知道为什么很多使用VIM很久的人都不知道这个功能。我个人把它叫作vip功能如果你以前没有用过可以在文件中输入命令vip看看效果。相信不会让你失望。
可见VIM的命令操作及其组合功能非常强大要高效使用VIM我们就必须使用命令模式以及命令组合。我看到有些开发者使用VIM时一上来就使用i命令进入编辑模式然后在编辑模式中工作。但是编辑模式的功能很有限完全发挥不出VIM提供的高效文本编辑功能。
接下来我们进入第二步也就是学习VIM最常用的命令。
## 命令模式中的基础命令
VIM有大量的命令可供我们使用这里我主要与你介绍针对单个文件编辑的命令因为这是编辑工作最基础的部分也是各种跨平台场景尤其在其他IDE中通过插件使用VIM的方式的共性部分。
至于更多的命令和细节,你可以参考我的“[命令模式中的基础命令](https://jungejason.github.io/vim-commands/)”这篇博客,或者自行搜索查询。
接下来,我会按照以下编辑文件的逻辑顺序,来与你介绍关键知识点和技巧:
1. 打开文件,以及进行设置操作;
1. 移动光标;
1. 编辑文本;
1. 查找、替换。
### 第一组常用命令是,打开文件以及对文件的设置
这些命令包括打开文件、退出、保存、设置等。关于设置,如果在远端的服务器上,我常常运行一条命令进行基本设置:
```
:set ic hls is hid nu
```
其中ic表示搜索时忽略大小写hls表示高亮显示搜索结果is表示增量搜索也就是在搜索输入的过程中在按回车键之前就实时显示当前的匹配结果hid表示让VIM支持多文件操作nu表示显示行号。
如果要关闭其中某一个选项的话在前面添加一个no即可。比如关闭显示行号使用
```
:set nonu
```
### 第二组常用命令是,移动光标
VIM提供了非常细粒度的光标移动命令包括水平移动、上下移动、文字段落的移动。这些命令之间的差别很细微。比如w和e都是向右边移动一个单词只不过w是把光标放到下一个单词开头而e是把光标放到这一个单词结尾。
虽然差别很小但正是这样的细粒度才使得VIM能够让我们使用最少的按键次数去完成编辑任务。
### 第三组常用命令是,编辑命令
编辑工作中我们应该大量使用命令组合来提高效率。关于组合命令的威力,我建议你看下“[命令模式中的基础命令](https://jungejason.github.io/vim-commands/)”那篇博客我与你详细解释了一个ct"的例子。
这里,**我重点与你分享一个设计命令的技巧**。VIM的取消命令u、重复命令.,都是针对上一个完整的编辑命令而言。所以,我们可以设计一个完整的编辑命令,从而可以使用重复命令.来提高效率。比如你要把一段文本中的几个时间都修改成20ms这段文本原来是
```
timeout: 1000000ms,
waiting: 300000ms,
starting: 40000ms,
```
希望改变成
```
timeout: 20ms,
waiting: 20ms,
starting: 20ms,
```
在VIM中有多种实现方法。一种还不错的方法是使用修改命令c和移动命令l的组合在每一行用一个命令搞定。具体操作是将光标挪到1000000ms里数字1的地方用c7l20命令对第一行进行修改然后在第二行、第三行的相同位置分别使用c6l20和c5l20进行修改。
这个命令可以完成工作,但每条命令都不一样,不能重复。实际上,还有一种更好的方法。
你可以设计一条命令在每一行重复使用。在这个例子里这个命令是ctm20<esc>意思是从当前位置删除到下一个字母m的位置进入编辑模式插入20然后返回命令模式。</esc>
使用这条命令对第一行进行修改之后,你可以把光标挪到第二、三行使用重复命令.来完成编辑任务,如下所示。
<img src="https://static001.geekbang.org/resource/image/92/5e/92124bb53e6bfa3c5fb0c1f3d5273a5e.gif" alt="">
当然了,你还可以使用正则表达式进行查找替换,但是远比上面这个重复命令要复杂。这个设计命令并重复使用的方法非常好用,建议你上手实践下。
关于重复命令VIM另外还有一个录制命令q和重复命令@,功能更强大,但也比较重。如果你想深入了解的话,[可以参考这篇文章](https://xu3352.github.io/linux/2018/11/04/practical-vim-skills-chapter-11)。
### 第四组常用命令是,查找、替换
这组命令主要有/、*和s等很常用网络上也有很多描述这里我就不再详细介绍了。比如我在“[命令模式中的基础命令](https://jungejason.github.io/vim-commands/)”这篇博客中详细介绍了s命令可供你参考。
除了上述4种常见命令外VIM中还有一种很强大的可视模式Visual Mode可以提高编辑体验。接下来我们再一起看看。
### 可视模式
可视模式一共有3种包括基于字符的可视模式、基于行的可视模式和基于列的可视模式详见“[命令模式中的基础命令](https://jungejason.github.io/vim-commands/)”这篇博客中的介绍。
接下来,我以基于列的可视模式为例,带你看看可视模式是如何提高编辑体验的吧。
我们先来看看第一个例子。有一段文本每一行都用var声明变量比如var gameMode现在我希望改成使用const来声明。我们来看看具体的实现方式。
<img src="https://static001.geekbang.org/resource/image/ca/63/ca00ba7234b33295581aa3ff04469963.png" alt="">
第一步,把光标挪到第一行开头的 v 字符处使用组合键Ctrl-v进入列可视模式然后使用7j下移动七行再用e向右移动一个单词从而选中一个包含所有var的矩形区域。
<img src="https://static001.geekbang.org/resource/image/71/b4/71de442222209adc9b9c86813da264b4.png" alt="">
第二步是开始编辑。输入c删除所有的var并进入编辑模式。
<img src="https://static001.geekbang.org/resource/image/1b/58/1bcd320829837a41bb513978b3432a58.png" alt="">
第三步是输入const并输入Esc完成编辑操作回到命令模式整个修改完成。
<img src="https://static001.geekbang.org/resource/image/37/e8/377269a6d42aa02d4d8f6ade37bf77e8.png" alt="">
<img src="https://static001.geekbang.org/resource/image/58/ff/58aaa90b1938cd51464f6bdf2330acff.png" alt="">
我们再来看看第二个例子。我希望在上面这段文字的每一行末尾都添加一个分号。具体的操作步骤如下所示:
首先,用$命令把光标挪到最后一行的末尾然后Ctrl-v进入列模式再用7j命令将光标挪到第一行这时每一行的末尾都被包含到了一个方块里。不过因为每一行的长度不同所以方块没有显示完全。
<img src="https://static001.geekbang.org/resource/image/3c/ad/3cea82dcf9ba1c4a9053ccd4d5e839ad.png" alt="">
然后输入A命令光标挪到每一行的末尾并进入编辑模式。
<img src="https://static001.geekbang.org/resource/image/db/84/dbecf5cbb5b75cf002270c154abbdc84.png" alt="">
最后输入要插入的分号输入Esc完成编辑。这样每一行的末尾都添加了一个分号。
<img src="https://static001.geekbang.org/resource/image/be/8b/be6fa0acecd2dee663df3deb1929b68b.png" alt="">
<img src="https://static001.geekbang.org/resource/image/a7/4b/a7ac6e2c639334b799058b2dd243c64b.png" alt="">
最后,关于可视模式我还有三个比较有用的小贴士:
- 第一在退出了可视模式之后可以使用gv命令重新进入可视模式并选择上一次的选择。这个命令出乎意料得有用因为我们常常需要对上一次的选择进行进一步的操作。
- 第二进入可视模式之后可以直接使用v、V、Ctrl-v在三种模式之间切换而不需要退出可视模式再重新进入。比如你一开始使用v进入了字符可视模式这时发现你需要删除几行就可以直接输入V进入行的可视模式。
- 第三修改选取的区域范围。当你进入可视模式之后光标默认处于所选区域的结尾处你可以挪动光标调节选择区域的结尾部分。但如果你想调节的是所选区域的开头部分则可以使用命令o将光标跳到选择区域的开始部分再次输入命令o光标又会跳到选择区域的末尾。一个更好玩的情况是在列模式中你可以使用小写o在对角线上跳转大写O在水平方向跳转从而可以灵活调整所选矩形的四个角。
以上就是命令模式中的常用基础命令了。理解了这些命令再加上命令组合你就可以比较高效地使用VIM进行文本编辑了。但要更高效地使用VIM我们还有一个问题没有解决VIM虽然强大但也只是整个工作环境中的一个工具怎样才能在整个工作中高效地使用VIM技能呢
所以接下来我将带你探索如何寻找合适的VIM使用场景。
## 寻找合适的VIM使用场景
寻找合适的适用场景常常包括两种情况一是VIM不是主力IDE的情况二是VIM与其他工具的集成。接下来我们先看第一种情况。
### 我的工作环境中VIM不是主力IDE怎么办
这种情况下我会建议你先看一下你的主力IDE是否支持VI模式。目前绝大部分主流IDE都支持而且大都做得不错。如果你的主力IDE中能使用VIM命令的话那从VIM特有的命令模式就能让你收益颇丰。
从我的经验来看我只有在Facebook那几年使用VIM作为主力IDE其他时间使用的编辑器主要是Intellij的IDE系列和VS Code。在这些IDE里我一直在使用VI模式效果也都很好。
除了在主力IDE中使用VI模式外你还可以选择把VIM只作为一个单纯的文本编辑器需要强大的编辑功能时临时用一下就可以。比如我在写微信小程序的时候一开始使用的是原生的微信开发工具编辑功能不是太强。所以在遇到一些重量级的编辑工作时我就打开VIM快速搞定然后再回到微信原生开发工具IDE里继续工作。
### VIM能在Linux命令行环境中与其他工具结合的很好
Unix/Linux系统的一个设计理念是每个工具都只做一个功能并且把这个功能做到极致然后由操作系统把这些功能集成起来。VI当初就是作为Unix系统里的编辑器而存在的到了40年后的今天虽然VIM已经可以被配置成为一个强大的IDE但很大程度上依然是Unix/Linux系统的基础编辑器仍然可以很方便地和Unix/Linux的其他工具集成。
为了帮助你理解我再和你分享3个适用场景。
**第一个场景使用VIM作为其他工具的编辑器。**
在大部分Linux系统里默认的编辑器就是VIM。如果不是的话可以使用如下命令来设置
```
// 全局使用VIM
export EDITOR='vim'
```
**第二个适用场景使用管道Pipe。**
管道是Linux环境中最常用的工具之间的集成方式。VIM可以接收管道传过来的内容。比如我们要查看GitHub上用户xxx的代码仓的情况可以使用下面这条命令
```
curl -s https://api.github.com/users/xxx/repos | vim -
```
curl命令访问GitHub的API把输出通过管道传给VIM方便我直接在VIM中查看用户xxx的代码仓的细节。
这里需要注意的是在VIM命令后面有一个-表示VIM将使用管道作为输入。
**第三个适用场景在VIM中调用系统工具**
除了系统调用VIM和使用管道进行集成之外我们还可以在VIM中反过来调用系统的其他工具。这里我与你介绍一个最实用的命令**在可视模式中使用!命令调用外部程序。**
比如我想给一个文件里的中间几行内容前加上从1000开始的数字序号。
<img src="https://static001.geekbang.org/resource/image/f7/cc/f72d9d852cdca00c79544ef3a41dd3cc.png" alt="">
在Linux系统里我们可以使用nl这个命令行工具完成具体的命令是nl -v 1000。所以我们可以把这一部分文本单独保存为文件使用nl处理后再把处理结果拷贝回VIM中。
虽然可以达到目的但过程繁琐。幸运的是我们可以在VIM里面直接使用nl并把处理结果插入VIM中具体操作如下。
首先使用命令V进入可视模式并选择这一部分文字。
<img src="https://static001.geekbang.org/resource/image/69/37/6962fb43054994be72fcd30f89802437.png" alt="">
然后,输入命令!VIM的最后一行会显示&lt;,&gt;! 表示由外部程序操作选中的部分。这时我们输入nl -v 1000并回车。
<img src="https://static001.geekbang.org/resource/image/0d/7d/0dd3edaf5ca34ae776d1527fbbee547d.png" alt="">
VIM就会把选择的文本传给nlnl在每一行前面添加序号再把处理结果传给VIM从而完成了我们想要的编辑结果也就是在所选的几行文字前面添加从1000到1006的序号。
<img src="https://static001.geekbang.org/resource/image/5a/fd/5a7aa3f398c73283234d386a603bc3fd.png" alt="">
同时在VIM的底部会显示7 lines filtered意思是VIM里面的7行文本被使用外部工具处理过。是不是很方便
我每次使用这样的功能时都觉得很爽,因为这可以让我聚焦在工作上,而不会把时间花在繁琐的操作上。
以上就是3个最常用的VIM和其他工具集成的例子。这种工具的集成工作方式可以大大提高单个工具所能带来的效率提升我还会在后面的文章中与你详细讨论。
## 总结
在今天这篇文章中我与你介绍了高效学习VIM的三个步骤第一学习VIM的命令模式和命令组合方式第二学习文本编辑过程中各个环节最常用的命令第三在自己的工作环境中找到适用VIM的场景。
事实上我今天与你讲述的VIM命令和使用技巧只是最常见的跨平台使用中的共性部分对效能提升带来的效果也最直接、最明显。
这些远没有覆盖VIM的强大功能。比如我没有与你讨论多文件、多Tab、多窗口编辑的场景以及插件的话题。如果你需要的话可以把VIM配置成一个类似IDE的开发环境进入沉浸式的VIM使用体验。关于插件方面的内容我推荐3个插件
- [pathogen](https://github.com/tpope/vim-pathogen)。它是一个插件管理软件很好地解决了VIM自带插件删除不理想的问题。关于pathogen的使用你可以参考下[这篇文章](https://gist.github.com/romainl/9970697)。
- [nerdtree](https://github.com/scrooloose/nerdtree)在VIM中添加文件夹管理的功能。
- [fugitive](https://github.com/tpope/vim-fugitive)在VIM中添加查看、编辑Git内容的功能。它的功能简直是强大到变态。
其中pathogen和fugitive的作者都是[Tim Pope](https://github.com/tpope)一个VIM牛人。如果你想了解更多的插件的话可以看看他的其他VIM插件。
不容置疑的是VIM的学习曲线非常长即使我已经使用了15年仍然会时不时地学习到一些新东西。只要你愿意就可以一直学习一直提高。
## 思考题
你想要分享的最炫酷的VIM技巧是什么呢
感谢你的收听,欢迎你在评论区给我留言分享你的观点,也欢迎你把这篇文章分享给更多的朋友一起阅读。我们下期再见!