跳转至

技能拾遗


Lec02: Vim

目录

Part 0

前言

Vim的哲学

logo


在编程的时候,你会把大量时间花在阅读/编辑而不是在写代码上。所以,Vim 是一个多模态编辑器:它对于插入文字和操纵文字有不同的模式。Vim 是可编程的(可以使用 Vimscript 或者像 Python 一样的其他程序语言),Vim 的接口本身也是一个程序语言:键入操作(以及其助记名)是命令,这些命令也是可组合的。Vim 避免了使用鼠标,因为那样太慢了;Vim 甚至避免用上下左右键因为那样需要太多的手指移动。

Vim的优点


  • 高效性

  • 轻量级

  • 可移植性

  • 可拓展性

  • 高度语义化

  • 批量处理化

Vim模式

Vim模式(cont.)


  • Normal Mode: 普通模式,是vim的默认模式,绝大部分操作都是在这个模式下进行的

  • Visual Mode: 可视化模式,可以细分成三个子模式:普通可视化模式(按v键进入),行可视化模式(按V键进入),块可视化模式(按Ctrl+v键进入),用于选中文本区域

  • Insert Mode: 插入模式,按i键进入,基本等同于平时输入的方式

  • Command Line Mode: 命令行模式,按:键进入,经常用于执行文件级别的操作

  • Replace Mode*: 替换模式,按R键进入,依次替换光标处的字符,使用频率不高

Normal模式:基本移动

使用hjkl对光标进行上下左右移动

Normal/Insert模式常用操作

  • x: 删除光标当前位置的字符

  • r(replace): 替换光标当前位置的字符

  • i(insert): 进入输入模式,从光标之前开始输入
  • a(append): 进入输入模式,从光标之后开始输入
  • o(open): 下方插入新的一行,进入输入模式
  • I: 进入输入模式,从行首开始输入
  • A: 进入输入模式,从行末开始输入
  • O: 上方插入新的一行,进入输入模式

Visual模式酷炫操作

在Visual Block模式下,可使用I或者A实现多行插入操作,在默认vim下需要按esc键确认

在Vscode Vim里则可以直接在Visual Line模式下实现上述操作

Command模式常用操作


  • :w: 保存当前文件

  • :q: 退出当前文件

  • :q!: 强制退出当前文件

  • :wq: 保存并退出当前文件

  • :wq!: 强制保存并退出当前文件

  • :h {command}: 提供相应command的文档

Part 1

动作-Motion

行内移动

b跳转到当前单词开头,e跳转到当前单词末尾,w跳转到下一单词开头

行内移动(cont.)

  • 0: 跳转到行首

  • $: 跳转到行末

  • ^: 跳转到本行首个非空白字符
  • {num}_: 跳转到光标下方第{num}行的首个非空白字符,没有数字前缀时等同于^
  • %: 跳转到括号的另一端,跨行也生效
  • f{char} / t{char}: 跳转到本行下一个{char}字符出现处/出现前
  • F{char} / T{char}: 跳转到本行上一个{char}字符出现处/出现后
  • ; / ,: 对上述f / tF / T操作的结果进行重复同向/反向查找

跨行移动

  • {num}j: 光标向下移动{num}

  • {num}k: 光标向上移动{num}

  • {: 跳转到上一个非连续空行
  • }: 跳转到下一个非连续空行
  • /{pattern}: 按照正则表达式跳转到下一个{pattern}出现的位置
  • ?{pattern}: 按照正则表达式跳转到上一个{pattern}出现的位置
  • *: 采用/{pattern}的行为搜索当前光标下的单词
  • n / N: 对上述/?操作的结果进行重复同向/反向查找

页面移动


  • gg: 跳转到文件第一行

  • G: 跳转到文件最后一行

  • Ctrl+u / Ctrl+d: 向上/向下滚动半页
  • Ctrl+b / Ctrl+f: 向上/向下滚动整页
  • {linenum}gg: 跳转到第{linenum}
  • zz / zt / zb: 光标聚焦到屏幕中央/顶部/底部

"飞雷神"——标记移动

标记移动(cont.)

  • m{mark}: 将当前光标位置标记为{mark}

  • `{mark}: 跳转到标记{mark}位置

  • ``: 跳转到上次跳转前的位置
  • `.: 跳转到上次修改的位置

常用的编辑动作

  • c(change): 删除内容并进入插入模式

  • d(delete): 删除内容

  • y(yank): 复制文本内容
  • p(paste): 粘贴文本内容。如果yank的是一整行,那么粘贴时会在光标下方新起一行

cdy指令往往需要结合移动指令来形成完整的指令。例如,ce是改变从光标处到单词末尾的内容,ggdG是删除文件内的所有内容,yt,是复制从光标处到逗号处的内容

这三个编辑指令连续按两次,表示作用于光标所在行。例如,cc表示修改一整行内容

重复上次的修改操作

