vimbook-OPL(5-7)

Chapter 5 Windows

5.1 打开新窗口

分屏的命令有以下命令:

  1. :sp 上下分屏,:vs 左右分屏

  2. CTRL-W_CTRL-W在窗口之间切换

  3. CTRL-W_h CTRL-W_j CTRL-W_k CTRL-W_l 进行左右上下窗口切换,用 :h CTRL-W_h 可以查看对应的帮助文档。

  4. :sp file 可以在分屏的同时打开文件,在执行任何打开操作时可以用 +command 打开头执行的一条命令,如:

    1
    
    :sp +/sprintf three.c
    

    在分屏打开文件后马上执行搜索 sprintf 的命令。

  5. CTRL-W_K 将当前窗口放在最顶部的位置,CTRL-W_L 将当前窗口放在最右边的位置,CTRL-W_H 将当前窗口放在最左边的位置,CTRL-W_J 将当前窗口放在最下边的位置;

5.2 控制窗口大小

在sp前面带上数字,会成为新打开的窗口的行数,形如: :10sp alpha.c 将在上下分屏,并且新打开的窗口大小是10行。用 [N]CTRL-W_+ [N]CTRL-W_- 分别增加或减小当前窗口的大小,[N] 指定增加减少的行数,不提供时默认为1行,用 CTRL-W_=将屏幕对半平分。

5.3 Buffers

A buffer is a copy of a file that you edit along with the setting and marks that go with it.
vim中的一个重要概念就是缓冲,所谓缓冲就是在内存中的文件拷贝附带它们的设置和标记。

在vim中缓冲有三种状态:

  • Active 出现在屏幕上
  • Hidden 文件没有出现在屏幕上,但是还在内存中,用 :hide 将一个缓存隐藏
  • Inactive 文件没有处于编辑状态

:buffers 命令查看所有缓冲的信息,信息首列是缓冲序号,第二列是缓冲的状态,第三列是文件名。以下是一些状态字符的含义:

  • % 当前窗口的缓冲区
  • # 轮换缓冲区(Alternate buffer)
  • a 激活缓冲区
  • h 隐藏缓冲区
  • - 非激活缓冲区
  • + 修改过的缓冲区

以下是我在 bx 项目下打开若干文件的输出:

1  h   "~/project/bx/src/bx.cpp"      line 1
3  h   "allocator.h"                  line 44
5 #h   "inline/allocator.inl"         line 1
6 %a   "os.h"                         line 23

5.4 选择缓冲

选择一个缓冲,可以用 :buffer number ,number是缓冲的序号,如果你不知道缓冲的需要,那么用 :buffer filename 也能打开对应的缓冲,:[N]bnext 打开下N个缓冲,不提供N默认为下一个 :[N]bprevious 打开上N个缓冲,不提供N时默认为上一个,:[N]bNext 是它的别名,:blast 打开第一个缓冲,:brewind:bfirst 打开第一个缓冲。

可以将分屏命令和缓冲选择命令结合,如 :sbuffer number :sbuffer filename :[N]sbnext :[N]sbprevious :sblast :sbfirst :sbrewind 分别在打开缓冲时进行分屏。

设置optinons :set hidden,当文件离开屏幕时不变成Inactive,而是变成Hidden

6 Basic Visual Mode

6.1 简介

vim 和 vi 最大区别就在于可视化模式,可视化模式提供了对高亮文本进行操作的便利方式。vim提供三种可视化模式:

  • v 进入 a character-bycharacter visual mode 字符可视化模式
  • V 进入 linewise visual mode 行可视化模式,只能高亮整个行
  • CTRL-V 进入 Visual Block Mode 块列可视化模式,高亮的是一个矩形块

<Esc> 命令退出可视化模式,可以在可视化模式中按别的模式的命令,直接切换各个模式。

