积累沉淀

待山花烂漫,化茧成蝶

Vim 教程

什么是Vim

  • Vim是最流行的文本编辑软件之一,有"编辑器之神"的美誉
  • 社区活跃,插件丰富,生态优秀
  • 许多IDE都支持Vim模式:VSCode、JetBrains系列

vim 在编程中的小Tips

  1. 光标在函数上时,gd 跳转到函数定义或声明;gd— go to definition
  2. gt —在标签中向后跳转; gT — 在标签中向前跳转;gi—快速跳转到上次编辑的位置进入插入模式;
  3. ctrl + o 依次返回光标的位置;
  4. ctrl + i:跳回下一个位置;
  5. 在终端中输入命令 如 git clone xxxxxxxxxxxxxxxxxxxxxxxxxx或时其他复杂命令很长的修改该过程如下:ctrl+a 移动行首;
    ctrl+e 移动行尾;ctrl+f 往后移动;ctrl+b 往前移动;

Normal模式:基本移动

  • hjkl:上下左右
  • gg:跳到第一行(类似Home键) G:跳到最后一行(类似End键)
  • <Ctrl-u>/<Ctrl-b>:往上翻半页/一页(类似PageUp键) <Ctrl-d>/<Ctrl-f>:往下翻半页/一页(类似PageDown键)
  • {Lineno}gg:跳到第lineno 行
  • zz/zt/zb:光标行设置为屏幕居中/屏幕第一行/屏幕最后一行
  • L — 移动屏幕尾;H—移动屏幕首;M—移动到屏幕中;

进入Insert模式

Normal模式下通过特定命令进入Insert模式

  • i:代表"insert",当前光标之前开始输入
  • a:代表"append",当前光标之后开始输入
  • o: 下方插入新的一行,然后开始输入
  • s:删除当前光标的字符,然后开始输入
  • r: 替换模式,ra — 将当前字符替换为a
  • R: 替换模式,替换行,输入内容会覆盖当前内容;
  • I:在本行的开头开始输入
  • A:在本行的末尾开始输入
  • O:上方插入新的一行,然后开始输入
  • S:删除当前行,然后开始输入
    Tips:大写字母和小写字母的操作存在关联,可以一起记忆

进入Command模式

Normal模式下输入:进入Command模式

  • w:保存当前文件:q:退出
  • q!:放弃当前更改,然后退出:wq:保存当前更改,然后退出
  • h{command}:显示关于命令的帮助
  • <Esc>回到Normal模式

进入Visual模式

  • Normal模式下按v进入可视模式
  • 进入可视模式后可以用Normal模式下的移动命令选择文本
  • 可视模式下×/y:剪切/复制;
  • 回到Normal模式下p:粘贴
  • Normal模式下按V进入行可视模式,一次选中一整行,在需要选中多行时很方便
  • <Esc>回到Normal模式

Vim:移动与编辑

基于单词的移动

简单的hjkl显然无法满足我们的需要

  • w:代表"word",跳转到下一处单词的开头
  • b:代表"back",跳转到上一处单词的开头
  • e:代表"end",跳转到下一处单词的结尾
  • ge:e的反向版本,跳转到上一处单词的结尾
    wbe大写版本WBE对应的单词是连续的非空字符

基于搜索的移动行内搜索

  • f{char}/t{char}:跳转到本行下一个char字符出现处/出现前
  • ;/,:快速向后/向前重复ft查找
  • F{char}/T{char}:往前搜索而非往后文件中搜索:
  • /{pattern}:跳转到本文件中下一个pattern出现的地方
  • ?{pattern}:跳转到本文件中上一个pattern出现的地方
  • pattern可以是正则表达式
  • *:等价于/{pattern},pattern是当前光标下的单词
  • nN:快速重复/查找

