Vim 2 高级用法

Vim 系列教程目录:vim

本节会讲一些 Vim 中的高级概念和进阶用法, 了解了这些以后, 能够解开不少疑惑, 使用起来也会更驾轻就熟.windows

CWD/PWD

CWD(Current Working Directory), 当前工做目录, 这是 Vim 中一个挺重要, 可是却又常常被忽略的概念. 简单来讲, CWD 是 Vim 和操做系统的文件系统进行交互时的上下文环境.缓存

要查看 Vim 的 CWD, 你可使用 :pwd 命令来查看. 正常来讲, 当你点击桌面上的 gVim 图标打开 Vim 时, Vim 的 CWD 是用户目录, 当你在文件上右键->用 Vim 编辑打开 Vim 时, Vim 的 CWD 是文件所在路径.bash

CWD 有什么用呢? 如今请你打开 Vim, 而后在命令模式下执行 :e test_vim_cwd.txt, 你会看到打开了一个名为 test_vim_cwd.txt 的新文件, 你随便添加一些文本, 而后保存, 你会发现此次 Vim 再也不提示你没有文件名, 你能够直接保存了. 那么问题来了, 这个文件被存到哪里了呢?session

我想你应该已经猜到了, 没错, 在 Vim 里新建的文件, 若是不指定路径, 会被保存到 CWD 里. 因此说 CWD 是 Vim 和文件系统交互时的上下文环境.编辑器

除此以外, Vim 的不少插件工做时也依赖 CWD, 好比 NERDTree, CtrlP 等等.关于插件咱们之后再讲, 如今你先记住, CWD 是会影响一些插件的表现的.布局

在现阶段, 你不须要关心 CWD, 由于咱们如今仍是单文件操做, CWD 是哪都无所谓. 但若是你确实想改一下 CWD, 可以使用 :cd 命令修改 CWD:post

cd d:/xxx/yyy
复制代码

这和命令行里切换目录的方式是同样.学习

OK, 关于 CWD, 先说到这, 后面还会再说. 另外, 如今你又学会一个新命令: :e, 这个命令能够新建一个新文件. 其实, :e 这个命令后面能够路径/文件名, 若是给定的路径文件存在, 则是打开, 若是不存在, 则是新建.测试

文本对象

好, 咱们再回到 Vim 的操做中, 请打开一个英文文本文件或输入一些英文, 以便接下来的学习.

以前的复制和删除都是以字符, 行为单位, 而 w, e, b的做用是从光标处到下个单词开头或本单词结尾, 因此要想删除整个单词, 你得这么作: bdw, 这表示先将光标移动到单词开头, 而后 dw. 这很麻烦, 有时候不当心看错了, 光标就移动错了. 要解决这个问题, 可使用 文本对象.

如今请移动到一个单词的任意一个字母上, 而后执行指令 daw, 你会发现整个单词被删除了, 神奇吧. 这个指令中的 aw 在 Vim 中表明一个文本对象: a word, 即一个单词, 执行 daw 就表示删掉一个单词, 并且, 不管你在这个单词的哪一个字母上, 均可以执行此命令删掉整个单词.

除了 aw, Vim 还支持下列文本对象:

  • aw: a word, 表示一个单词, 及其后面的空白, daw 表示删除光标所在单词及空白
  • iw: inner word, 也是表示一个单词, 可是不包括单词后面的空白
  • as: a sentence, 表示一个句子, 及其后面的空白, das表示删除光标所在句子及空白
  • is: inner sentence, 也是表示一个句子, 可是不包括句子后面的空白
  • ap/ip: a paragraph, 一个段落, 细节同上
  • a[, a] / i[, i]: 一个 [] 块, a[, a] 包括两边的 "[]", i[, i] 不包括两边的 []
  • a(, a) / i(, i) / ab ib: 一个小 block, 细节同上
  • a{, a} / i{, i} / aB iB: 一个大 block, 细节同上
  • a<, a> / i<, i>: 一个尖括号块, 细节同上
  • a", a', a` / i", i', i`: 一对引号, 细节同上
  • at/it: 一个 tag, 匹配 HTML 或者 XML 中的 tag 及其内容, 会忽略单标签

