Vim 简明教程

“Vim 是一个历史悠久的,具有很多命令的功能非常强大的文本编辑器,被称为 编辑器之神。”

简介

Vim 是从 vi 发展出来的一个文本编辑器。其代码补完、编译及错误跳转等方便编程的功能特别丰富,在程序员中被广泛使用。和 Emacs 并列成为类 Unix 系统用户最喜欢的编辑器。两派使用者经常发起 “XXX 才是最好的编辑器” 之争。

Vim 的几种模式

Vim 最常用的有四个模式,分别是:

normal 模式 :在普通模式中,用户可以执行一般的编辑器命令,比如移动光标,删除文本等等。这也是 Vim 启动后的默认模式。
insert 模式 :在这个模式中,大多数按键都会向文本缓冲中插入文本。大多数新用户希望文本编辑器编辑过程中一直保持这个模式。在插入模式中,可以按 ESC 键回到普通模式。
visual 模式 :这个模式与普通模式比较相似。但是移动命令会扩大高亮的文本区域。高亮区域可以是字符、行或者是一块文本。当执行一个非移动命令时,命令会被执行到这块高亮的区域上。Vim 的 “文本对象” 也能和移动命令一样用在这个模式中。
command 模式 :在命令行模式中可以输入会被解释成并执行的文本。例如执行命令(: 键),搜索(/? 键)或者过滤命令(! 键)。在命令执行之后,Vim 返回到命令行模式之前的模式,通常是普通模式。

此外还有一些衍生模式,包括:

操作符等待模式:这个派生模式指普通模式中,执行一个操作符命令后 Vim 等待一个 “动作” 来完成这个命令。如 dw 中的 d 即为操作符
插入普通模式:这个模式是在插入模式下按下 Ctrl-o 键的时候进入。这个时候暂时进入普通模式,执行完一个命令之后,Vim 返回插入模式
替换模式:这是一个特殊的插入模式,在这个模式中可以做和插入模式一样的操作,但是每个输入的字符都会覆盖文本缓冲中已经存在的字符。在普通模式下按 R 键进入。

入门

Vim 自带一个交互式的基本教程,里面包括了最常用的命令和你应该学了解的最基础的知识,安装 vim 之后,只需要在终端输入:

1
vimtutor

运行命令后,会出现操作系统对应语言的教程文档,首先要做的就是要对这个基础文档中的所有命令进行练习,直到形成肌肉记忆,下面简单总结一下教程中使用到的命令。

进入和退出 Vim