NOTE: 前两个模式查看帮助需要在命令前面带上 d_ 比如可视化模式下的 d 命令,用 :h v_d。块可视化模式查看帮助得在命令前带上前缀 v_b_ 比如块可视化模式下的 r 命令,用 :h v_b_r

6.2 在可视化模式中进行编辑

  • d 删除高亮的文本
  • D 删除高亮的行
  • y 复制高亮的文本
  • Y 复制高亮的行
  • c 删除高亮文本并进入插入模式
  • C 删除高亮文本所在的整行并进入插入模式
  • J 将高亮的行拼合成一个长的行,中间的所有空白用空格替换
  • gJ 将高亮的行拼合成一个长的行,中间的换行符别删除
  • > < 将高亮的行向右或向左缩进 “shiftwidth” 的长度
  • = 将高亮的行依据语法格式进行智能缩进
  • CTRL-] 将高亮的文本跳转其定义,此定义的位置需要用 ctags 生成
  • K 对高亮的文本用 man 查询定义,并展示出来

6.3 Visual Block Mode

块列可视模式是非常重要的,能够定义一个高亮一个四边形的文本块,可以做到同时编辑多列,比如做到对多行进行注释。按住 CTRL-V 即进入块列可视模式,其中执行的所有命令将作用于每一行。以下是块列可视模式下可执行的命令(这些命令都有两个特性:1.当某一行太短而不在可视块中时,那一行不受影响;2.如果输入的字符串中有换行符时,只有首行受影响):

  • I{string}<Esc> 在可视块的左侧的每行插入字符串string,输入时字符串出现在第一行,当按下<Esc>结束输入时,string神奇的出现在每一行;
  • c 将可视块中的文本删除,并进入插入模式,输入的字符串插入到每一行;
  • C 从可视块的左侧删除到行尾,并进入插入模式,输入的字符串插入到每一行;
  • A 命令在可视块的右边的每行插入字符串。它有点特殊,可以作用于较短的行,短行将用空白符补齐;
  • r{char} 将可视块中的每个字符替换为{char}表示的字符;
  • > 将可视块向右缩进 “shiftwidth” 的长度,起点是可视块的左侧;
  • < 将可视块向左缩进 “shiftwidth” 的长度,影响的仅仅是可视块本身,如果可视块的左侧距离前面的字符不足 shift 长度,那么能缩进多少就缩进多少;

7 Commands for Programmers

这一章主要讲语法高亮、缩进以及如何定位函数、宏、变量的定义,从这一章中可以看出 Vim 的设计初衷应该是为了给 C/C++ 程序员设计的,别的语言支持的就没那么好了。

7.1 语法高亮

命令 :syntax on 启用语法高亮,:h :syntax 查看语法高亮的帮助文档,语法高亮可以标记关键字、字符串和注释等程序文本结构,并对每个标注不同的颜色。颜色在颜色主题 —— 位于 $VIMRUNTIME/colors 目录 —— 配置。Vim 配色方案有两大系列:light 和 dark,用 :set background={light|dark} 进行切换,:set background? 查看当前的配色系。为什么出现这两个呢?原因在于命令行模式下,终端的配色可能是白色的也可能是黑色的,通过设置不同配色方案来适应。如果你使用非标准的文件扩展名,很可能 Vim 不能正常识别,这时候得用 :set filetype={language} 告知 Vim 文件类型。

7.2 缩进命令

程序的结构好坏就是通过缩进来判断的,一个缩进良好的程序对阅读者来说是莫大的帮助,也提升了代码的评分。所有好的开源项目的代码必定有优秀的统一的缩进。[count]<< 命令将光标下 count 行文本向左移动一个 shiftwidth 长度,[count]>> 则向右缩进。:set shiftwidth=4 设置 shiftwidth 长度为 4。<motion >motion 按照 motion 移动的位置向左/右缩进一个 shiftwidth。motion 可以是 1G 10j % 等等。

7.3 自动缩进