上述文本对象大均可以使用计数器, 例如:

  • d3aw: 表示删除3个单词, as, ap 同理
  • y2ab / y2a(: 表示向外复制两层小括号的内容, 其余相似括号的同理
  • ", ', `, 这几个不可以使用计数器

这样一来, 一次性可操做的文本就大大增长了, 并且不用关心光标的位置, 很是便捷.

寄存器

咱们以前说过, 剪切(删除)的文本会进入到 Vim 中的寄存器里, 那什么是寄存器呢?

所谓寄存器, 就是存放文本和指令/命令的地方, 例如使用 y, d, c 等命令复制或剪切的文本都会被自动存放在 Vim 的寄存器中, 用户能够将文本和指令放在寄存器中, 也能够从寄存器中读出来.

Vim 中共有9类寄存器, 具体以下:

类型 标识 读写者 是否只读 包含的字符来源
Unnamed " Vim 最近一次的复制或删除操做 (d, c, s, x, y)
Numbered 0 到 9 Vim 寄存器 0: 最近一次复制. 寄存器 1: 最近一次删除. 寄存器 2: 倒数第二次删除, 以此类推. 每来一次新的删除和修改, Vim 就把前一次的寄存器 1 的内容复制到寄存器 2, 2 到 3, 依此类推. 而寄存器 9 的内容就丢失了
Small delete 中横线 - Vim 最近一次行内删除
Named a 到 z 或 A 到 Z 用户 由用户指定时使用, 用户可将文本存储到这些寄存器中. 若是存储至寄存器 a, 那么 a 中的文本就会被覆盖. 若是你存储至 A, 那么会将文本添加给寄存器 a,不会覆盖以前已有的文本
Read-only : 与 . 与 % 和 # Vim : 为最近一次使用的命令, . 为最近一次添加的文本, % 为当前的文件名, # 为轮换文件名
Expression = 用户 Vim 存储表达式的地方, 用户只可读
Selection/Drop + 与 * 和 ~ Vim +*为 GUI 选择寄存器, 你能够理解为它们就是系统的剪切板, -为鼠标拖放的寄存器
Black hole 下划线 _ Vim 通常称为黑洞寄存器, 当把文本写到这个寄存器中时, 什么都不会发生, 且不可读, 这个寄存器可用来删除文本而不影响其余寄存器
Last search pattern / Vim 最近一次经过 /?:global 等命令调用的匹配条件

要查看这些寄存器中到底有什么, 可使用以下命令:

  • :reg 查看全部寄存器中的内容
  • :reg <register name> 查看指定寄存器中的内容, 例如: reg 0

须要注意的是, 有些寄存器名字为特殊字符, 须要使用 \ 转义.

如今你能够先复制一段文本, 而后执行命令 :reg ", 查看一下 Unnamed 寄存器中的值.

寄存器的读写

要访问寄存器, 须要使用 " 做为前缀, 例如: "0, "a.

接下来咱们作一个测试, 例如将 'hello' 这个单词存储到寄存器 a, 先将光标移动到 'hello' 这个单词上, 而后执行:

"ayiw 复制代码

上述指令表示: 使用寄存器 a, 而后复制一个单词. 此时使用命令 :reg a 查看寄存器 a 中的内容, 就能看到 'hello' 了. 须要注意的是, 当使用复制剪切等命令向指定寄存器中写入内容时, 内容同时也会被写入到 Unnamed 寄存器.

每次向寄存器中写入内容, 会将寄存器中已有的内容覆盖, 若是想要往寄存器中追加内容, 则需使用大写字母防卫寄存器, 如: "Ayiw, 这表示将当前单词追加到 寄存器 a 中.

要读取寄存器 a 中的内容, 则可以使用以下命令:

"ap 复制代码

这表示先启用 寄存器 a, 而后进行粘贴操做, 你就能够看到, 寄存器 a 中的内容被粘贴出来了.

另外, 在插入模式下也能够访问寄存器, 在 插入模式中按 Ctrl-r, 而后再输入寄存器标识(不用输入", 直接输入标识), 就能够将对应寄存器中的内容输出.

访问系统剪切板

上面说了, y, d, c, x, s 等命令都是将内容存进了 Unnamed 寄存器中("), Unnamed 寄存器是 Vim 本身的寄存器, 操做系统是访问不到的, 因此你到别的软件了使用 Ctrl-v 是是没法粘贴出来的.

可是 Vim 中有另外两个寄存器: +*, 这两个寄存器能够理解为操做系统的剪切板, 因此咱们能够经过这两个寄存器对系统的剪切板进行读写, 方式以下:

  • 经过 "+y / "+d / "+c 将内容复制/剪切到系统剪切板
  • 经过 "+p 将系统剪切板内容粘贴出来

PS. 使用 "+ 和 "* 效果同样

上节咱们讲过 . 这个指令, 能够重复上次的操做, 咱们也说了, . 本质上是一个"宏", 那么什么"宏"呢?

所谓"宏", 其实就是能够反复播放的一系列操做的集合. 前面说了, 寄存器不仅是能够存储数据, 还能够存储指令/命令, Vim 中的宏就是将指令存储到寄存器中, 而后再读取出来. 宏的使用步骤以下:

  • 在普通模式下, 按 q 键开始录制宏, 后面通常跟上 Named 寄存器的名字, 如 qm, 表示将宏录制到 m 寄存器中.
  • 进行一系列操做, 都会被记录下来, 各类模式中的操做都会被记录到宏中
  • 回到命令模式, 再次按q, 退出宏录制
  • @m 播放m寄存器中的宏, 前面能够加数字表示播放次数
  • @@ 表示播放以前播放过那个个宏

录制好宏以后, 能够经过 reg 查看宏中的内容. 另外, 一样能够经过使用大写字母访问寄存器, 追加宏命令.

缓冲区/窗口/标签页

缓冲区(Buffer)

在 Vim 中打开的文件都会被存放在 Vim 的缓冲区中. 缓冲区在内存里, 当修改了文件还未保存时, 改动就在缓冲区中, 当保存时, Vim 会将缓冲区中的内容写到文件. 要查看缓冲区中有哪些文件, 可以使用 :buffers 命令, :ls, :files 命令能够起到一样的效果.

运行这个命令后, 你会看到相似的输出:

1      "Android\AFeed\02_项目基本配置.md" 第 39 行
  3  a   "[未命名]"                     第 0 行
  5      "Develop\Editor\Vim_1_基本使用.md" 第 177 行
  6 %a   "Develop\Editor\Vim_2_高级用法.md" 第 203 行
  7  a   "\Program Files (x86)\Vim\_vimrc" 第 0 行
  8      "Develop\Editor\Vim_3_vimrc.md" 第 86 行
  9      "Develop\Editor\Vim_5_经常使用插件(通用).md" 第 117 行
复制代码

缓冲区列表第一列是其序号, 第二列是标记, 标记的含义以下:

  • a 当前 active 而且 visible 的 Buffer
  • % 表示在当前窗口显示的 Buffer
  • = 只读 Buffer
  • h 隐藏的 Buffer

如何操做这些 Buffer 呢? 可以使用以下命令:

  • :buffer <buffer no> 经过 Buffer 编号切换到指定 Buffer, 简写 :b <buffer no>
  • :buffer <file name> 经过文件名切换到指定 Buffer, 简写 :b <file name>
  • :bnext, :bprevious 切换到下一个/上一个 Buffer, 简写 :bn, :bp
  • :bfirst, :blast 切换到第一个/最后一个 Buffer, 简写 :bf, :bl
  • :bdelete <buffer no> 删除指定缓冲区, 简写 :bd <buffer no>

关于 Buffer 要注意:

  • Buffer 一旦建立, 默认就一直存在, 除非你手动删掉. 这个特性会致使一个怪现象: 你在文件系统里把一个文件删除了, 可是 Buffer 没删除, 当你又读取并修改保存了这个 Buffer 后, 你会发现文件系统里的那个文件又回来了... 这是由于, Buffer 是文件在内存中的缓存, 你把文件从硬盘上删了, 可是内存中的缓存还在, 当你保存时, 又把文件写回去了. 因此删除文件时, 最好也把 Buffer 删了.
  • 一样的, 删除 Buffer 不会影响文件系统中的文件, 删除 Buffer 的操做只影响内存中的 Buffer.

窗口(Window)

Vim 中一个编辑区域中能够有多个窗口. 所谓窗口, 其实就是把编辑区分割成不一样区域, 每一个区域被称为一个窗口. 窗口是用来显示 Buffer 的, 当你打开 Vim 时, 其实同时也打开了一个窗口, 只是这个窗口占满了整个编辑区域.

使用以下命令, 能够把当前分割窗口:

  • :split: 在当前窗口上边打开新窗口, 新窗口中依然是当前文件, 简写为 :sp
  • :split filenpath: 在当前文件上边打开新窗口, 新窗口中为指定文件, 简写为 :sp filepath
  • :vsplit: 在当前文件左边打开新窗口, 新窗口中依然是当前文件, 简写为 :vsp, 一样可指定文件名
  • :new: 在当前文件上边打开新的空白窗口, 不可指定文件名
  • :vnew: 在当前文件左边打开新的空白窗口, 不可指定文件名

注意:上述命令均可以在前面加一个数字, 表示新窗口的大小(行数), 如 :3sp a.txt, 则打开 a.txt 的窗口只有三行. 另外, 能够反复使用上述命令, 把窗口分割成更小的窗口.

关于窗口的几个快捷键:

  • Ctrl-w w: 先按 Ctrl-w, 再按一次 w, 在多个窗口间切换
  • Ctrl-w h/j/k/l: 切换到指定方向的窗口
  • Ctrl-w t/b: 切换到最上面/最下面的窗口
  • Ctrl-w H/J/K/L: 将窗口移动到指定的方向
  • Ctrl-w +/-: 更改窗口大小, 固然, 使用鼠标拖拽也能够

关于窗口的几个命令:

  • :close 关闭当前窗口, 其实 q 命令和 ZZ 也是能够关闭当前窗口的, 只不过 :close 命令能够保证不会关闭最后一个窗口
  • :only 只保留当前窗口, 关闭其余窗口, 若是其余窗口中的文件没保存, 会有警告
  • :wall 保存全部窗口
  • :qall 退出全部窗口
  • :wqall 保存并退出全部窗口

标签页(Tab)

除了窗口功能, Vim 还支持多标签页功能. 标签页是窗口的合集, 即一个标签页中有多个窗口, 而:wall, :qall 等窗口功能其实只对当前标签页中的窗口有效. 使用下列命令, 能够开启新的标签页:

  • :tabedit: 打开新的空白标签页, 简写: tabe
  • :tabedit filepath: 在新的标签页中打开指定文件, 简写: tabe filepath
  • :tab split: 打开新的标签页, 其内容是当前标签页
  • :tab help: 在新的标签页中打开帮助文档

关于标签页的几个指令/命令:

  • gt / :tabn 切换到下一个标签页
  • gT / :tabp 切换到上一个标签页
  • 数字gt / :tabn 数字: 切换到指定位置的标签页, 从1开始
  • :tabc 关闭当前标签页( tabclose 的简写)
  • :tabo 只保留当前标签页, 关闭其余标签页(tabonly 的简写)

正确理解三者的关系

先引用文档中的原话(help window):

Summary: SummaryA 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.

个人理解:

  • Buffer 是文件在内存中的缓冲区, 一个 Buffer 对应一个文件, 不管是新打开且未编辑的空文件, 仍是 vimrc 或是其余文件, 在内存中都有对应的缓冲区.
  • Window 是用来显示 Buffer 的, 一个 Window 对应一个 Buffer, 可是一个 Buffer 能够同时被多个 Window 显示. Buffer 只有显示在 Window 中的时候才是可见的, 不可见的 Buffer 可使用 Buffer 相关命令查看.
  • Tab 是 Window 的集合, 一个 Tab 能够分割成多个 Window, 多个 Tab 间的 Window 和一个 Tab 中的 Window 没区别. 不一样的 Tab 本质上操做的是同一组 Buffer, 都是经过 Window 来展现.

一些奇怪现象的解释:

  • 打开一个文件的时候, 自动分割出一个 Window, 这是由于以前 Window 中的 Buffer 还未保存, Vim 默认不会隐藏未保存的 Buffer, 会保持其在 Window 中的可见性, 因此分割新 Window 来显示新 Buffer.
  • 在一个 Tab 中打开一个 Buffer 时, 忽然跳到了另外一个 Tab, 这是由于不一样的 Tab 其实操做的是同一组 Buffer, 若是一个 Buffer 已经在 Tab1 中打开了, 你在 Tab2 中再次打开这个 Buffer, 会跳到 Tab1 中.

能够再看看这些文章:

Session

不少软件都具备这样一种功能: 在你下一次启动该软件时,它会自动为你恢复到你上次退出的环境, 恢复窗口布局, 所打开的文件等等. Vim 也有相似的功能, 只是用起来比较麻烦...

当你要退出 Vim 时, 能够保存一个 Vim Session(会话), Vim 会话存放着所 有跟你的编辑相关的信息. 这包括诸如文件列表, 窗口布局, 全局变量, 选 项, 以及其它信息.

要保存会话信息, 可以使用命令 :mksession sessionname, 简写为 :mks sessionname, sessionname 由你指定, 会话信息会保存到名为 sessionname 的文件中, 默认状况下, Session 文件是存在用户目录下的, 固然你也能够指定 Session 文件的路径, 例如: :mksession d:/vim/session1. 若是 Session 文件已存在, 你须要使用 :mksession! d:/vim/session1 来保存 Session.

下次你打开 Vim, 能够载入这个 Session 文件, 就能恢复以前的会话信息了, 要载入会话, 可以使用命令 :source sessionname.

比起其余编辑器, Vim 的 Session 稍显难用一些.

折叠

折叠... 怎么解释呢, 就是把一段文本显示为一行, 就像一张纸, 要把它缩短些, 就折叠起来. 被折叠的文本其实还在, 只是显示方式变了. 折叠的好处 是, 经过把多行的文本折叠成带有折叠提示的一行, 会使你更好地了解对文 本的宏观结构.

要建立一个折叠, 可以使用 zf 指令, 你能够把光标移动到某一个段落内, 而后使用指令 zfap, 你会发现, 这段文字被折叠了. 这个指令的含义是: zf 是折叠指令, ap 是文本对象, 表示一段, zfap 就表示折叠一段文字.

要展开折叠的文本, 可将光标移动到折叠行上, 使用 zo 指令, 折叠的文字就会展开. 要想再次折叠, 使用 zc 指令, 此次为啥不用 zf 了? 由于 zf 是建立折叠的.

经常使用折叠指令:

  • za 打开/关闭折叠, 至关于 zo/zc 交替使用
  • zM 折叠全部
  • zR 打开全部折叠
  • zD 删除折叠

总的来讲, 折叠用的很少, 这里就很少介绍了.

其余技巧

  • 将命令行(系统命令)返回的结果输出在 Vim 中 在命令模式下输入:r! <cmd> 或者 :r !<cmd> 便可, 注意 <cmd> 指的是你要输入的系统命令
  • 将 Vim 命令的执行结果输出到文件, 须要以下三步:
    • 执行命令 :redir > a.txt, 此命令意为将命令输出到 a.txt 中, 默认会在 pwd 目录下新建文件, 你也能够指定文件路径, 若是文件已存在, 可以使用 redir! 进行覆盖, 或使用 redir >> a.txt 进行追加.
    • 执行 Vim 命令
    • 再次执行命令: redir END, 此命令意为重置命令输出位置.

小结

本节讲了一些 Vim 中的进阶用法, 可让你处理文本时更加方面快捷. 另外, 对于 Vim 中的寄存器, Buffer, Window, Tab等概念也有详细的介绍, 了解这些会让你理解 Vim 的一些行为. 仍是那句话, 多练习, 在用的过程当中学习, 感悟.

相关文章
相关标签/搜索