输入命令 vim filename,即为使用 vim 打开文件。由于这是一个新建文件,你会得到一个空的窗口。屏幕看起来会像下面这样:

    +---------------------------------------+
    |#                                      |
    |~                                      |
    |~                                      |
    |~                                      |
    |~                                      |
    |"file.txt" [New file]                  |
    +---------------------------------------+
            ('#" 是当前光标的位置)

以波纹线 (~) 开头的行表示该行在文件中不存在。换句话说,如果 Vim 打开的文件不能充满这个显示的屏幕,它就会显示以波纹线开头的行。在屏幕的底部,有一个消息行指示文件名为 file.txt 并且说明这是一个新建的文件。这行信息是临时的,新的信息可以覆盖它。

处于 normal 模式时 (按 键),输入命令 :q,即可退出 vim 编辑器,如果不想保存修改而退出,使用 :q! 命令。

处于 normal 模式时,输入命令 :wq 可以保存文件并退出 vim 编辑器,其中 :w 命令表示保存文件,也可以按下 ZZ 保存并退出文件。

移动光标

Vim 使用 hjkl 来控制光标的移动。

1
2
3
h 的键位位于四个字母的最左边,每次按下光标就会向左移动
l 的键位位于四个字母的最右边,每次按下光标就会向右移动
我们一般说上下,jk 键位的位置正好对应了这个说法,j 表示上,k 表示下

按下 G 键可以跳转到文件末尾,按下 gg 可以跳转到文件开头,也可以通过 : 行号 或者 行号 G 命令快速跳转到行号处。

            |   first line of a file   ^
            |   text text text text    |
            |   text text text text    |  gg
   7G / :7  |   text text text text    |
            |   text text text text
            |   text text text text
            V   text text text text    |
                text text text text    |  G
                text text text text    |
                last line of a file    V

按下 ^ 可以跳转到本行第一个不为空白字符处,按下 0 可以返回行首。按下 $ 可以跳转到行尾。

             ^
       <------------
  .....This is a line with example text
  <-----------------   --------------->
  0                  $
  (这里 "....." 表示空白字符)

按下 w 可以跳转到下一个单词词首, 3w 表示跳转 3 个单词。

      This is a line with example text
      --->-->->----------------->
       w  w  w    3w

按下 b 可以跳转到上一个单词词首

    This is a line with example text
    <----<--<-<---------<---
       b   b b    2b      b

按下 e 可以跳转到下一个单词词尾,按下 ge 可以跳转到上一个单词词尾。

    This is a line with example text
       <-   <--- ----->   ---->
       ge    ge     e       e

上面的 w, b, e, ge 会将标点符号也认为是一个单词,如果使用 W, B, E, gE 会以空白字符作为分隔符进行单词跳转,如下:

             ge      b          w                             e
             <-     <-         --->                          --->
      This is-a line, with special/separated/words (and some more).
         <----- <-----         -------------------->         ----->
         gE      B                   W                       E
         ge      b          w                             e

使用操作符 f 可以向后移动到一个指定的字符处,如 fx 向后查找到本行中的字符 x

例如,假定你在下行行首,而想移动到单词 humanh 那里。执行命令 fh 即可:

    To err is human.  To really foul up you need a computer.
    ---------->--------------->
        fh           fy

这个例子里同时演示 fy 命令移动到了 really 的词尾。

你可以在这个命令前面加计数前缀,所以,你可以用 3fl 命令移动到光标后第三个 l 处,即 foull:

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

F 命令用于向左查找:

    To err is human.  To really foul up you need a computer.
              <---------------------
                        Fh

tx 命令与 fx 相似,但它会把光标移动到目标字符的前一个字符上。提示: t 表示 To (到达)。这个命令的反向版本是 Tx

    To err is human.  To really foul up you need a computer.
               <------------  ------------->
                    Th              tn

移动光标的命令是 Vim 中最为基础的命令,但是他和我们平常使用的上下左右键有较大的区别,所以需要进行大量的练习让他成为你理所当然的操作习惯。

推荐一款游戏用来练习 Vim 的基础命令:

PacVim

通过这个游戏,可以快速的上手和熟练 vim 的基本操作,值得一试。

相对屏幕移动

通过 Ctrl-f 向下翻页,Ctrl-b 向上翻页, Ctrl-u 向下滚动半屏(即把当前行上半屏的行置于当前行), Ctrl-d 向上滚动半屏(即把当前行下半屏的行置于当前行), Ctrl-e 逐行下滚,Ctrl-y 逐行上滚。这在几乎所有 Unix 软件中都是可以使用的,比如 man 和 less。

                                   +----------------+
                                   | some text      |
                                   | some text      |
          原文本                    | some text      |
    +---------------+              | some text      |
    | some text     |  CTRL-U  --> |                |
    |               |              | 123456         |
    | 123456        |              +----------------+
    | 7890          |
    |               |              +----------------+
    | example       |  CTRL-D -->  | 7890           |
    +---------------+              |                |
                                   | example        |
                                   | example        |
                                   | example        |
                                   | example        |
                                   +----------------+

H 可以移动到屏幕的首行,L 到屏幕尾行,M 到屏幕中间。

                    +---------------------------+
            H -->   | text sample text          |
                    | sample text               |
                    | text sample text          |
                    | sample text               |
            M -->   | text sample text          |
                    | sample text               |
                    | text sample text          |
                    | sample text               |
            L -->   | text sample text          |
                    +---------------------------+

zt 可以置顶当前行,通常用来查看完整的下文,比如函数、类的定义。 zz 将当前行移到屏幕中部,zb 移到底部。

    +------------------+             +------------------+
    | some text        |   zt  -->   | line with cursor |
    | some text        |             | some text        |
    | some text        |             | some text        |
    | some text        |             | some text        |
    | some text        |             | some text        |
    | some text        |             | some text        |
    | line with cursor |             | some text        |
    | some text        |             | some text        |
    +------------------+             +------------------+

    +------------------+             +------------------+
    | some text        |             | some text        |
    | some text        |             | some text        |
    | some text        |             | some text        |
    | some text        |   zz  -->   | line with cursor |
    | some text        |             | some text        |
    | some text        |             | some text        |
    | line with cursor |             | some text        |
    | some text        |             | some text        |
    +------------------+             +------------------+

    +------------------+             +------------------+
    | some text        |             | some text        |
    | some text        |             | some text        |
    | some text        |             | some text        |
    | some text        |             | some text        |
    | some text        |             | some text        |
    | some text        |             | some text        |
    | line with cursor |             | some text        |
    | some text        |   zb  -->   | line with cursor |
    +------------------+             +------------------+

文本编辑

插入文本

在 normal 模式下,按下 i 键可以在光标所在处进入 insert 模式,按下 I 键会直接在行首进入 insert 模式。

在 normal 模式下,按下 a 键可以在光标所在处之后进入 insert 模式,按下 A 键会直接在行尾进入 insert 模式。

在 normal 模式下,按下 o 键可以在光标所在行之后插入空行,按下 O 键则是在光标所在行之前插入空行,两个命令都会进入 insert 模式。

如果进入了 insert 模式,Vim 会在窗口的底部显示 --INSERT-- (中文模式显示的是 -- 插入 --),这表示你在插入模式。

    +---------------------------------------+
    |A very intelligent turtle              |
    |Found programming UNIX a hurdle        |
    |~                                      |
    |~                                      |
    |-- INSERT --                           |
    +---------------------------------------+
删除文本

在 normal 模式下,可以使用 x 键删除光标坐在位置的字符。

在 normal 模式下,可以使用 dw 命令删除至一个单词的末尾,其中 d 是一个 操作符,可以和其他 动作 命令进行组合,使用删除操作符 d 的命令格式如下:

1
2
3
d motion
# d - 删除操作符
# motion - 操作符的操作对象

dd 是删除一行,db 是往前删除至单词开头,d$ 是删除至行末等。

替换文本

在 normal 模式下,按下 r 键可以进入替换状态,可以输入任意字符替换光标所在的字符,替换后即会退出替换状态,如果想保持替换状态,可以使用 R 命令,即可进入替换模式,你输入的字符会依次替换光标所在的字符,直到你按 退出替换模式。

    +---------------------------------------+
    |A very intelligent turtle              |
    |Found programming UNIX a hurdle        |
    |~                                      |
    |~                                      |
    |-- REPLACE --                          |
    +---------------------------------------+
更改文本

使用操作符 c 可以实现更改文本,实现的功能相当于删除并进入 insert 模式,例如 cw 命令表示删除一个单词并进入 insert 模式,c$ 命令表示删除至行尾并进入 insert 模式, cc 表示修改一整行,但是会保留这一行的缩进。

    To err is human
       ------->
         c2w
    To human
复制和粘贴文本

使用操作符 y 可以复制文本,例如 yy 可以复制一行的文本,yw 可以复制一个单词,使用 visual 模式选中文本后按 y 可以复制选中文本。

除了复制的文本外,Vim 的删除操作也会将删除的文本存入一个寄存器中,使用 p 命令可以在光标之后插入寄存器中的内容,使用 P 命令可以在光标之前插入寄存器中的内容。

    let sqr = LongVariable *
             -------------->
                   y2w

    let sqr = LongVariable *
                           p

    let sqr = LongVariable * LongVariable
保存文件

之前说到使用 :w 命令可以保存文件,默认存储的文件名为打开文件的文件名,如果需要另存为的话,只需要在命令后加上另存为的文件名即可,如 :w filename 便可将文件另存为为 filename

除了保存整个文件之外,vim 还支持部分文本的保存,按下 v 进入 visual 模式,移动光标选中想要部分保存的内容,输入 : 字符,可以看到屏幕底部会出现 :'<,'>,输入命令 w filename,命令变为 :'<,'>w filename 即可把选中的内容保存到 filename 文件中。

提取和合并文件

:w 命令相对应的,:r 命令是从文件中读取文本,输入命令 :r filename,将会读取文件 filename 中的所有内容,并将其插入到光标所在位置处。

使用计数指定动作

在 normal 模式下,输入 4h 使光标向前移动 4 个位置,输入 2w 使光标向后移动两个单词。

在 normal 模式下,输入 d2w 向后删除两个单词,输入 2dw 先后删除两个单词,这两个命令的区别是,前者是执行一次删除两个单词的命令,后者是执行两次删除一个单词的命令。

撤销类命令

在 normal 模式下,输入 u 可以撤销上一条命令,输入 U 可以恢复一行的原始状态,输入 Ctrl-r 可以重做撤销的命令。

定位文件状态

在 normal 模式下,按下 Ctrl-g 会显示当前编辑文件中当前光标所在行位置以及文件的状态信息。

搜索类命令

在 normal 模式下,输入 / 加上搜索字符串可以在当前文件中查找该字符串,查找后,按下 n 键可以跳转到下一个搜索字符处,按下 N 可以跳转到上一个搜索字符处。如果想使用逆向查找命令,可以使用 ? 和搜索字符串进行查找。

要回到之前的位置,可以按下 Ctrl-o,重复按可以回到更多步,而按下 Ctrl-i 可以跳到更新的位置。

当光标处于 {[()]} 任意一个括号字符上时,按下 % 可以快速查找并跳转到匹配的括号位置。

                        %
                     <----->
            if (a == (b * c) / d)
               <---------------->
                        %

当光标不在一个括号字符上,% 会先正向查找找到一个。比如当光标停留在上例中的行首时,% 会正向查找到第一个 )。再按一次会移动到它的匹配处。

            if (a == (b * c) / d)
            -------------------->
                       %