Vim 中有许多自动缩进的 Options,我主要总结一下自动的缩进:

  • :set cindent 使得文本按照 C 风格程序结构进行自动缩进,必须自动在 if(x) 之后缩进,在 { 之后缩进,在 } 之后回退缩进;

    :filetype on
    :autocmd FileType c,cpp :set cindent
    

    以上命令将在识别 C/C++ 文件时自动进行 C 风格缩进,而在其它文件时不这样做,autocmd 是在一些定义好的事件触发之后自动执行的命令;

  • :set smartindent C 风格的程序缩进是比较复杂的,而智能缩进则比较简单了,遇到 { 就缩进, 遇到 } 就回退缩进,遇到 cinwords Options 中的关键词就增加缩进;这里有必要提一点,Vim 的设计肯定是对 C/C++ 做了特别的支持的,当遇到 # 字符时,那一行不做任何缩进,然后在下一行恢复,这样做是为了给 C 预处理器提供便利;

  • :set autoindent 这种模式就很简单了,上面一行是缩进多少,下面一行就缩进一样多。这种模式给 Python、Lua 语言用是十分好的;

7.4 = 命令

=motion 将用 motion 选中的文本用 Vim 内部格式化程序,常用的 motion 就是 % 对一个块进行格式化。这个命令对 C/C++ 语言支持的很好,对 PHP 支持的很差。越发让我感觉 Vim 是专门为 C/C++ 设计的。

7.5 在程序中定位标识(Items)

  • [CTRL-I ]CTRL-I 在 #include 包含的文件和当前文件中搜索光标下的 word,前面的命令从所有文件的源头搜索第一个,后面的命令从光标之后开始搜索;
  • gd gD 搜索并把光标定位到变量定义的位置,前者搜索局部变量,后者搜索全局变量。这个命令有时会出错,因为 Vim 不是编译器,没法完全理解程序;
  • [CTRL-D ]CTRL-D 在 #include 包含的文件和当前文件中搜索并把光标定位到宏定义的位置,前者定位从所有文件的源头开始搜索第一个,后者从光标之后开始搜索;
  • [d ]d 与上面的命令一样搜索,在屏幕下方显示第一个而不是跳转,前者从最开始搜索,后者从光标之后搜索;
  • [D ]D 与上面的命令一样搜索,在屏幕下方显示所有定义,前者从最开始搜索,后者从光标之后搜索;

7.6 匹配括号命令

% 是个神奇的命令,跳转到匹配的块的边界,与 d = < > 等命令配合完成复杂的更新(Change)操作。Vim 预定义的可以匹配的标记有 (), {}, [],以及C 语言的块注释 /* */,还有在预处理命令 #if/#ifdef/#ifndef, #else, #endif 之间循环跳转。

那么怎样只选择 {} 的内含大块而不要括号呢?Vim 提供了命令 i{ i} 来选择这个内含大块。组合命令 >i{ 将只缩进这个内含大块而括号不动,在可视化模式中可以只选中内含大块。类似的 Vim 提供了 i[ i] i( i) 来匹配别的括号中的内含大块。这真是个有用的命令。

7.7 在 man 程序中查找

K 命令将光标下的 word 用 man 程序打开,相当于调用了 man {word}。用 {num}K 相当于将光标下的 word 调用了 mane {num} {word} 这个 num 就是想要查找的对应的 section 。当写的程序是 Linux 程序,并且调用了 System Call 时,这个命令可以用来查找函数的描述,岂不快哉!

调用的这个外部程序是由 keywordprg Option 指定的,是可以替换的。

7.8 Tags

Vim 专门为了 C/C++ 语言设计了 Exuberant Ctags(ctags) 程序用来将文本中的各种定义进行索引,然后可以在 Vim 跳转或者查找这些定义,这是比上面讲的命令更加强大的查找功能。在 Vim 中定义用术语 tags 来表示。执行 ctags -R src include 将对 src 和 include 中的文件递归索引,并在当前目录下生成一个 tags 文件。用 :set tags=./tags 设置标签文件。

Vim 对标签提供了丰富的查找命令:

  • :tag {word} 直接跳转到 word 所在的定义
  • CTRL-] 跳转到光标下 word 所在的定义,并将此标签放到标签栈(Tag Stack)中,用 [count]CTRL-T 从标签栈中弹出 count 标签,并回到上 count 个地方,:[count]tag 将当前标签跳转路径上的前 count 个标签重新压入,并跳转到那个标签的位置。 比如跳转的路径 debugPrintf -> debugPrintfVargs -> debugOutput ,当连续两次按 CTRL-T 回到 debugPrintf 时,按 :2tag 又会跳到 debugOutput 所在的定义;
  • :tags 显示所有查找过的标签,> 指示的位置是当前所在的标签;
  • :stag {word} 将屏幕分屏并跳转到定义,[count]CTRL-W_]CTRL-] 的分屏版本;

