# 第三章 Vim 常用命令 在第二章已经介绍了 VimL 语言的基本语法,理论上来说,就可以据此写出让 vim 解释 执行的合法脚本了。然而,能写什么脚本呢?除了打印“Hello World!”,以及高级点的 用循环计算诸如“1+2+...+100”这样人家好像也能心算的题目外,还能干嘛呢? 所以,如果要让 vim 脚本真正有实用价值,还得掌握 vim 提供的内置命令,用以控制 Vim 或定制 Vim。本章就来介绍一些主要的、常用用的命令。 Vim 是个极高自由度的文本编辑软件,它在以下几个层级上给用户提供了自由度: 1. `option` 选项。预设了一个很庞大的选项集,用户可以按自己的喜好设置每个选项的 值(当然很多选项也可以接受默认值而假装当它们不存在),这可能改变 Vim 的很多 基础表现与行为。 2. `map` (快捷键)映射。一个非常简单但非常强大的机制。用户可以根据自己的习惯 来重新映射各种模式下不同按键(及按键序列)的解释意义。初入门的 Vimer 很容易 沉迷于折腾各种快捷键。 3. `command` 自定义命令。Vim 是基于 ex 命令的,然后允许又你自定义 Ex 命令。可 见这是比简单映射更灵活强大的利器,当然它的使用要求也比映射要高一些。 4. `VimL` 脚本。进一步将命令升级为脚本语言,据此开发插件,使得 Vim 的扩展性具 有无限可能。在 Vim 社区已经涌现了很多优秀插件,大多可以直接拿来用。当自己掌 握了 VimL 语言后,也就可以自己写些插件来满足自己的特殊需求或癖好。 本教程虽是旨在 VimL 脚本语言,但还是有必要从简单的选项说起吧。 ## 3.1 选项设置 ### 选项分类与设置命令 设置选项的命令是 `set`。根据选项值的不同情况,可以将选项分为以下三类: 1. 不需要值的选项,或者说是 bool 型的开关切换状态的选项。这种选项有两个相对立 的选项名,分别用命令 `:set option` 表示开启选项,`:set nooption` 表示关闭选 项。例如 `:set number` 是设置显示行号,`:set nonumber` 是设置不显示行号。 2. 选项有一个值。用命令 `:set option=value` 设定该类选项的值。选项值可以是数字 或字符串,但字符串的值也不能加引号,就按字面字符串理解。也就是说,`:set` 后 面的参数,不是 VimL 的表达式,与 `:let` 命令有根本的不同。这个命令更像是 `shell` 设置变量的语法,`=` 前后也最好不要用空格。 3. 选项允许有多个值,值之间用逗号分隔。设置命令形如 `:set option=val1,val2`。 此外还支持 `+=` 增量与 `-=` 减量语法,如 `:set option+=val3` 或 `:set option-=val2`,表示在原来的“值集合”的基础上增加某个值或移除某个值。 ### 选项值变量 在选项名前面加个 `&` 符号,就将一个选项变成了相应的选项值变量。例如,以下两条 命令是等效的: ```vim : set option=value : let &option = value ``` 与普通变量赋值一样,`=` 前后的空格是可选的,这里的空格只是一种编程习惯,为增加 可读性。另外有以下几点要注意: 1. 第一类选项,在用 `:set` 命令时不需要等号,但是用 `:let &` 命令时也要用等号将 其值赋为 1 或 0,分别表示开启选项与关闭选项。同时 `&` 只允许作用在没有 `no` 前缀的选项之前。比如 `:let &nonumber = 1` 是非法的,只能用 `:let &number = 0` 表示相同意图。 2. 第二类选项,如果值是字符串,用 `:let &` 命令时要将值用引号括起来,也就像普 通变量赋值一样,要求等号后面是合法的表达式。 3. 第三类选项,它的值也是一个由逗号分隔的(长)字符串,比如 `:echo &rtp`。并不 能由于这类选项支持多个值就将 VimL 的列表赋给它,不过很容易通过 `split()` 函 数从这类选项值中分隔出一个列表。 备注:选项设置 `:set` 应是历史渊源最早的命令之一吧。而 `:let` 是后来 VimL 语言 发展丰富起来提供的命令。两者有不一样的语法,所以又提供了这种等价转换方法。 ### vimrc 配置全局选项 严格地说,`:set` 是设置全局选项的命令。既是影响全局的选项,一般是要第一时间在 `vimrc` 中配置的。最重要的是以下两条配置: ```vim : set nocompatible : filetype plugin indent on ``` 第一条配置是说不要兼容 `vi`,否则可能有很多 `vim` 的高级功能用不了。第二条配置 (虽然不是 `set` 选项)是用 Vim 编写程序源代码必要的,意思是自动检测文件类型, 加载插件,自动缩进的意思。除非在很老旧的机器上,或为了研究需要,一般都没理由不 加上这两条至关重要的配置。 下面再介绍一些比较重要的几类配置选项,当然这远远不够全面。查看选项的帮助命令是 `:help options`,查看某一个选项的帮助是在用单引号括起选项名作为帮助参数,例如 `:help 'option'`。查看某个选项的当前值是命令 `:set option?` 或 `:echo &option` 。 + 编码相关:encoding fileencodings fileencoding - encoding 是 Vim 内部使用的编码。建议 `:set encoding=utf-8`。 - fileencodings 是打开文件时,Vim 用于猜测检测文件编码的一个编码列表。对中文 用户,建议 `:set fileencodings=ucs-bom,utf-8,gb18030,cp936,latin1`。 - fileencoding (局部选项),当前文件的编码,如果与 encoding 不同,在写入时 自动转码。用户一般不必手动设这个选项,除非你想用另外一种编码保存文件。 + 外观相关:number/relativenumber wrap statusline/tabline - number 是在窗口左侧加一列区域显示行号,relativenumber 显示相对行号,即相对 光标所在的行的行号,当前行是 0,上面的行是负数,下面的行是正数。 - wrap 是指很长的文本行折行显示。一般良好风格的程序源文件不应出现长行,但 Vim 作为通用文件编辑器,不一定只用于编辑程序。 - statusline 是定制状态栏,格式比较复杂,建议查看文档,也有些插件提供了很炫 酷的状态栏。tabline 的定制格式与状态栏一样,在开多个标签页时才生效。 - laststatus 什么时候显示状态栏,建议用值 `2` 表示始终显示状态栏。 - cmdheight 命令行的高度,默认只有 1 行太少,当命令行有输出时可能经常要多按 一个回车才回到普通模式。建议 2 行,更多就浪费空间了。 - wildmenu 这是在编辑命令行时,按补全键后,会临时在状态栏位置显示补全提示。 + GUI外观:只在 gVim 或有 GUI 版本的 Vim 有效 - guioptions 设置 GUI 各部件(菜单工具栏滚动条等)是否显示。 - clipboard 设置剪切板与 Vim 的哪个寄存器关联。 + 颜色主题: - colorscheme 这是个单独的命令,不是 `set` 选项。选择一个颜色主题。颜色主题 是放在运行时各路径的 `colors/` 子目录的 `*.vim` 文件。 - background 背景是深色 `dark` 或浅色 `light`。有的 colorscheme 只适于深色或 浅色背景,有的则分别为不同背景色定义不同的颜色主题。 - term 与 t\_Co 有的颜色主题可能还与终端与终端色数量有关。 - cursorline 与 cursorcolumn 用不同格式高亮当前行与当前列,具体高亮格式由颜色 主题定义。个人建议只高亮 cursorline 。 - hlsearch 高亮搜索结果。 + 格式控制: - formatoptions 控制自动格式化文本的许多选项,建议看文档。 - textwidth 文本行宽度,超过该宽度(默认78)时自动加回车换回。在编辑程序源文 件时可用上个 formatoptions 选项控制只在注释中自动换行但代码行不自动换行。 - autoindent smartindent 插入模式下回车自动缩进。 - shiftwidth 缩进宽度。 - tabstop softtabstop 制表符宽度,软制表符是行首按制符缩进的宽度。一般建议 硬制表符宽度 tabstop 保持 8 不变,用 shiftwidth softtabstop 表示缩进。 - expandtab 插入制表符自动转为合适数量的空格。 - paste 将 Vim 的插入模式置于“粘贴”模式,从外部复制文本进 Vim 开启该选项可避 免一些副作用。但只建议临时开启该选项。 + 路径相关: - runtimepath 运行时路径,简称(rtp)。vim 在运行时搜索脚本的一组路径。一般 不手动设置该值,如果有插件管理器管理插件的话。插件必须放在某个 `&rtp` 路径 下,现在流行的是将插件工程主目录添加至 Vim 的 `&rtp` 中。 - packpath (Vim8开始才支持)动态加载插件的搜索路径,默认是 `~/.vim/pack`。 插件主目录可置于 `{packpath}/{packname}/opt/{plugin}`。然后用 `:packadd` 启用插件。 - path 这是 vim 在寻找编辑文件,如 `gf` `:find` 等命令时所要搜索的一组目录。 - tags 这是 vim 按标签跳转 `Ctrl-]` 或 `:tag` 等命令所依据的标签文件,默认是 `./tags,tags`(相对路径)。一般不建议修改默认值,但可以默认值基础上添加更 多的标签文件,比如编辑一个工程时,将工程主目录下的 tags 文件也加进来。 - autochdir 将当前路径自动切换到当前编辑的文件所在的目录。当你依赖一些管理工 程类的插件时,可能要求当前路径锁定在工程主目录,不宜开启该选项。但是个人喜 欢开启这选项,这样在用 `:e` 命令打开同目录下的其他文件时很方便。 Vim 所支持的选项实在是太多了。初学者建议参考前人经验成熟的配置,用 `:help` 查 看每个选项的具体含义,然后决定这种选项是否适合自己。另外注意有些选项可能要配合 起来才能发挥更好的效果。 ### VimL 控制局部选项 局部选项是只影响当前缓冲文件或窗口(buffer/window)的选项。严格来说是局部选项 值,而不是有另外一类选项。默认情况下每个新文件或窗口都继承选项的全局值,但对于 一些选项,可以为该文件或窗口设定一个不同与全局的局部值。然而并不是所有选项都有 局部值意义,在每个选项的帮助文档中,会指明该选项是全局(global)或局部的( local to buffer 或 local to window)。 设置局部选项(值)用 `:setlocal` 命令。如果目标选项没有局部值,则等效 `:set` 命令设置全局值。但是最好不要混用,避免误解。局部选项值变量用 `&l:option` 表示 。比如 `number` 行号就是个局部选项: ```vim : set nonumber : setlocal number : echo &number : echo &l:number : echo &g:number ``` 你可以将 vim 分裂出两个窗口(`:split` 或 `:vsplit`),在其中一个窗口上执行以上 语句,试试看结果。需要注意的是,虽然局部选项值借用了变量的局部作用域前缀 `l:` ,但它的默认规则又有点不同。看这里的 `&number` 是默认的 `&l:number` 而不是 `&g:number`。事实上,普通的局部变量 `l:var` 根本不能在函数外的命令行使用。 当用 VimL 写脚本时,如果要改变选项设置,且该选项支持局部值,最好用 `:setlocal` 只改变局部值。这也是编程的一大原则,尽量将影响局部化。下面介绍一些比较重要的局 部选项设置: + 文件类型:filetype - 大部分情况下,这个选项不用手动设置,也不用脚本显式设置,打开自动检测就可以自 动根据后缀名设置相应的文件类型。不过在创建新的文件类型时,可能需要自己设置 这个选项。 - 文件类型插件,如 `~/.vim/ftplugin/*.vim` 脚本内若涉及选项更改,也尽量用 `:setlocal` 只设局部选项。 + 缓冲类型:buftype - "buffer type" 与 "file type" 是两个不同的概念。缓冲类型更加抽象,是 vim 内 部用于管理缓冲的一些控制属性,而文件类型是着眼于文件内容性质的。 - `buftype` 的两个重要的选项值是 `nofile` 与 `nowrite`,表示特殊的不用写文件 的 buffer,而这两者又还有细微差别,具体请读文档。 + 其他 buffer 属性: - buflisted 是否将当前缓冲记录在缓冲列表中。 - bufhidden 当缓冲不再任一窗口展示,如何处理该缓冲,有几种不同的选项值。 - modifiable 当前缓冲是否可修改,包括更改编码与换行符格式也算种修改。 由于在 Vim 中,最主要的可见(可编辑)对象就只是 buffer,所以在一些复杂而细致的 插件中,经常会开辟一个辅助窗口,仅为展示辅助内容,这就往往要设置一个特殊的 `buftype` 及其他一些 buffer 属性。 此外,在脚本中,可能有需求只临时改变某个选项值,处理完毕后再恢复原选项设置,这 就要借且选项值变量了。处理流程大致如下: ```vim : let l:save_option = &l:option : let &l:option = ? |" 或者 setlocal option = ? : " do something : let &l:option = l:save_option ```