替换类命令

在 normal 模式下,输入命令 :s/old/new/g,可以将文件中所有的 old 字符串替换为 new

只替换单行的字符串可以使用命令 :s/old/new

要替换多行字符串可以使用命令 :#,#s/old/new/g,其中 # 表示行号,如 :4,8s/old/new/g 表示将 4 到 8 行的 old 替换为 new

如果要进行有提示的替换,可以使用命令 :s/old/new/gc,每次替换都会进行是否替换的询问。

执行外部命令

在编辑过程中,同样可以执行 shell 命令,只需要输入 :! command 即可运行外部的 shell 命令,命令执行后会回到 vim 中。

** 上面的所有命令都是使用 vim 需要学习的基础命令,只有把基础命令都联系到滚瓜烂熟,肌肉记忆的程度,才能够真正的感受到使用 vim 的便捷之处,加油!**

进阶

选项配置

Vim 可以进行预先配置启动项,从而增加插件以增强 Vim 的功能, 要配置 Vim,需要使用 vimrc 文件。

vimrc 文件

如果已经有 vimrc 文件了,可以直接在 vim 中输入命令 :edit $MYVIMRC 来进行编辑。

如果还没有 vimrc 文件,可以在用户目录创建该文件,即 ~/.vimrc,如果想 vim 启动时显示行号,可以在 vimrc 文件中加上:

1
set number

重启 vim 后即可生效。

下面简单介绍一些常用设置:

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
syntax on                       " 设置语法高亮
set fileencodings=utf-8 " vim 写入文件时编码类型
set termencoding=utf-8 " 输出到终端时编码类型
set encoding=utf-8 " 缓存文本,寄存器,脚本文件编码类型
set number " 显示行号,也可以使用 set nu
set cursorline " 突出显示当前行
set cursorcolumn " 突出显示当前列
set nocompatible " 以不兼容模式运行 vim
set showmatch " 显示括号匹配
set tabstop=4 " 设置 Tab 键长度为 4 个空格
set shiftwidth=4 " 设置自动缩进长度为 4 个空格
set softtabstop " 设置编辑模式删除 Tab 时为 4 个空格
set expandtab " 设置用空格来表示缩进
set smarttab " 根据文件中其他地方的缩进空格个数来确定一个 Tab 是多少个空格
set autoindent " 在插入一个新行时使用和前一行相同的缩进
set smartindent " 打开智能缩进
set paste " 设置为粘贴模式,使用鼠标右键粘贴时避免出现格式变形
set listchars=▸-,eol:↩︎,trail:-↩ " 将 Tab 键显示为 >-,行尾显示 ↩︎, 将行尾空格显示为 -↩︎
set backspace=indent,eol,start " 指明在插入模式下在哪里允许 <BS> 删除光标前面的字符。逗号分隔的三个值分别指: 行首的空白字符,换行符和插入模式开始处之前的字符。
set nowrap " 禁止自动换行显示
set history=1000 " 保存 1000 条命令和 1000 个查找模式的历史,数值可按需修改
set ruler " 在 vim 窗口右下角显示当前光标的位置
set showcmd " 在 vim 窗口右下角 ruler 左侧显示未完成的命令
set incsearch " 设置实时匹配
set hlsearch " 设置搜索时高亮匹配词
filetype plugin indent on " 开启文件类型探测,使用文件类型相关插件,使用缩进文件
autocmd FileType text setlocal textwidth=78 " 一行超过 78 行时自动换行
set foldenable " 允许折叠