还可以进行正则表达式查找呢!:tag /{pattern} 对 pattern 中的模式进行正则匹配并跳转到第一个匹配的定义,正则表达式不要太复杂哦,否则估计没人愿意用。 Vim 提供了如此多的命令,正如 C++ 提供如此的特性一样,“你可以用,但不代表你必须用”。

:tselect {name}:tselect /{pattern} 被设计为显示所有的匹配定义而不是跳转。结果列表中的 Priority 字段是由三个字母组成的,F 代表完全匹配, S 代码时静态(Static)标签否则为全局标签,C 表示标签在当前文件。在列表的最下方有一个提示符,输入序号就可以跳转到对应的定义。g] 对光标下的 word 执行这种查找。:tjump {name} 执行查找并且当只有一个匹配时跳转到这个定义,如果有多个匹配与 :tselect 结果一样。

当查找到不止一个标签时,用 :[count]tnext 下一个标签 :[count]tprevious 上一个标签 :[count]trewind 第一个标签 :[count]tlast 最后一个标签,进行跳转。

为了显示制表符 Tab 和换行符,用 :set list 对于原始的 Vim 将 Tab 显示为 ^I ,在每行的结尾显示 $ ,用 ’listchars’ 改变显示的字符。去文档中查找帮助看下具体如何使用。’expandtab’ 将输入的 Tab 扩展为空格,而用 CTRL-V<Tab> 就不会将 Tab 进行扩展。

7.9 编译程序

Vim 在设计的时候就考虑了通过 make 来编译程序,:make [arguments] 调用当前目录下的 Makefile 以 arguments 为目标和参数,并在屏幕下方回显 Shell 的输出。

当发现错误时,错误显示在 quickfix 中,有以下命令可用:

  • :[count]cnext 跳转到下 count 个错误;
  • :[count]cprevious 回到上 count 个错误;
  • :crewind 跳到一个错误 :clast 调到最后一个错误 :cnfile 跳到下一个文件的第一个错误;
  • :cc 回到当前所在的错误
  • :clist [from] [,[to]] 显示错误列表,通过 from 和 to 指定显示的范围
  • :clist! 显示错误列表的所有信息(包括正常信息)
  • :cfile [error-file] 将 error-file 中的内容导入到 quickfix 中,如果没有指定将默认使用 ’errorfile’ 选项的值作为文件名,这个多用于帮助其它开发者定位 bug 用,另外一个开发者只需要发送其错误文件过来即可;
  • :cquit 退出错误状态。

选项 ‘makeprg’ 指定默认的 make 程序;

7.10 Grep 查找

:grep [arguments] 调用外部的 grep 程序,arguments 与在 Shell 中调用 grep 是一样的。结果将显示在 Vim 的 quickfix 中,可用命令与 :make 一样。

7.11 modeline

每个文件可以包含一个模式行,模式行必须在文件的第一行或者最后一行,格式固定用对应语言的注释语法,如 C 的

/* vim: set ai tw=75: */

vim: set 之前必须有一个空格,命令必须以 : 结束,中间用空格隔开的是个 set 的 Options。