vim学习笔记

总结学习vim的笔记

vim中的基本概念

word和WORD

Vim对单词有两种不同的定义,并且分别用“单词”(word)和“字串”(WORD)对其进行区分。我们之前遇到过的每个面向单词的动作命令,都有一个面向字串的命令与其对应,这当中包括 W、B、E和 gE。

实际上当使用小写的时候代表的就是word 使用大写字母的使用就是WORD。如:

一个单词由字母、数字、下划线,或其他非空白字符的序列组成,单词间以空白字符分隔(参见:h word)。而字串的定义则更简单,它由非空白字符序列组成,字串间以空白字符分隔(参见:h WORD)。

如果你想更快地移动的话,可以用面向字串的动作命令;而如果你想以更细的粒度移动的话,则可以用面向单词的动作命令。

多文件编辑

标签页(tab)、窗口(window)、缓冲区(buffer)是Vim多文件编辑的三种方式,它们可以单独使用,也可以同时使用。 它们的关系是这样的:

A buffer is the in-memory text of a file. A window is a viewport on a buffer. A tab page is a collection of windows. –vimdoc

缓冲区是文件的内存文本。窗口是缓冲区上的视口。标签页是窗口的集合。

三者具体的关系如下:

  • buffer: 当用 vim 打开一个文件编辑时,编辑的对象并不是源文件,vim 会先将文件加载到内存中,用户编辑的数据存储再 buffer 中,使用 :w 可以将 buffer 中的数据写入,使用 :q! 表示退出并丢弃 buffer 中的内容。

  • window: window 就是 buffer 的视口,用于显示 buffer 的内容,一个 buffer 可以显示在多个 window 中,也可以多个 window 显示不同的 buffer

  • tab: tab 页是一组 window

使用-O参数可以让Vim以分屏的方式打开多个文件:

vim -O main.cpp my-oj-toolkit.h

使用小写的-o可以水平分屏。

  • vim a b c 可以打开 a b c 三个文件

  • 使用 :n 可以跳转到一个文件

  • :e# 回到刚才编辑的文件

缓冲区

缓冲区之间跳转最常用的方式便是 Ctrl+^(不需要按下Shift)来切换当前缓冲区和上一个缓冲区。 另外,还提供了很多跳转命令:

1
2
3
4
5
:ls, :buffers       列出所有缓冲区
:bn[ext] 下一个缓冲区
:bp[revious] 上一个缓冲区
:b {number, expression} 跳转到指定缓冲区
:b接受缓冲区编号,或者部分文件名。例如:
  • :b2将会跳转到编号为2的缓冲区,如果你正在用 :ls 列出缓冲区,这时只需要输入编号回车即可。
  • :b exa 将会跳转到最匹配exa的文件名,比如 example.html ,模糊匹配打开文件正是Vim缓冲区的强大之处。

引用Vim官方解释,缓冲区是一个文件的内容占用的那部分Vim内存:

A buffer is an area of Vim’s memory used to hold text read from a file. In addition, an empty buffer with no associated file can be created to allow the entry of text. –vim.wikia

  • 每个窗口显示一个在一个缓冲区上查看(通常是文件)。
  • 一个缓冲区可以出现在多个窗口中(窗口2和窗口3显示相同的缓冲区)。
  • 有些缓冲区可能被隐藏(不显示)。

buffer的三种状态

  • active:显示在窗口中的 buffer

  • hidden: 没有显示在窗口中的 buffer

  • inactive:没有显示,并且没有任何东西,没有与某个文件进行绑定

相关命令

1
2
3
4
5
6
7
:ls 或者是:buffer可以查看所有的buffer,与之一样的命令还有 :buffers

ls显示的符号的意义:

% 符号指明哪个缓冲区在当前窗口中可见,而 # 符号则代表轮换文件。按 <C-^>可以在当前文件和轮换文件间快速切换,在本例中,按一次会切换到 a.txt,再按一次,就又回到 b.txt了。注意:想要使用<C-^>来转换缓冲区,之前必须先使用命令 :bnext

缓冲区 a.txt 前有一个 + 号,表示这个缓冲区被修改过了。如果现在保存文件的话,缓冲区的内容就会被写入磁盘里,而 + 号也会消失了。

创建缓冲区

每次打开一个文件时,vim都会自动打开一个缓冲区。使用命令:ls :buffers可以进行查看。

不带任何参数打开多个文件便可以把它们都放入缓冲区(Buffer):

vim a.txt b.txt

当你使用:q关闭文件时?是否看到过1 more file to edit的警告?那就是缓冲区中的文件。

缓冲区之间的移动

我们可以用4条命令来遍历缓冲区列表。:bprev:bnext 在列表中反向或正向移动,每次移动一项;而 :bfirst:blast 则分别跳到列表的开头和结尾。

还可以使用以下命令来进行缓冲区的跳转:

1
2
3
4
5
6
7
:b <Tab>       " 显示所有Buffer中的文件
:b car<Tab> " 显示 car.c car.h
:b *car<Tab> " 显示 car.c jetcar.c car.h jetcar.h
:b .h<Tab> " 显示 vehicle.h car.h jet.h jetcar.h
:b .c<Tab> " 显示 vehicle.c car.c jet.c jetcar.c
:b ar.c<Tab> " 显示 car.c jetcar.c
:b j*c<Tab> " 显示 jet.c jetcar.c jetcar.h