.命令可以重复上一次的修改操作,在需要多次执行同一修改操作的情景下会很有用

批量动作


在Vim中,移动指令是可以搭配数字来使用的,例如3w表示移动到后方第三个单词的开头

而编辑动作通常会和移动指令组合,所以就会创造出以下操作:

  • c3w3cw: 改变从光标处到后方第三个单词开头前的内容

  • d2j2dj: 删除本行以及下两行的内容

  • 3yy: 复制三行内容

Part 2

文本对象-TextObject

文本对象

通过i(inner)/a(around)+w(word), s(sentence), p(paragraph)以及各种配对符的组合可以产生具有语义化的文本分割

文本对象操作实例

例如,我们可以使用ci(来修改一个函数的参数列表

插件: Vim-surround


有时,我们不仅需要修改配对符里的内容,还需要修改配对符本身,而Vim本身并没有提供相应的功能,所以我们可以依靠插件vim-surround来实现

  • ysiw": 为光标所在处的单词加上双引号

  • cs"(: 表示将配对符"改为配对符(

  • ds": 删除配对符"

Part 3

寄存器与宏

寄存器

Vim提供了用于缓存文本内容的寄存器,编辑操作总会把原本的文本内容缓存到默认寄存器

常规寄存器: 用{a-z}{0-9}等字符来引用

特殊寄存器:

  • ": Vim默认寄存器,复制改变删除等操作的文本内容都会被存放在此寄存器中

  • %: 存放着文件名

  • +: 系统寄存器
  • .: 存放上次插入的内容
  • :: 存放上次执行的指令

通过:reg {reg_name}可以查看寄存器中存放的内容

指定操作使用的寄存器


当我们想要指定编辑操作使用的寄存器时,可以在相应指令之前加上"{reg_name}来进行寄存器切换

例如,

  • "+yy: 将光标所在行的内容复制到系统剪切板

  • "Adw: 将删除的单词内容追加存放到a寄存器

  • "ap: 将a寄存器的内容粘贴出来

宏(Macro)

宏(Macro)

录制一系列键盘操作,并允许我们重放这些操作

  • q{reg_name}: 将键盘操作录制到{reg_name}寄存器下,再次按q退出录制

  • @{reg_name}: 重放{reg_name}寄存器下保存的操作

  • @@: 重放上一次宏操作

录制宏时应当考虑宏的泛用性,保证在各种变化下都能产生相同的执行效果。例如,可以在操作前,先把光标移动到行首,再执行其他操作

Part 4

命令行模式操作

基本Ex命令

rangecommandflag(非必要)三部分构成

例如,

  • :% delete a: %表示作用于整个文件,所以这个指令就是将整个文件全部删除,并将删除的内容存放到a寄存器中

  • :2,4 yank: 表示复制第2行到第4行的内容

  • :.+1, $-2 print: 表示打印光标下方一行直到倒数第三行的内容($表示最后一行)

这里的flag就是第一个指令中的寄存器a

Visual模式下的range

在Visual模式下可以通过:来选定range

行的复制、移动和粘贴


  • :[range] copy {address}: 表示将range包含的所有行复制到address

  • :[range] move {address}: 表示将range包含的所有行移动到address

  • :{address} put {reg_name}: 表示将{reg_name}存放的内容粘贴到address

例如,当我们想要将第一行、第三行、第五行的内容粘贴到文本末尾时,可以采取

:1 yank a
:3 yank A
:5 yank A
:$ put a

来实现

Normal命令


:[range] normal {commands}: 对范围内的所有行执行normal模式下的commands命令

另外Normal命令还可以配合.命令和使用

  • :[range] normal .: 对范围内所有行重复执行上次的修改操作
  • :[range] normal @{reg_name}: 对范围内所有行重放{reg_name}中存放的宏操作

Global命令


:[range] global/{pattern}/{command}: 对范围内所有符合{pattern}的行执行command模式下的Ex命令,缺省为print

Global命令可以嵌套Normal命令使用,达到相当强大的效果

例如,删除全文中的单行注释,可以使用:% g/\/\//normal /\s*\/\/\<CR>d$来实现,原理是先用global筛选出带有//的行(/需要进行转义),然后用\s*\/\/匹配//以及前方的空白字符,\<CR>表示回车,需要通过Ctrl+v+回车来进行特殊输入,表示确认搜索,最后用d$,来删除后方所有内容

全文文本替换

全文文本替换(cont.)

:[range]s/{pattern}/{text}/{flags}: 表示将符合{pattern}的字符串替换成{text}

{flags}包含:

  • g: 表示global,全局生效

  • i: 表示大小写不敏感

  • c: 对每一个匹配项替换前进行确认
  • n: 计数

例如,:%s/vim//gn会统计文件中vim出现的次数,而不关注中间{text}部分的内容

对于之前提到过的“删除全文中的单行注释”,也可以使用:%s/\s*\/\/.*//g来实现