基于标记的移动

  • m{mark}:把当前位置标记为mark
  • `{mark}:跳转到名为mark的标记位置
    mark是a-z的字符
    常用场景:当需要临时离开当前光标处,做一些事情后再快速地回来
    我比较习惯用的标记是mm
    内置标记:
  • ``:上次跳转前的位置
  • `.: 上次修改的位置
  • `^:上次插入的位置

其它实用的跳转

  • ^/$:跳转到本行的开始/结尾
  • %:跳到匹配的配对符(括号等)处

快速编辑

Vim-Action

重复操作:.命令

  • .:重复上一次修改
  • u:撤销上一次修改
  • <Ctrl-r>:重做上一次修改
    . 命令非常适合用于需要多次重复某一个修改动作的场景省去了重复输入命令,大大提高效率

批量操作:数字+动作

{count}{action}:重复count次action
动作动作可以是移动动作或是编辑动作

  • 4j:向下移动4行
  • 3dw:删除3个单词
  • 2yy:复制2行
  • 4p:粘贴4次

数字+动作,是一种重要的批量操作方式,命令直观,语义明确

  • .命令可以直观地看到每一次的变化,在合适的时候停止
  • 数字+动作则需要预先知道动作的次数

文本对象操作

textobjects:语义化的文本片段
格式:i/a+对象常见的对象:

  • w/w,s,p,t,b,(, [, {:单词/联单词、句子、段落、标签、()、[]、{};
    *(/),[/」,{/},</>,‘/“:配对符定义的对象
    i代表"inner”,内部;
    a代表"a",额外包括周围的空格或配对符

文本对象操作:例子

文本对象提供了为文本赋予了结构化的含义,允许我们以一个语义对象作为操作单元
[count]{operator}{textobjects}

  • diw:删除一个单词
  • ci(:修改小括号内部
  • yi{:复制大括号内部

通过组合operator与textobjects,可以对不同的语义对象实施不同的操作,不仅十分灵活,而且语义明确,容易记忆
配合:命令或【count】可以简单地完成多次对特定语义对象的操作

textobjectsVSmotion

{operator}{motion}与{operator}{textobjects} 解耦了操作与操作的对象,大大提升了操作效率

  • motion是能够移动光标的命令,可以独立使用(如wbe)
  • 文本对象只能跟在operator后面,不能独立使用(如iw)
  • motion通过光标的移动确定operator的作用范围,范围更加灵活但不够明确
  • textobjects则是显式地指定操作的对象,范围明确

操作符与命令补充

  • gu/gU/g~:操作符,转小写/转大写/翻转大小写 例如:guiw, gUiw, 符合{Operator}{textobjects} 或者 {operator}{motion}
  • J:join,连接两行
  • <Ctrl-a>/<Ctrl-x>:增加数字/减少数字
  • g<Ctrl-A>:创建递增序列
  • </>:左/右缩进

建议:让你的命令更模块化
尽量使你的命令更模块化,具有清晰的含义与作用范围,以便于与·等命令协同例如:daw比dw具有更清晰的语义,也更模块化

寄存器

Vim提供了许多寄存器用于存放内容,可以理解为剪贴板
一个字符对应一个寄存器(如a-z,0-9)特别的寄存器:

  • ":默认寄存器,平时复制、删除的内容都放在里面
  • %:当前文件名
  • .:上一次插入的内容
  • ::上一次执行的命令

通过:reg{register}查看对应寄存器中的内容

指定寄存器

在复制/删除/粘贴等操作前加上"{register}就可以指定本次操作所用的寄存器
只要涉及寄存器操作的都可以这样指定

  • "ayy:将这一行复制到a寄存器中
  • "bdiw:将单词删除,保存到b寄存器中
  • "cp:将c寄存器中的内容粘贴出来

常见用途:将想要持久保存的文本放到特定寄存器里,随时进行粘贴,避免被覆盖
寄存器字符大写:添加(append)而非覆盖


宏(Macro):录制一系列键盘操作,并允许我们重放这些操作操作序列存储在指定的寄存器中

  • q{register}:开始录制宏,存在寄存器register 中
  • 录制过程中按q退出录制
  • @{register}:重放寄存器register中的操作
  • @@:重放上一次宏操作

常见用法:q{register}录制一段操作,@{register}重放,然后一直@@重放注意::命令对宏不生效,.命令只记录上一次修改,而宏可能包含多次修改
命令:.,$ normal @a

建议:让你的宏对连续重放友好

  1. 让你的光标移动更加general
  2. 假设你要在多个特定的位置进行特定的操作,一个好的习惯是在宏录制的最后,跳转到下一个需要编辑的位置
    即,宏包括【编辑动作】+【跳转到下一个需要编辑的位置】
    这样一来,连续重放就可以实现对所有需要编辑的位置进行编辑操作通过大写的寄存器,在宏的后面添加命令
    如果宏是重放友好的,允许我们使用[count]@{register}直接重放count次

vim 命令模式

  1. 前面的教程大多集中在Normal模式
  2. 命令模式提供了除了Normal模式的编辑方式
  3. 命令模式的操作对象以“行”为基本单位
  4. normal和global命令提供强大的批量行操作

Ex命令格式

:[range] {excommand} [args]

  • range:作用的范围,不给的话默认是本行
  • excommand:特殊的命令,适用于Command模式
  • args:后续的参数,视命令而定

一些ExCommand([x]为寄存器,是可选项):

  • :[range] delete[x]:删除range中的行(到寄存器x),delete可简写为 d
  • :[range] yank[x]:复制range中的行(到寄存器x),yank可简写为y
  • :[range] print:将range 中行打印出来,print 可简写为p

range与address:指定范围

range由一个或两个address构成,即{address}或{address},{address} address可以是:

  • {lineno}:行号,如3代表第三行(o代表第一行上面的虚拟行)
  • $:最后一行
  • .:光标所在行
  • /{pattern}/:下一个pattern所在的行
    address可以做加减法,.+3代表光标往下第三行,$-3代表倒数第4行

address组合成range

address组合出range(可以混用):

  • 1,3:文件的1-3行
  • .,·+4:当前-当前往下4行 (共5 行)
  • $-3,$:文件的最后4行
  • %:特殊的range,代表当前文件的所有行
  • </'>:可视模式中选中范围的开头和结尾(可视模式下直接按:可以直接设置)
    例子:
  • :1,3 delete:删除1~3行
  • :.,.+4 yank:复制当前-当前往下4 行
  • :$-3,$ print: 打印文件的最后4行

行的复制、移动、粘贴

  • :[range]copy{address}:把range中的行复制到address后面
  • :[range]move{address}:把range中的行移动到address后面
  • :[address]put[x]:把寄存器×的内容粘贴到address后面

0作为虚拟行的address,可以用来将内容插入第一行

批量操作:normal命令

格式::[range]normal{commands}
含义:对range中的所有行执行Normal模式下的命令commands

  • 将range设置为%,可以对整个文件的所有行执行
  • :[range] normal. :配合,命令,效果拔群
    常用做法:先做一次修改操作,再用normal命令在指定的行上完成操作
  • .命令只能记录一次修改,用宏可以实现记录多个操作:[range] noraml @{register}
    常用做法:先把想要的操作录制成宏,再用normal命令在指定的行上重放宏

批量操作:global命令

  • 格式::[range]global/{pattern}/[cmd]
  • 含义:对range中包含pattern的所有行执行Command模式下的Ex命令
  • [cmd]:Ex命令,不给的话默认是打印(print)注意,normal命令也是Ex命令!
  • :[range]global/{pattern}/normal{commands}:对range中所有带pattern的
    行,执行Normal模式下的命令commands

例子:

  • ·:%global/TODo/delete:删除所有带TODO的行

替换命令

:[range]s/{pattern}/{string}/[flags]
将pattern替换为string
flags:

  • g:替换每一行的所有匹配
  • i:忽视大小写
  • c:替换前进行确认
  • n:计数而不是替换
:%s/Vim//gn:统计文件中所有Vim出现的次数(此时替换为什么无所谓,加了n就不会执行替换操作)
%s /\<vim\>/str/g;精确匹配vim这个单词比如 abc_vim是无法匹配的。
Buy me a coffee please.