需要注意,:b<Tab> 之间是需要有一个空格的

缓冲区的删除

:bdelete N1 N2 N3 :N,M bdelete注意:删除一个缓冲区并不会影响缓冲区所关联的文件,而只是简单地把该文件在内存中的映像删掉。如果我们想删除编号5~10(包含5和10)的缓冲区,可以执行 :5,10bd;然而,如果想要保留编号为8的缓冲区的话,那么就只能用 :bd 5 6 7 9 10 了。

缓冲区相关命令

标签页

标签页是容纳一些窗口的容器

Vim 的标签页可以把工作分隔到不同的工作区。Vim 中的标签页更像是 Linux 中的虚拟桌面,而不是像其他文本编辑器中的标签页。

标签页是最常见的多文件编辑方式吧,熟悉IDE的小伙伴一定能很快上手! 使用-p参数来用多个标签页启动Vim

1
vim -p main.cpp my-oj-toolkit.h /private/etc/hosts

如何使用标签页

:lcd {path}               //设置当前窗口的本地工作目录
:windo lcd {path}      //设置所有窗口的本地工作目录

打开及关闭标签页

:close        //关闭此窗口以及包含此窗口的标签页
:tabclose    //关闭当前标签页,无论其中有多少个窗口 :tabc
:tabonly    //关闭当前标签页外的所有其他标签页 :tabo
:tabedit {filename}    //在新标签页打开文件  :tabe
:tabe[dit] {file}   edit specified file in a new tab
:tabf[ind] {file}   open a new tab with filename given, searching the 'path' to find it
:tabc[lose]         close current tab
:tabc[lose] {i}     close i-th tab
:tabo[nly]          close all other tabs (show only the current tab)

Ctrl+w+T                //把当前窗口移到一个新标签页

中括号中的部分可以省略,在Vim中:h tabedit可以查看命令帮助。

在标签页中切换

:tabn         go to next tab
:tabp         go to previous tab
:tabfirst     go to first tab
:tablast      go to last tab


123gt                  //跳到标签页123
123gT                 //跳转方向与上一条相反
:tabnext 2,同123gt   //切换到编号为2的标签页
:tabnext,同gt           //切换到下一个标签页
:tabprevious,同gT    //切换到上一个标签页

在正常模式(normal)下,还可以使用快捷键:

gt            go to next tab
gT            go to previous tab
{i}gt         go to tab in position i 

重排标签页

:tabmove N
当N为0时,当前标签页会被移到开头
当N为空时,当前标签页会被移到结尾
当N为123时,当前标签页会被移到123标签页

窗口

sfind 可以打开在 Vim PATH 中的任何文件。这当然需要我们设置 PATH,一个通用的做法是在 ~/.vimrc 中添加:

1
2
" 将当前工作路径设为Vim PATH
set path=$PWD/**

同时 sfind 命令和窗口命令同时使用:

1
:vertical rightbelow sfind file.txt

上述命令:

  • vertical 打开一个垂直分割的窗口
  • rightbelow 指定窗口的位置:右下角
  • sfind 打开 file.txt 文件

常用的窗口操作

  • CTRL‑W ] 分割窗口并跳转到光标下的标签

  • CTRL‑W f 分割窗口并编辑光标下的文件名 (file)

  • CTRL‑W ^ 分割窗口并编辑轮换文件

  • CTRL‑W n 或 :new 创建新空白窗口 (new)

n 表示上一个,N表示下一个

窗口的创建

:split 新建一个窗口,将当前窗口分割成两半,他们显示的是相同缓冲区的内容(同一个文件)。这样就可以在两个窗口中浏览相同的文件了。可以简写为 sp + 窗口名

:vsplit 创建全新的垂直分割的窗口,同样是显示和当前窗口同一个文件内容。可以简写为 vsp + 窗口名

注意,如果直接在命令行中输入 :split :vsplit,所打开的窗口中的内容和原来的窗口中的内容是一样的。

窗口的关闭

有4种关闭窗口的方式,分别是:离开(quit)、关闭(close)、隐藏(hide)、关闭其他窗口

1
2
3
4
5
^代表Ctrl键
^Wq,离开当前窗口
^Wc,关闭当前的窗口
^Wo,关闭当前窗口以外的所有窗口

窗口切换

1
2
3
4
5
6
7
8
9
ctrl w + hjkl 光标在各个窗口之间切换

**Ctrl + w + w:这个命令会在所有窗口中循环移动**

Ctrl + w + t:移动到最左上角的窗口

Ctrl + w + b:移动到最右下角的窗口

Ctrl + w + p:移动到前一个访问的窗口

窗口移动

1
2
3
4
5
Ctrl + w + r:向右或向下方交换窗口,而Ctrl + w + R则和它方向相反。

光标会随着窗口而移动

Ctrl + w + x:交换同列或同行的窗口的位置。vim默认交换当前窗口的与它下一个窗口的位置,如果下方没有窗口,则试着与上一个窗口交换位置。亦可在此命令前加上数量,与制定的窗口交换位置。

窗口移动并且改变布局

1
2
3
4
5
6
7
注:下面的第三个字母都是大写,按玩Ctrl + w之后,按shif + 相应的字母。后面用^代替Ctrl
Ctrl + w + K :移动当前窗口至屏幕顶端,并占用全部宽度
^WJ: 移动窗口至屏幕底端,并占用全部宽度
^WH:移动窗口至屏幕左端,并占用全部高度
^WL:移动窗口至屏幕右端,并占用全部高度

^WT :移动窗口至屏新的现有分页

行和列的调整

:res(ize)+num 把当前窗口高度增加num行

:res(ize)-num 把当前窗口高度减少num行

横向调整

:vertical res(ize) num 指定当前窗口为num列

:vertical res(ize)+num 把当前窗口增加num列

:vertical res(ize)-num 把当前窗口减少num列


Ctrl+w +        增加窗口高度
Ctrl+w -        减小窗口高度
Ctrl+w =        统一窗口高度

第一章

关于.命令

这个命令的作用是重复你上一次的操作

>G<G

这两个命令前者是在行头添加一个tab,后者是删除一个tab。可以和命令.一起使用。

常用的操作

1
2
3
4
5
6
7
8
9
10
:E 打开一个文件夹,使用hjkl选择文件回车进入

:ter 打开一个终端窗口 使用exit退出

ctrl w + hjkl 光标在各个窗口之间切换

:shell 可以在不关闭vim的情况下切换到shell命令行

:exit 从shell回到vim

翻页命令

ctrl+f 向上翻页
ctrl+b 向下翻页
ctrl+u 向下翻半页
ctrl+d 向上翻半页
ctrl+y 向下翻一行
ctrl+e 向上翻一行
L 屏幕底行
H 屏幕顶行
zz 移动屏幕至光标位屏幕中央

搜索命令

/?是vim中的两种搜索命令,但是它们两个的搜索方向相反,/是向后搜索。

设置/取消大小写:

:set noignorecase # 不区分大小写
:set ignorecase # 区分大小写 
:set incsearch 可以在敲键的同时搜索,按下回车把移动光标移动到匹配的词; 按下 Esc 取消搜索。
:set wrapscan 用来设置到文件尾部后是否重新从文件头开始搜索。

搜索历史

假设你执行了三个查找命令:

    /one
    /two
    /three

现在,让我们输入 “/“ 启动一次查找,但先不按下回车键。现在按 (上箭头),Vim把 “/three” 放到你的命令行上。回车就会从当前位置查找 “three”。如果你不回车,继续按 ,Vim 转而显示 “/two”,而下一次 变成 “/one”。你还可以用 命令在历史记录中反向查找。

如果你知道前面用过的一个模式以什么开头,而且你想再使用这个模式的话,可以在输入 前输入这个开头。继续前面的例子,你可以输入 “/o“,Vim 就会在命令行上显示 “/one”。

冒号开头的命令也有历史记录。这允许你取回前一个命令并再次执行。这两种历史记录是相互独立的。

单词搜索

在vim中进行单词搜索有两种方法:

假设你在文本中看到一个单词 “TheLongFunctionName” 而你想找到下一个相同的单词。
你可以输入 “/TheLongFunctionName”,但这要输入很多东西。而且如果输错了,Vim 是不可能找到你要找的单词的。

有一个简单的方法: 把光标移到那个单词下面使用 * 命令。Vim 会取得光标上的单词并把它作为被查找的字符串。# 命令在反向完成相同的功能。你可以在命令前加一个计数: 3* 查找光标下单词第三次出现的地方。

第二种方法就是直接进行搜索:
如果你输入 “/the”,你也可能找到 “there”。要找到以 “the” 结尾的单词,可以用:

    /the\>

“>“ 是一个特殊的记号,表示只匹配单词末尾。类似地,”<“ 只匹配单词的开头。
这样,要匹配一个完整的单词 “the”,只需:

    /\<the\>

这不会匹配 “there” 或者 “soothe”。注意 *# 命令也使用了 “词首” 和”词尾” 标记来匹配整个单词 (要部分匹配,使用 g*g#)

大小写搜索: 在查找模式中加入 \c 表示大小写不敏感查找,\C 表示大小写敏感查找。

/foo\c

搜索高亮

gd可以直接完成任务,使用:noh取消高亮。

查找和替换

这个功能其实很难使用, 注意是因为命令太多了.

:s(substitute)命令用来查找和替换字符串。

:{作用范围}s/{目标}/{替换}/{替换标志}

例如 :%s/foo/bar/g 会在全局范围(%)查找 foo 并替换为 bar,所有出现都会被替换(g)

作用范围

作用范围分为当前行、全文、选区等等。

当前行:

:s/foo/bar/g

全文:

:%s/foo/bar/g

选区,在 Visual 模式下选择区域后输入 :,Vim 即可自动补全为 :'<,'>

:'<,'>s/foo/bar/g

2-11 行:

:5,12s/foo/bar/g

当前行 . 与接下来两行 +2

:.,+2s/foo/bar/g

替换标识符

光标的移动

涉及的主要按键是:
$:行尾
^:软行首(就是不包括空格)
0:硬行首(直接到真正的行首)
w/W:下一个单词首
e/E:下一个单词尾
ge:g命令是一个附加命令,这个命令含义和e相反,移动到上一个单词尾
b/B:上一个单词首
h:左移一位
j:下移一位
k:上移一位
l:左移一位
{}:段首尾
H:屏幕顶行
L:屏幕底行
M:屏幕中央
:10: 移动光标到文件第 10 行。可以 :set number 来让 vim 显示行号。
zt: 光标所在字符不动,将当前行移动到屏幕顶部,通常用来查看完整的下文,比如函数、类的定义。
zz: 光标所在字符不动,将当前行移到屏幕中间。
zb: 光标所在字符不动,将当前行移到屏幕底部。

软硬行首的区别

1
2
3
4
5
6
          ^
<-----------x
.....This is a line with example text
<----------------x x-------------->

0 $

.....表示空格

行内搜索

在行内使用搜索达到快速移动的目的。
行内搜索的按键是f/F其中f是向右搜索。t/T命令和f/F命令非常相似,其含义是To。它们唯一的不同是,t/T只会到达目标的前一个字符上。而f/F是直接到达该字符。

1
2
3
To err is human.  To really foul up you need a computer. 
--------------------->
3fl

vim键盘图

由图可知:

  • gz是附加命令,也就是它们都需要和其他命令一起使用。
  • ^的含义是移动到软行首,而0是移动到硬行首。区别是^只是移动到这行的第一个字符处,而0是移动到真正的行首。与0相对应的是$,而不是^
  • oO的作用分别是:向下起一行和向上起一行

ddcc的关系是, 前者不会进入插入模式,但是后者会。两者都是删除的作用。

操作符命令

上图中的橙色就是操作符命令。

操作符 + 动作命令 = 操作

d{motion} 命令可以对一个字符(dl)、一个完整单词(daw)或一整个段落(dap)进行操作,它作用的范围由动作命令决定。c{motion}、y{motion}以及其他一些命令也类似,它们被统称为操作符(operator)。

需要注意的是{motion}的含义就是文本对象,只有命令后面有这个{motion}则这个命令后面可以接上文本对象

下图就是操作符表,包含了vim中的所有操作符。当然,我们可以定义自己的操作符,使用h:map-operator来查看相关信息。

Vim的语法只有一条额外规则,即当一个操作符命令被连续调用两次时,它会作用于当前行。所以 dd 删除当前行,而 >> 缩进当前行。gU 命令是一种特殊情况,我们既可以用 gUgU ,也可以用简化版的 gUU 来使它作用于当前行。

操作符待决模式

结识操作符待决模式普通、插入及可视模式很容易辨识,但是Vim还有另外一些很容易被忽视的模式,操作符待决模式(Operator-Pending mode)就是一个例子。

每天我们无数次地使用它,但通常它只持续不到一秒时间。举个例子,在我们执行命令 dw 时,就会激活该模式。这一模式只在按 d 及 w 键之间的短暂时间间隔内存在,一眨眼工夫就不见了。

如果我们把Vim想象成有限状态机,那么操作符待决模式就是一个只接受动作命令的状态。这个状态在我们调用操作符时被激活,然后什么也不做,直到我们提供了一个动作命令,完成整个操作。当操作符待决模式被激活时,我们可以像平常一样按 中止该操作,返回到普通模式。

很多命令都由两个或更多的按键来调用(查阅:h g:h z:h ctrl-w ,或者:h [,可以看到一些例子),但在多数情况下,头一个按键只是第二个按键的前缀。这些命令不会激活操作符待决模式,相反,可以把它们当成命名空间(namespace),用来扩充可用命令的数目。只有操作符才会激活操作符待决模式。

你也许想知道,为什么要有一个完整的模式,专门用于操作符和动作命令之间的短暂瞬间,而命名空间命令则仅仅是普通模式的一个扩充?好问题!这是因为我们能够创建自定义映射项来激活或终结操作符待决模式。换句话说,它允许我们创建自定义的操作符及动作命令,从而让我们可以扩充Vim的词汇。

在vim中删除的键有:

其实就是sdcx四个键的大小写, d和c一组都是需要组合的键(但是这个两个将的大写是可以直接使用的), s和x一组是不需要组合的键

  1. x相当于删除键.X相当于退格键
  2. cc单个c键按了没有用必须要组合其他键. 使用这个可以删除一行并且不进入插入模式.
  3. dd这个作用和上面是一样的, 但是dd不会进入插入模式
  4. s删除光标处的字符, S是删除当前行然后进入插入模式
  5. 需要注意的是cd单按都是没有用的. 必须组合, 模式是c\d+动作键(就是图中绿色的)
    1. cc
    2. dd
    3. cw c$
    4. dw d^
    5. c2h 删除左侧的两个字符
    6. d2l 删除右侧的两个字符
    7. df; 向右删除到一个;
  6. D这个就是从当前光标删除到行尾, 不进入插入模式
  7. C和上面一样, 但是进入插入模式

移动键

+或Enter: 把光标移至下一行第一个非空白字符。


-: 把光标移至上一行第一个非空白字符。


w: 前移一个单词,光标停在下一个单词开头;


W: 移动下一个单词开头,但忽略一些标点


e: 前移一个单词,光标停在下一个单词末尾;


E: 移动到下一个单词末尾,如果词尾有标点,则移动到标点


b: 后移一个单词,光标停在上一个单词开头;


B: 移动到上一个单词开头,忽略一些标点

vim中的跳转

一般,每次你执行一个会将光标移动到本行之外的命令,该移动即被称为一个 “跳转” 。这包括查找命令 “/“ 和 “n” (无论跳转到多远的地方)。但不包括 “fx” 和 “tx” 这些行内查找命令或者 “w” 和 “e” 等词移动命令。另外 “j” 和 “k” 不会被当做是一次 “跳转”,即使你在前面加上计数前缀使之移动
到很远的地方也不例外。

由于 jump list 保留了光标的移动记录,我们可以通过 :jumps 查看 jump list,vim 会显示近 100 条记录;我们也可以可以在 jump list 中选中记录进行对应位置的跳转。

但是使用 :jumps 查看 jump list 来进行跳转的操作比较繁琐,而且很多时候我们并不关心之前这么多的跳转,我们只在乎跳转的顺序,因为只有顺着 jump list 的顺序,我们总会跳到想去的位置,这时我们可以使用以下命令:

    ctrl + i:跳转到 jump list 的后一个记录    
    ctrl + o:跳转到 jump list 的前一个记录

需要注意的是,jump list的存储对象是跳转,诸如hjkl这些移动命令并不是跳转。

类型跳转

使用ctags filename生成一个tag文件,然后就可以在目标文件中进行类型的跳转了使用ctrl ]使用ctrl t跳回来。

文件跳转

使用gf跳转到文件,使用ctrl o回来。

使用标记

m{a-zA-Z}命令会用选定的字母标记当前光标所在位置。小写位置标记只在每个缓冲区里局部可见,而大写位置标记则全局可见。

标号是全局的,只要使用vim创建的标号,不管在哪个文件使用命令marks都可以看到,并且可以直接使用'来进行跳转。

m + [小写字母]:只可在单个文件内跳转的标记;后面的为标记的标识符,用于跳转的指向;可以理解为当前标记的名字;下同
m + [大写字母]:可在多个文件之间跳转的标记

mmm 命令是一对便于使用的命令,它们分别设置位置标记 m,以及跳转到该标记。

ma使用a来表示这一行,跳转后可以使用'a(注意是单引号)来跳转到这行,标号可以使用任意符号。

使用:makes查看所有的标号。注意这个

删除标号:

1
2
3
4
:delmarks name

# 删除所有标号
:delmarks!

多文件操作

基础操作

修改了一个文件之后可以直接使用:edit filename修改下一个文件,但是这种方法会退出原本的文件。如果没有报错的话会报错,:edit! filename强制退出。

文件列表

使用命令args可以查看vim的参数,实际就是vim filename1 filename2
可以使用这个命令打开多个文件:

1
:args file1 file2 file3

文件杂项操作

1
2
vim -R filename # 以只读打开文件,但是仍然可以使用:w!强制修改
vim -M filename # 以只读模式打开文件,无法强制修改

文件之间的移动

<backspace> 跳转到交替文件(上一个文件)。
gt 跳转到下一个标签页。
gT 跳转到上一个标签页。

ctrl快捷键

插入模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
ctrl + k
键入二合字母
命令:dig可以查看所有的二合字母

ctrl + c/[
退出插入模式

ctrl + i
跳转到 jump list 的后一个记录

ctrl + o
跳转到 jump list 的前一个记录

**如 `j` `k` 一样, `i` `o` 的按键位置也是一样的规律:表示下一个在左,表示上一个的在右**

ctrl + r
后面跟寄存器名称,插入寄存器内容

ctrl + d
在当前行删除一个缩进,不论光标在哪

ctrl + t
在当前行插入一个缩进,不论光标在哪

0 + ctrl + d
删除当前行的所有缩进

^ + ctrl + d
删除当前行的所有缩进,恢复下一行的缩进

ctrl + h
删除前一个字符

ctrl + w
删除光标前的单词

ctrl + u
删除至行尾

ctrl + m
回车

ctrl + e
插入光标下方的字符

ctrl + y
插入光标上方的字符

普通模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
ctrl + a
N 加到光标所在/之后的数值上,默认加一

ctrl + x
N 减到光标所在/之后的数值上,默认减一

ctrl + b
光标向上滚动一屏

ctrl + f
光标向下滚动一屏

ctrl + c
终止当前的 (搜索) 命令

ctrl + d
光标向下滚动半屏

ctrl + u
光标向上滚动半屏

ctrl + e
文本上滚 N

ctrl + y
文本下滚 N

ctrl + g
显示当前文件名和位置

ctrl + o/t
跳转到跳转表里第 N 个较旧的位置

ctrl + i
跳转到跳转表里第 N 个较新的位置

ctrl + r
重做 'u' 撤销的改变

文本对象

vim中提供了文本对象,文本对象允许我们操作括号、被引用的文本、XML标签以及其他文本中的常见结构。

Vim 的文本对象分为两类:一类是操作分隔符的文本对象,如 i)、i” 和 it;另一类用于操作文本块,如单词、句子和段落。

Vim 的文本对象由两个字符组成,第一个字符永远是 i 或是 a。我们一般说,以 i 开头的文本对象会选择分隔符内部的文本,而以 a 开头的文本对象则会选择包括分隔符在内的整个文本。为了便于记忆,可以把 i 想成“inside”,而把 a 想成“around”或“all”。

分隔符文本对象

用文本对象执行操作可视模式适用于介绍文本对象,因为可以很容易看到发生的变化。然而,在操作符待决模式中使用文本对象,才能真正展现出它们的强大能力。文本对象自身并不是动作命令,我们不能用它们在文档中移动。但是我们却可以在可视模式及操作符待决模式中使用文本对象。

记住:每当在命令语法里看到{motion} 时,你也可以在这个地方使用文本对象,常见的例子包括 d{motion}、c{motion}和 y{motion}(更多命令,请参见操作符命令表格)。

范围文本对象

范围文本对象主要是四种类型:

  • word 单词
  • WORD 字串
  • 句子
  • 段落

看看和分隔符文本对象相比,范围文本对象中的ai有什么不同。

在分隔符文本对象中i代表的是不包括分隔符,而a则表示包括分隔符。

在范围文本对象中,i表示的是不包括范围文本两边的空格,而a则表示包括。

两种文本对象的使用

实际上文本对象主要和操作符一起使用。

实列:

从上图可以知道,两种文本对象都需要跟在操作命令后面使用。

可视模式

vim中有三种可视模式可以使用:v V Ctrl V

这个三种模式分别是单个字符选择模式、行选择模式、块/列选择模式

使用gv可以重复选择上一次选中的字符

`< `> 前者是可以区域的开头,后者是结尾。这类表示范围的符号中,>附近的符号都是在 < 的右边如:

`< \< `> \>

在该模式下有些快捷键可以快速在选中的文本中再次选择文本,如:

杂项

  • 像大多数移动命令一样,$命令接受计数前缀。但是 “移动到一行的行尾 n 次”没有什么意义,所以它会使光标移动到另一行。例如,1$ 移动到当前行的行尾,而2$则移动到下一行的行尾,如此类推。
    0 命令不能加计数前缀,因为 0 本身就是个数字。而且,出人意料地是,^命令使用计数前缀也没有任何效果。

  • 当我们按错了某个命令想要退出时,esc可以退出大部分命令

  • 使用:help e37直接查看e37错误码的帮助信息

  • !一般表示强制操作,大多数命令可以在后面加上它一表示强制操作,如果在命令的前面使用 ! 则表示运行 shell 中的命令

  • <<>> 前者是删除本行前的tab,后者是在本行添加一个tab。如果本行没有tab可供删除或者是已经有了tab则无法使用<<>><>可以在各个模式下使用,在可视模式下使用时可以快速添加tab。

  • cc在普通模式下按这个可以进入插入模式并且会直接跳到和上下行一致的开头处。

  • 先按num+o一个数字+o,然后输入文本可以将这个文本复制num遍,同样的使用num+O可以从上面开始插入num

  • r:替换当前光标下的字符,按下 r,然后输入一个字符,用来替换当前字符

  • A:和a一样进入插入模式,但是是从句尾开始插入。

  • / 称之为正斜线

常用快捷键

  1. vip选中一个段落
  2. 重复和后退
  3. 在vim中有文本行和屏幕行的区别,实际上这是因为文本行太长导致无法在屏幕上完整的显示,而将一个文本行拆分开来。在很多编译器中都没有这两个概念的区分,它们直接操作屏幕行。

    实际上将原来操作文本行的命令:h j k l $ ^ 0等等,加上一个g就变成了操作屏幕行,注意不可以一直按着g然后去按其他按键。
  4. yyY作用一致: 复制当前行
  5. g_到本行最后一个非 blank 字符的位置。
  6. tf命令:t{char}f{char}分别是查找字符{char}的左边界和右边界。同样的TF命令也是查找字符{char}的左边界和右边界,但是是反向查找。dt"删除至光标左边的双引号,df)删除至光标左边的右括号。
  7. 命令ddp可以快速交换两行。
  8. 命令xp可以交换两个字符。
  9. 命令80ichar可以插入80个字符。
  10. 在普通模式下使用 K 可以用 ‘keywordprg’ 程序 (缺省: “man”) 查光标下的关键字通过 man 命令快速搜索信息
  11. 使用 J 可以快速连接两行,并且添加**空格**,使用 gJ` 可以合并两行,并且删除空格
  12. :qa 退出 Vim 并放弃所有的更改。
  13. :xa 写入所有的更改并且退出
  14. {visual}g?rot13 编码高亮的文本
  15. N ]pp,但调整当前行的缩进,其中 N表示行数。所谓的调整缩进就是使用这个命令进行粘贴不会有缩进,但是使用p命令进行粘贴会有缩进。这个是在光标的上面粘贴。而命令 N [则是在光标的下面进行粘贴。
  16. N gpp,但将光标留在新文本之后。其含义就是粘贴完之后光标会跳转到下一行的开头
  17. 使用命令 ctrl + x 可以进行补全:

vim中提供了一个.命令,这个命令可以理解位低级的宏。这.是重复上一次的操作,上一次的操作是从normal模式到insert模式之间所执行的操作

vim还提供了宏,所谓的宏就是记录你在normal模式下的行为至寄存器中,然后可以重复使用。

q+{a-zA-Z0-9}之间的一个字符,其实就是寄存器名称。

如何使用宏

q键既是开始录制宏键,也是结束录制宏键

使用:reg a(register name)可以查看宏的内容。

通过@a执行录制的宏,使用@@执行最近使用过的宏

使用宏的时候尤其需要注意光标的位置,因为宏是从当前光标的位置开始执行的。所以我们需要在录制宏的时候就使用$ ^ 0 等等位移键控制好光标的位置。

22@qq中存储的宏执行22次。

串行执行宏和并行执行宏

宏可以多次执行,但是一旦执行至某一次时出现了错误,如果是串行执行的话就会停下来,不在执行。如果是并行执行的话就会跳过错误继续执行。

如何并行执行:

:normal @qv模式下选中的代码中执行宏,此时就是并行执行宏,否则都是串行执行。

给宏追加命令

有时候,我们在录制宏的过程中会漏掉某个至关重要的步骤。在这种情况下,我们没必要从头开始重录所有的步骤,而是可以在现有宏的结尾附加额外的命令。

如果我们使用qa来记录一个宏到a寄存器中,记录完成之后按下q退出,但是我们如果漏过一些命令此时可以使用qA来在该宏的最后面加上命令。

这个方法缺点明显,就是只可以在宏的后面进行添加命令。

还可以直接通过修改宏来达到目的:

  1. 首先,我们按G键,跳到当前文档的结尾,目的是要把寄存器a中的内容粘贴至新的一行。处理这种情况最简单的方式是用 :put命令:➾:put a

    为什么不直接用 “ap 命令呢?因为,在本例的上下文中,p命令会把寄存器a的内容粘贴至当前行的光标之后。而:put命令总会将它们粘贴至当前行的下方,无论寄存器保存的是面向行的还是面向字符的文本块。

  2. 现在我们可以像编辑普通文本一样编辑宏了。

  3. 我们依次运行命令 0 以及 “ay$,将把该行除回车符之外的每一个字符都复制下来。在把宏的内容保存回寄存器a之后,我们就可以用dd删除这一行了。尽管删除的内容最终将被保存到缺省寄存器,但我们也不会用到它们。

    做完以上这些步骤,当前寄存器 a中保存着一个新的、改进的宏。我们可将其用于本节刚开始的示例文本。

命令模式

在 Ex 命令影响范围广且距离远 中,我们已经了解了这个一般规律,即普通模式命令,适合在本地进行操作,而 Ex 命令则可以远距离操作。

Vim 中,有一种特殊的模式叫做命令行模式,它可以让我们输入一些命令,而无需离开当前模式。

这个模式下可以执行其他模式下的一些命令,但是这个模式的特点是适用于远距离的、长范围的情况。

使用@:可以重复执行上一次的命令。

其实命令行模式中的许多命令都是和普通模式中的命令效果是一样的。但是一般来说使用命令行模式会要快于直接使用命令模式

直接进入 Vim 之后所在的模式就是命令行模式。

显示命令 P

这个命令其实是 print 命令的缩写,作用是打印当前行。

这个命令可以打印你给定范围中的文本,其中给定范围的方式可以是:

  • 行号范围:10,20p
  • 选择范围:'<,'>p
  • 正则表达式范围:/(.*)/p

其一般的范围形式就是{start,end}

符号 功能
. 代表当前行
$ 代表当前行的结尾
% 代表整个文档

0 行在文件中并不真实存在,但它作为一个地址,在某些特定场景下会很有用处。特别是,在把指定范围内的行复制或移动到文件开头时,可以用它做 :copy {address}:move {address} 命令的最后一个参数。

所以一下命令的含义就明确了:

1
2
:,.$p  # 打印当前行到结尾
:%p # 打印整个文档

地址的偏移

除开直接指定打印的范围之后,还可以对打印的范围进行偏移:

1
:.,.+3p  # 打印当前行到当前行的第三行

复制命令 t 和移动命令 m

复制命令的简称是t,但是全称是 copy 。这个命令的作用是复制指定范围的文本到寄存器中。为了更好地记忆,你可以把该命令想成“复制到(copy TO)”。其实这个命令的本意就是这样的。通过下面的例子可以知道。

移动命令全称是 move ,简称为 m。它的作用是移动指定范围的文本到另一个位置。

复制命令

1
2
3
4
5
:6t.  # 把第6行的内容复制到当前行的下一行
:t6. # 把当前行的内容复制到第6行的下一行
:t. # 把当前行的内容复制到下一行,这个命令相当于 yyp
:t$ # 把当前行的内容复制到文件末尾
:`<,`>t0 # 把选择区域的内容复制到文件开头

:t.命令会创建一个当前行副本,而另外一种做法则是用普通模式的复制和粘贴
命令(yyp)来达到同样的效果。这两种复制当前行的技术有个需要关注的差别:yyp 会使用寄存器,而 :t. 则不会。因此,当我不想覆盖默认寄存器中的当前内容时,有时我会使用 :t. 来复制行。

移动命令

:move 命令看上去和 :copy 命令很相似:

1
:[range]move {address}

上面这个就是移动命令支持的语法。

重复命令

命令行窗口

使用 q: 可以进入命令行窗口,这个窗口中有一些历史信息,同样的在命令行窗口中也可以使用 Vim 中的命令。按下回车可以执行命令

运行 shell 命令

在命令行模式中,输入 :! 然后输入 shell 命令,就可以运行 shell 命令。

例如:

1
:!ls  # 列出当前目录下的文件

注意区分 :!ls:ls 的不同之处。前者调用的是 shell 中的 ls命令,而 :ls调用的是 Vim 的内置命令,用来显示缓冲区列表的内容。

Vim 的命令行中,符号 % 代表当前文件名,如:

1
:gcc %  # 编译当前文件并生成可执行文件

:!{cmd} 这种语法适用于执行一次性命令,但是如果想在 shell 中执行几条命令要怎么做?对这种情况,可以执行 Vim:shell 命令来启动一个交互的 shell 会话。

把缓冲区内容作为标准输入或输出

:read !{cmd} 命令让我们把命令的标准输出重定向到缓冲区。正如你所期望的
一样,:write !{cmd} 做相反的事。它把缓冲区内容作为指定 {cmd} 的标准输入

根据叹号在命令行上的位置不同,它的含义也不大相同。比较一下这些命令:

1
2
3
:write! sh
:write ! sh
:write !sh

上面三种写法中,只有第二种和第三种一样的。其含义都是将缓冲区中的内容作为指定命令的标准输入。

但是,第一种写法的含义是:将当前的缓冲区数据强制写入到文件 sh

转到具体的内容中去:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|usr_29.txt|		用户手册中关于在程序的不同部分间移动的内容。
|usr_30.txt| 用户手册中关于编辑程序的内容。
|C-indenting| 输入时自动设置每行的缩进。
|=| 重新缩进一些行。
|format-comments| 对注释进行排版。

|:checkpath| 显示所有被 (嵌套) 包含的文件。
|[i| 在当前和被包含的文件中查找光标所在的的标识符。
|[_CTRL-I| 跳到 "[i" 的匹配。
|[I| 列出在当前和被包含的文件中匹配光标所在的标识符的行。
|[d| 在当前和被包含的文件中查找光标所在的标识符的宏定义。

|CTRL-]| 跳到光标所在的标签处 (例如: 函数的定义)。
|CTRL-T| 跳回执行 CTRL-] 命令前的地方。
|:tselect| 从一连串匹配的标签中选出一个。

|gd| 跳到光标所在的局部变量的声明处。
|gD| 跳到光标所在的全局变量的声明处。

|gf| 跳到光标所在的文件名表示的文件。

|%| 跳到匹配的 ()、{}、[]、/* */、#if、#else、#endif 处。
|[/| 跳到上一个注释开始的位置。
|]/| 跳到下一个注释结束的位置。
|[#| 反向到未闭合的 #if、#ifdef 或 #else 处。
|]#| 正向到未闭合的 #else 或 #endif 处。
|[(| 反向到未闭合的 '(' 处。
|])| 正向到未闭合的 ')' 处。
|[{| 反向到未闭合的 '{' 处。
|]}| 正向到未闭合的 '}' 处。