更多配置可以使用这个 Vim 配置工具 来模拟。

也可以参考多人推荐的 spf13-vim 来学习他人的配置。

添加插件

Vim 可以通过插件增强功能,把插件放入 Vim 的 plugin 目录中即可使插件生效。

如果没有 plugin 目录,可以使用命令 mkdir -p ~/.vim/plugin 创建。

Vim 中共有两种插件:

  • 全局插件: 用于所有类型的文件
  • 文件类型插件:仅用于特定类型的文件

当然,这种拷贝插件的方式比较麻烦,所以插件管理器也应运而生,最常用的是 Vundle 管理器。

网上关于插件安装的文章数不胜数,就不在此赘述了。

VimAwesome 可以找到大家常用的插件。

编辑多个文件

编辑另一个文件

输入命令 :edit foo.txt 可以关闭当前文件并打开 foo.txt,如果当前文件未保存,则会提示错误信息。或者可以使用 :edit! foo.txt 命令放弃当前文件的修改并打开 foo.txt 文件。

文件列表

可以在启动 vim 时指定打开多个文件。例如:

1
vim test test1 test2

这样会打开三个文件,可以使用命令在这三个文件中进行跳转:

1
2
3
4
5
:next 或 :n        # 跳转到下一个文件
:previous 或 :prev # 跳转到上一个文件
:first # 跳转到第一个文件
:last # 跳转到最后一个文件
:2next # 向后跳转两个文件

上面的两条命令默认也会保存当前文件,然后进行跳转。

但是这样的方式不利于我们对多个编辑的文件进行管理,所以使用标签的方法打开多个文件是一个更好的方式,将在后面进行相应的讲解。

分割窗口

水平分割

分割新窗口最简单的命令如下:

1
:split 或 :sp      # 水平分割窗口

这个命令把屏幕分解成两个窗口并把光标置于上面的窗口中:

    +----------------------------------+
    |/* file one */                    |
    |~                                 |
    |~                                 |
     one===============================
    |/* file one */                    |
    |~                                 |
     one===============================
    |                                  |
    +----------------------------------+

这两个窗口允许你同时显示一个文件的两个部分。例如,你可以让上面的窗口显示变量定义而下面的窗口显示使用这些变量的代码。

