You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

208 lines
13 KiB

2 years ago
# 第三章 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
```