|v_ab| 选中 "一个块" ("a block"),从 "[(" 至 "])",含括号
|v_ib| 选中 "内含块" ("inner block"),从 "[(" 至 "])"
|v_aB| 选中 "一个大块" ("a Block"),从 "[{" 至 "]}",含括号
|v_iB| 选中 "内含大块" ("inner Block"),从 "[{" 至 "]}"

启动参数

在使用命令 Vim 打开文件时,可以用一些参数来控制打开方式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
vim [options] ‑ 从标准输入读入文件

vim [options] ‑t {tag} 编辑与标签 {tag} 关联的文件

‑g 启动 GUI (同时允许其他选项)

+[num] 置光标于第 [num] 行 (缺省: 末行)

+{command} 载入文件后执行命令 {command}

+/{pat} {file} .. 置光标于首次出现 {pat} 处

-R 只读模式

-d 比较模式

配置问题

需要注意的是,很多版本的 Vim 其实都不支持系统剪切板。可以使用如下命令查看自己的 Vim 是否支持剪切板:

1
vim --version | grep clipboard

如果输出包含 +clipboard 或 +xterm_clipboard 就支持,如果这两项都是 - 则不支持。例如我的 Vim 输出为(MacOS 上的 macvim):

1
2
+clipboard         +keymap            +printer           +vertsplit
+emacs_tags -mouse_gpm -sun_workshop -xterm_clipboard

需要安装插件:

1
2
3
- MacOS 下可以直接用 brew 安装 macvim,它是支持剪切板的。
- Linux 下,如果是 Debian 或 Ubuntu 可以安装 vim-gtk、vim-gnome,Redhat/CentOS 则可以安装 vim-X11。
- Windows 下比较复杂,可以参考 https://vim.fandom.com/wiki/Using_the_Windows_clipboard_in_Cygwin_Vim。

参考资料

参考资料

https://vim.nauxscript.com/vim/day-8.html#%E8%A1%8C%E5%86%85%E6%90%9C%E7%B4%A2

https://yianwillis.github.io/vimcdoc/doc/usr_03.html#03.7

窗口操作

https://yyq123.blogspot.com/

vim使用技巧作者博客

大量快捷键操作

在不同的软件中使用vim模式的教程

和上面一致

http://www.uinio.com/Linux/Vim/#%E5%AE%8F%E5%BD%95%E5%88%B6


vim学习笔记
https://ysc2.github.io/ysc2.github.io/2023/11/29/vim学习笔记/
作者
Ysc
发布于
2023年11月29日
许可协议