Ctrl-w w 命令可以用于在窗口间跳转。如果你在上面的窗口,它会跳转到下面的窗口,如果你在下面的窗口,它会跳转到上面的窗口。(Ctrl-w Ctrl-w 可以完成相同的功能,是为了避免你有时按第二次的时候没有松开 Ctrl 按键。) 类似的,也可以使用 Ctrl-w j 跳转到下面窗口,使用 Ctrl-k 跳转到上面窗口。

使用 :close:clo 命令可以关闭光标所在的窗口,并且只剩一个窗口的时候不会退出 vim。

当然,还可以利用分割窗口打开新的文件:

1
:split two

如果你正在编辑文件 one,则命令执行的结果为:

    +----------------------------------+
    |/* file two */                    |
    |~                                 |
    |~                                 |
     two===============================
    |/* file one */                    |
    |~                                 |
     one===============================
    |                                  |
    +----------------------------------+

如果想新建一个窗口用于编辑一个新文件,可以使用 :new 命令。

调整窗口大小

在分割了窗口之后,可以发现默认是所有窗口平分屏幕,即分割三个窗口,则每个窗口是屏幕的三分之一大小。对于已经打开的窗口,我们可以使用命令来控制窗口的大小:

1
2
3
Ctrl-w +          # 扩大窗口大小一行
Ctrl-w - # 缩小窗口大小一行
{height}Ctrl-w _ # 把窗口设置为指定的高度

不过这几种方法按键较多,可能并不能快速达到想要的窗口大小,在这种情况下,直接使用鼠标进行拖动可以更快的调整窗口大小。具体方法是使用鼠标点按住状态条进行拖动。

垂直分割

类似水平分割,垂直分割的命令为:

1
:vsplit:vsp

这个命令可以做到垂直分割窗口,效果如下:

    +--------------------------------------+
    |/* file two */     |/* file one */    |
    |~                  |~                 |
    |~                  |~                 |
    |~                  |~                 |
     two  ===============one  =============
    |                                      |
    +--------------------------------------+

如果既水平分割了窗口,又垂直分割了窗口,我们便需要在各个窗口之间进行移动,之前提到过的 Ctrl-w w 命令只能够向下一个窗口进行移动,不够方便高效。 Vim 提供了一下几种命令在窗口之间进行跳转:

1
2
3
4
5
6
7
Ctrl-w h        # 跳转到左边的窗口
Ctrl-w j # 跳转到下面的窗口
Ctrl-w k # 跳转到上面的窗口
Ctrl-w l # 跳转到右边的窗口

Ctrl-w t # 跳转到最顶的窗口
Ctrl-w b # 跳转到最底的窗口
标签页

经过上面的联系,我们可以发现,无论分割窗口多少次,各个窗口之间都是相互独立的,不会发生重叠,这样会导致窗口过多时,屏幕空间不足以显示文件内容。为了解决这个问题,我们可以使用标签页。

假如正在编辑文件 thisfile,使用以下命令可以创建一个新的标签页:

1
:tabedit thatfile 或 :tabe thatfile

命令运行效果如下:

    +----------------------------------+
    | thisfile | /thatfile/ __________X|   (thatfile 用加粗字体出现或高亮选中)
    |/* thatfile */                    |
    |that                              |
    |that                              |
    |~                                 |
    |~                                 |
    |~                                 |
    |                                  |
    +----------------------------------+

窗口顶端的横向文件名表示了已经打开的标签页和其中的文件名。

想要在标签之间进行切换,可以使用以下命令:

1
2
3
4
:gt         # 切换到下一个标签页
:gT # 切换到上一个标签页
:3gt # 切换到第三个标签页
:4gT # 向前切换4个标签页,如果超过标签页数量,将从最后一个标签页继续计算数量

本文仅仅是对 Vim 这一款强大软件的基本介绍,想要真正的发挥 Vim 的强大之处,还需要不断地学习和不断地练习,希望大家都能够成为 Vim 大神。

参考

1、newjueqi,Vim 的几种模式介绍
2、vimtutor
3、yianwillis,Vim 中文文档计划