vi/vim 基本使用方法
vi编辑器是所有Unix及Linux系统下标准的编辑器,它的强大不逊色于任何最新的文本编辑器,这里只是简单地介绍一下它的用法和一小部分指令。
1、vi的基本概念
基本上vi可以分为三种状态,命令模式(command mode)、插入模式(Insert mode)和底行模式(last line mode),各模式的功能区分如下:
1) 命令行模式command mode)
控制屏幕光标的移动,字符、字或行的删除,移动复制某区段及进入Insert mode下,或者到 last line mode。
2) 插入模式(Insert mode)
只有在Insert mode下,才可以做文字输入,按「ESC」键可回到命令行模式。
3) 底行模式(last line mode)
将文件保存或退出vi,也可以设置编辑环境,如寻找字符串、列出行号……等。
不过一般我们在使用时把vi简化成两个模式,就是将底行模式(last line mode)也算入命令行模式command mode)。
2、vi的基本操作
a) 进入vi
在系统提示符号输入vi及文件名称后,就进入vi全屏幕编辑画面:
$ vi myfile
b) 切换至插入模式(Insert mode)编辑文件
在「命令行模式(command mode)」下按一下字母「i」就可以进入「插入模式(Insert mode)」,这时候你就可以开始输入文字了。
c) Insert 的切换
您目前处于「插入模式(Insert mode)」,您就只能一直输入文字,如果您发现输错了字!想用光标键往回移动,将该字删除,就要先按一下「ESC」键转到「命令行模式(command mode)」再删除文字。
d) 退出vi及保存文件
在「命令行模式(command mode)」下,按一下「:」冒号键进入「Last line mode」,例如:
: w filename (输入 「w filename」将文章以指定的文件名filename保存)
: wq (输入「wq」,存盘并退出vi)
: q! (输入q!, 不存盘强制退出vi)
3、命令行模式(command mode)功能键
1). 插入模式
按「i」是从光标当前位置开始输入文件;
按「a」是从目前光标所在位置的下一个位置开始输入文字;
按「o」是插入新的一行,从行首开始输入文字。
2). 从插入模式切换为命令行模式
按「ESC」键。
3). 移动光标
vi可以直接用键盘上的光标来上下左右移动,但正规的vi是用小写英文字母「h」、「j」、「k」、「l」,分别控制光标左、下、上、右移一格。
按「ctrl」+「b」:屏幕往“后”移动一页。
按「ctrl」+「f」:屏幕往“前”移动一页。
按「ctrl」+「u」:屏幕往“后”移动半页。
按「ctrl」+「d」:屏幕往“前”移动半页。
按数字「0」:移到文章的开头。
按「G」:移动到文章的最后。
按「$」:移动到光标所在行的“行尾”。
按「^」:移动到光标所在行的“行首”
按「w」:光标跳到下个字的开头
按「e」:光标跳到下个字的字尾
按「b」:光标回到上个字的开头
按「#l」:光标移到该行的第#个位置,如:5l,56l。
4). 删除文字
「x」:每按一次,删除光标所在位置的“后面”一个字符。
「#x」:例如,「6x」表示删除光标所在位置的“后面”6个字符。
「X」:大写的X,每按一次,删除光标所在位置的“前面”一个字符。
「#X」:例如,「20X」表示删除光标所在位置的“前面”20个字符。
「dd」:删除光标所在行。
「#dd」:从光标所在行开始删除#行
5). 复制
「yw」:将光标所在之处到字尾的字符复制到缓冲区中。
「#yw」:复制#个字到缓冲区
「yy」:复制光标所在行到缓冲区。
「#yy」:例如,「6yy」表示拷贝从光标所在的该行“往下数”6行文字。
「p」:将缓冲区内的字符贴到光标所在位置。注意:所有与“y”有关的复制命令都必须与“p”配合才能完成复制与粘贴功能。
6). 替换
「r」:替换光标所在处的字符。
「R」:替换光标所到之处的字符,直到按下「ESC」键为止。
7). 回复上一次操作
「u」:如果您误执行一个命令,可以马上按下「u」,回到上一个操作。按多次“u”可以执行多次回复。
8). 更改
「cw」:更改光标所在处的字到字尾处
「c#w」:例如,「c3w」表示更改3个字
9). 跳至指定的行
「ctrl」+「g」列出光标所在行的行号。
「#G」:例如,「15G」,表示移动光标至文章的第15行行首。
4、Last line mode下命令简介
A) 列出行号
「set nu」:输入「set nu」后,会在文件中的每一行前面列出行号。
B) 跳到文件中的某一行
「#」:「#」号表示一个数字,在冒号后输入一个数字,再按回车键就会跳到该行了,如输入数字15,再回车,就会跳到文章的第15行。
C) 查找字符
「/关键字」:先按「/」键,再输入您想寻找的字符,如果第一次找的关键字不是您想要的,可以一直按「n」会往后寻找到您要的关键字为止。
「?关键字」:先按「?」键,再输入您想寻找的字符,如果第一次找的关键字不是您想要的,可以一直按「n」会往前寻找到您要的关键字为止。
D) 保存文件
「w」:在冒号输入字母「w」就可以将文件保存起来。
E) 离开vi
「q」:按「q」就是退出,如果无法离开vi,可以在「q」后跟一个「!」强制离开vi。
「qw」:一般建议离开时,搭配「w」一起使用,这样在退出的时候还可以保存文件。
Vim 带有完整的帮助文档。进入 Vim后输入“:help”即可访问。
需要设定的选项通常放在用户的 Vim 资源配置文件中,即在 ~/.vimrc 文件中加入:
set encoding=utf-8
set fileencoding=chinese
set fileencodings=ucs-bom,utf-8,chinese
set ambiwidth=double
如果想进一步了解这些选项的话,可以使用“:help'选项'”查看帮助文档中的相关(英文)信息。帮助中也可以查到这些选项(以及命令)的缩写:本文中为方便理解,除一些极少有人使用完整拼写的命令如“:e(dit)”、“:s(ubstitute)”等之外,一般使用完整拼写而不说明或使用缩写。关于配置文件 .vimrc,可以使用“:help.vimrc”查看相关信息。
1.3. 鼠标支持
不管是文本界面还是图形界面的Vim,都支持鼠标。不过,在文本界面中,鼠标支持缺省没有被激活;这就意味着,在终端上使用鼠标,所有的功能仍和没有使用 Vim 时相同,并不受Vim 影响。要激活文本界面中的鼠标支持也很容易,只需要执行一句“:set mouse=a”即可。
启用了鼠标支持之后,Vim 主要支持的鼠标操作有:
- 单击移动光标到点击的位置;
- 在帮助的关键字上双击显示该关键字相关的帮助信息;
- 在普通文本上双击选中点击位置的单词;
- 拖动鼠标选中文本;
- 使用鼠标滚轮滚动当前缓冲区中的文本;
- 多窗口编辑时可以拖动窗口分栏的位置。
进一步的信息可参看“:help 'mouse'”、“:help mouse-using”和“:help scroll-mouse-wheel”。
1.4. 空格、制表符和缩进
对于编写代码,缩进是最基本的概念之一。以下是相关的主要 Vim选项:
- shiftwidth(缩进的空格数);
- tabstop(制表符的宽度);
- expandtab(是否在缩进和遇到 Tab 键时使用空格替代;使用 noexpandtab 取消设置);
- softtabstop(软制表符宽度,设置为非零数值后使用 Tab 键和 Backspace 时光标移动的格数等于该数值,但实际插入的字符仍受 tabstop 和 expandtab 控制);
- autoindent(自动缩进,即每行的缩进值与上一行相等;使用 noautoindent 取消设置);
- cindent(使用 C 语言的缩进方式,根据特殊字符如“{”、“}”、“:”和语句是否结束等信息自动调整缩进;在编辑 C/C++ 等类型文件时会自动设定;使用 nocindent 取消设置);
- cinoptions(C 语言缩进的具体方式,请参考“:help cinoptions-values”);
- paste(粘贴模式,会取消所有上述选项的影响来保证后面的操作——通常是从剪贴板粘贴代码——保持原有代码的风格;使用 nopaste 取消设置)。
下面给出一些常用的组合:
- shiftwidth=4 tabstop=4:很多 Windows 出身的程序员会习惯这样的设置,让缩进等于制表符宽度。
- shiftwidth=4 tabstop=8:很多 Unix 程序员的设置,仍使用较常用的 4 格缩进,但制表符宽度为标准的 8。
- cinoptions=>4,n-2,{2,^-2,:2,=2,g0,h2,p5,t0,+2,(0,u0,w1,m1 shiftwidth=2 tabstop=8:标准的 GNU 编码风格的设置,对 Vim 缺省的 C 缩进风格作了很多微调,比如,if语句下的“{”、“}”要在“if”后缩进两格,但函数定义部分“{”、“}”仍和函数名一行对齐。开源软件经常使用该种缩进风格。
在编辑代码时一个很有用的命令是调整代码缩进,可以很方便地增加(或减少)若干级缩进,并自动根据选项设定使用正确的空格或制表符。只需要使用“V”选中你要调整的代码行,然后键入“”)即可增加(或减少)一级缩进;在键入“”)之前键入数字则可以指定增加(或减少)的缩进级数。
我们要讨论的最后一个相关的命令是“:retab”。在设定了 expandtab 选项时,该选项会把所有的制表符转换成空格。在没有设定expandtab 选项时,使用“:retab!”可把空白字符转换成制表符(可能误转换,慎用),使用“:retab n”可以把 tabstop重置为 n,并转换含制表符的连续空白字符为适当的制表符和空格的组合以保证含制表符的行看起来没有任何变化。详细信息请参看“:help:retab”。
1.5. 模式行(modeline)
Vim在打开文件时根据文件中的 Vim 指令设定相关的 Vim 选项。下面就是一个嵌在 C 源代码中的模式行:
/* vim: set tabstop=4 shiftwidth=4 expandtab: */
行首的“/*”和尾部的“*/”告诉 C 编译器这是一行注释,不是代码的一部分;而 Vim可通过后面的“vim:”识别出模式行的开始(必须出现在行首或前面有一个空白字符);后面则是“set”和空格间隔开的一串 Vim选项;“:”表示模式行结束。
1.6. 寄存器
通常的编辑器有一个剪贴板,以存储复制和剪切的内容。Vim 中的类似概念叫做寄存器(register)。除了有一个无名寄存器外,Vim还有一大堆有名的寄存器,可以通过“"”(参见“:help "”)或“Ctrl-R”(参见“:help i_CTRL-R”和“:helpc_CTRL-R”)加寄存器名(字母、数字和某些特殊字符,参见“:help registers”;“无名”寄存器的名字是“"”)来访问。比如,你先使用“"ayy”复制了一行,然后使用“dd”删掉了一行,然后移动光标到要复制到的位置,就可以使用“"aP”把先前复制的内容粘贴上去了。手工编辑是有名寄存器的作用还不是很大,但当你想让 Vim通过类似于宏的方式自动完成工作时,有名寄存器就变成不可缺少的重要功能了。
1.7. 搜索、替换和正则表达式
大家应该都已经知道 Vim里使用“/模式”(或“?模式”)进行搜索,使用“:s/模式/字符串/标志”进行替换,其中的“模式”是一个正则表达式。先说一点点搜索,搜索里最最有用的一个快捷方式是“*”(向下完整匹配光标下的单词)。把光标移动到你要搜索的词(变量名、函数名等)上,比如“test”,然后按“*”,Vim 将自动产生一个对“\”(参见“:help /\”)的搜索,也就是说,搜索完整的单词“test”。不要小看这个技巧,它经常可以大幅度地提高搜索的速度。相似的技巧还有“#”(向上完整匹配光标下的单词)、“g*”(向下部分匹配光标下的单词)等,请自行查看(“:help#”等)。
Vim 在搜索和替换时会对匹配成功的文本进行加亮,在已经完成搜索和替换任务后,这种加亮有时反而会妨碍显示。Vim专门提供一个命令取消这种加亮(直到用户再一次使用搜索或替换命令):“:nohlsearch”。建议用户创建一个键盘映射(keymapping)加入到 .vimrc 中,如:
nmap :nohlsearch
以上命令表示,在正常模式下按 F2 键相当于输入“:nohlsearch”后面跟一个回车,即取消搜索加亮显示。
再看几个搜索替换的实用例子。
- 去掉所有的行尾空格:“:%s/\s\+$//”。“%”表示在整个文件范围内进行替换,“\s”表示空白字符(空格和制表 符),“\+”对前面的字符匹配一次或多次(越多越好),“$”匹配行尾(使用“\$”表示单纯的“$”字符);被替换的内容为空;由于一行最多只需替换一次,不需要特殊标志。这个还是比较简单的。
- 去掉所有的空白行:“:%s/\(\s*\n\)\+/\r/”。这回多了“\(”、“\)”、“\n”、“\r”和“*”。“*”代表对前面的字符(此处为“\s”)匹配零次或多次(越多越好;使用“\*”表示单纯的“*”字符),“\n”代表换行符,“\r”代表回车符,“\(”和“\)”对表达式进行分组,使其被视作一个不可分割的整体。因此,这个表达式的完整意义是,把连续的换行符(包含换行符前面可能有的连续空白字符)替换成为一个单个的换行符。唯一很特殊的地方是,在模式中使用的是“\n”,而被替换的内容中却不能使用“\n”,而只能使用“\r”。原因是历史造成的,详情如果有兴趣的话可以查看“:help NL-used-for-Nul”。
- 去掉所有的“//”注释:“:%s!\s*//.*!!”。首先可以注意到,这儿分隔符改用了“!”,原因是在模式或字符串部分使用了“/”字符,不换用其他分隔符的话就得在每次使用“/”字符本身时写成“\/”,上面的命令得写成“:%s/\s*\/\/.*//”,可读性较低。命令本身倒是相当简单,用过正则表达式的人估计都知道“.”匹配表示除换行符之外的任何字符吧。
- 去掉所有的“/* */”注释:“:%s!\s*/\*\_.\{-}\*/\s*! !g”。这个略有点复杂了,用到了几个不太常用的 Vim正则表达式特性。“\_.”匹配包含换行在内的所有字符;“\{-}”表示前一个字符可出现零次或多次,但在整个正则表达式可以匹配成功的前提下,匹配的字符数越少越好;标志“g”表示一行里可以匹配和替换多次。替换的结果是个空格的目的是保证像“int/* space not necessary around comments */main()”这样的表达式在替换之后仍然是合法的。
希望上面的这些简单的例子能够引起你使用 Vim 的正则表达式高效完成任务的兴趣。进一步的信息可参考“:help regexp”。
1.8. 自动完成和路径设定
Vim 支持单词的自动完成。比如,你前面使用了一个很长的变量名,叫aLongVariable,下面你在输入时,就不用完整键入了。很可能,你只需要键入“aL”,然后按下“Ctrl-P”(向前搜索可匹配的单词并完成)就可以得到完整的变量名(没有得到想要的结果的话,多按几下“Ctrl-P”;或者前面多输入几个字符,如“aLongV”)。类似的命令还有“Ctrl-N”(向后搜索可匹配的单词并完成)、“Ctrl-X Ctrl-L”(搜索可匹配的行并完成)、“Ctrl-X Ctrl-F”(搜索可匹配的文件名并完成)等,具体可参看“:help ins-completion”。
如果你并不熟悉这些功能,但也并不觉得这有什么稀奇的话,下面这个例子可能会让你觉得吃惊。请尝试打开一个空白的 C 文件(vim test.c),并输入:
#include
int main()
{
pri
最后一行不要回车,直接在“pri”后面输入“Ctrl-P”,你将看到“printf”出现。是的,虽然文件里没有“printf”,但Vim 知道到哪里去寻找它!在作关键字匹配完成时,如果当前文件和其它打开的文件中没有想要的结果,Vim会自动到“#include”的文件中进行进一步的搜索(为什么是“#include”呢?请查阅“:help 'include'”),搜寻的目录则由选项 path 决定,其缺省值在 Unix(含Linux)下为“.,/usr/include,,”,代表搜索的目录依次是文件所在目录、/usr/include和当前目录。根据实际情况,你可能需要在 .vimrc文件中设置该选项,加入项目相关的包含目录,注意一般要保留最后的“,,”,除非你不需要在当前目录下搜索。设置了合适的 path后,另外带来的便利就是可以使用“gf”命令方便地跳转到光标下的文件名所代表的文件中。在上面的例子中,把光标移到“stdio.h”的任一字符上,键入“gf”,则 Vim 会自动打开 /usr/include/stdio.h 文件。使用“Ctrl-O”(参见“:helpCTRL-O”)可返回到原先的文件中。
1.9. 文件跳转和 Tags
大家一般都知道,在 Vim的帮助窗口中的关键字上双击鼠标或者键入“Ctrl-]”即可跳转至该关键字相关的帮助主题。不过,“跳转至匹配的关键字”这一功能并不仅仅局限于帮助文件。只要有合适的 tags 文件(参见“:helptags-file-format”),我们同样可以在源代码中使用这个方便的功能,跳转到与关键字匹配的“标记”处(通常是源代码中某一函数、类型、变量或宏的定义位置)。
要产生 tags 文件,通常我们使用 Exuberant Ctags [15]。一般的 Linux 发布版中均带有这一工具。Ctags带有的选项数量极多,此处我们仅简单介绍如何在一个典型的多文件、多层目录的项目中使用其基本功能:我们只需在项目的根目录处键入“ctags -R.”,Ctags 即可自动在文件中查找、识别支持的文件格式、生成 tags 文件。目前 Exuberant Ctags 支持多达 33种编程语言 [16],包括了 Linux 下常用的 C、C++、Java、Perl、PHP 等。有了 tags 文件,以下的 Vim命令就可以方便使用了(进一步的信息可参考“:help tags-and-searches”):
- :tag 关键字(跳转到与“关键字”匹配的标记处)
- :tselect [关键字](显示与“关键字”匹配的标记列表,输入数字跳转到指定的标记)
- :tjump [关键字](类似于“:tselect”,但当匹配项只有一个时直接跳转至标记处而不再显示列表)
- :tn(跳转到下一个匹配的标记处)
- :tp(跳转到上一个匹配的标记处)
- Ctrl-](跳转到与光标下的关键字匹配的标记处;除“关键字”直接从光标位置自动获得外,功能与“:tags”相同)
- g](与“Ctrl-]”功能类似,但使用的命令是“:tselect”)
- g Ctrl-](与“Ctrl-]”功能类似,但使用的命令是“:tjump”)
- Ctrl-T(跳转回上次使用以上命令跳转前的位置)
当我们在项目的根目录下工作时,上面这些命令工作得很好。但如果我们进到多层目录的里层再运行 Vim打开文件时,这些命令的执行结果通常就变成了错误信息“E433: No tags file”。这是因为缺省 Vim只在文件所在目录和当前目录下寻找 tags 文件,而我们前面只在项目的根目录下生成了 tags 文件,Vim无法找到该文件。解决方法有好几种,我认为一般较简单的做法是对每个项目都在 .vimrc文件中增加一个路径相关设定。假设我们有两个项目,位置分别是 /home/my/proj1 和 /home/my/proj2,那我们可以使用:
au BufEnter /home/my/proj1/* setlocal tags+=/home/my/proj1/tags
au BufEnter /home/my/proj2/* setlocal tags+=/home/my/proj2/tags
Vim 选项 tags 用于控制检查的 tags 文件,缺省值为“./tags,tags”,即前面所说的文件所在目录下和当前目录下的tags 文件。上面两行自动命令告诉 Vim,在打开项目目录下的文件时,tags 选项中的内容要增加项目的 tags文件的路径。进一步信息可参看“:help 'tags'”。
1.10. Make 和 grep
Make [17] 和grep [18] 应当算是 Unix 世界里无人不晓的基本工具了吧。很自然的,Vim对它们有着特殊的支持。该支持主要通过访问一个特殊的快速修订窗口(quickfix window)来实现。直接在 Vim 的命令模式里输入相应的make 或 grep 命令(如“:grep foo *.c”)即可将命令的执行结果放入该窗口,同时根据返回的结果跳转到第一个错误(make的情况;在使用 grep 时是匹配成功之处)。以下是常用的“快速修订”命令:
- :cn(显示下一个错误)
- :cp(显示上一个错误)
- :cl(列出所有的错误及其编号)
- :cc(跳转到指定编号的错误)
- :copen(打开快速修订窗口,在其中显示所有错误,可在错误上双击鼠标或按回车键跳转至该错误)
Vim 的这个特性也可以与 make 和 grep 以外的程序一起工作(事实上,在 Windows XP上,“:grep”命令一般调起的是“findstr /n”)。具体调用那个程序由选项 makeprg(Linux 下缺省为“make”)和grepprg(Linux 下缺省为“grep -n $* /dev/null”)控制,而如何解析返回的内容则由选项 errorformat和 grepformat 控制。鉴于在 Unix/Linux 下一般不需更改这些选项的内容,此处不再详述。
1.11. 执行外部命令
在“:make”这样的命令中,Vim会自动调用外部的程序。用户当然也可以自己执行外部的程序:估计很多的人都已经知道了用“:!命令”可以在 Vim中执行一个外部命令。不过,估计大部分人都不知道,还有其它一些命令可以执行外部命令,并且,即使“:!”命令里面也有一些技巧可以使用。
最正规的执行外部命令的方法,如前所述,就是“:!”。比如,我们想要显示当前目录下的所有文件,就可以直接执行:“:!ls”。Vim会在一个终端窗口中进行文件列表,然后提示我们按键返回 Vim中。事实上,这种方式对于“cp”、“rm”这样基本不需要输出的命令比较实用,而对于“ls”这样关注于输出的命令并不太适用。如果想把外部命令执行的结果插入到当前编辑的缓冲区中,可以考虑使用“:r!”。比如,我们使用“:r!ls”,就可以把“ls”命令的执行结果插入到缓冲区中光标所在行下面。在使用宏时,这可能会特别有用。Vim 的“:!”命令还有一个特别强大的技巧可以使用。拿一个实际例子,我们需要对在一个文件的每一行之前插入一个编号,该怎么做呢?——用Vim 的宏或者脚本可以完成这一工作,但这不是最高效、最灵活的工作方式。Linux 下一般带有的 GNU 的nl,可以用非常灵活的方式来完成这一任务——要对所有的非空行进行编号,只需要“:%!nl”;要对包含空行的所有行进行编号?OK,“:%!nl-ba”。
稍作一点解释。当使用可视模式选中文本行后然后键入“:!”(命令行上将出现“:'!”,表示命令的范围是选定的文本),或者使用“:%!”(表示命令的范围是整个缓冲区中的文本),Vim在执行后面的命令时,将把命令范围里的文本行作为后面执行的命令标准输入,并用命令执行后的标准输出替换当前缓冲区中的这些文本行。这就是上面的命令行的工作原理。
1.12. 定宽文本排版
在传统的 Unix 环境下,文本文件的定义是具有一定长度限制的文本行的组合 [19]。虽然 Vim本身对行的长度没有任何实际的限制,但有一些工具有这样的限制。为了最大程度的兼容性,也为了在显示、打印等处理上比较方便,一般推荐在邮件和源代码中一般不要超出 72 列(最多不超出 80 列)。Vim 在处理定宽的文本方面具有特殊的支持能力。下面是一个在 Vim 中把行宽(使用选项textwidth)设为 40 后输入 Harry Potter and the Half-Blood Prince 的第一句话的结果:
It was nearing midnight and the Prime
Minister was sitting alone in his
office, reading a long memo that was
slipping through his brain without
leaving the slightest trace of meaning
behind.
输入时我只使用了英文字母和空格,换行符都是 Vim自动插入的。如果在某一行加入或删除了一些字符后行不就不齐了吗,该如何处理?很简单,把光标移到要重新格式化的文本开头,使用“gq”命令后面跟一个光标移动命令确定重新格式化的范围。比如“gq}”(格式化一段),“gq5j”(格式化 5 行),“gqG”(格式化至文件末尾)。
除了选项 textwidth 外,选项 formatoptions 确定了跟文本格式化有关的基本选项,常用的数值有:
- t:根据 textwidth 自动折行;
- c:在(程序源代码中的)注释中自动折行,插入合适的注释起始字符;
- r:插入模式下在注释中键入回车时,插入合适的注释起始字符;
- q:允许使用“gq”命令对注释进行格式化;
- n:识别编号列表,编号行的下一行的缩进由数字后的空白决定(与“2”冲突,需要“autoindent”);
- 2:使用一段的第二行的缩进来格式化文本;
- l:在当前行长度超过 textwidth 时,不自动重新格式化;
- m:在多字节字符处可以折行,对中文特别有效(否则只在空白字符处折行);
- M:在拼接两行时(重新格式化,或者是手工使用“J”命令),如果前一行的结尾或后一行的开头是多字节字符,则不插入空格,非常适合中文
上面提到的注释,可以是 C/C++ 中的“//”和“/*”,也可以是邮件中引用原文使用的“>”等字符(具体由 comments选项控制;参见“:help 'comments'”)。Vim在遇到这些字符时,能够相当智能地进行处理,足以完成日常编辑源代码和邮件的需要。在使用一些处理纯文本不够强大的邮件客户端时,我通常使用 Vim编辑邮件(特别是英文邮件),然后把结果贴回到邮件编辑窗口中进行发送。
Vim 中 formatoptions 的缺省值是“tcq”,一般我会在 .vimrc 文件中加入一行“set formatoptions+=mM”来确保 Vim 能在中文字符之间折行而不要求空格的存在,并且在大部分情况下可以正确地处理中文重新格式化。
1.13. 其它小技巧
也许你会觉得这些很有用:
- %(跳转到与之匹配的括号处)
- .(重复上次的修改命令)
- `.(跳转到最近修改过的位置)
- ZQ(无条件退出)
- ZZ(存盘退出)
- ga(显示光标下的字符在当前使用的 encoding 下的内码)
- guw(光标下的单词变为小写)
- gUw(光标下的单词变为大写)
- :TOhtml(根据 Vim 的语法加亮的方式生成 HTML 代码;在图形界面中也可以使用菜单“Syntax—Convert to HTML”达到同样效果)
VIM中括号的自动补全与删除
很多现代 IDE 都有自动补全配对括号的功能,比如输入了左括号“(”,IDE 就自动在后面添加一个对应的右括号“)”,并且将光标移到括号中间。VIM 虽然没有直接提供这个功能,但要实现其实非常简单,只要在你的 .vimrc 文件中添加下面的内容就可以了:
原理很简单,就是将左括号的键映射为一个新的操作,在输入左括号时,让 VIM 立刻输入右括号,同时再将光标左移一格到括号中间。
除了括号的自动补全,有时我们也需要括号的自动删除。比如在输入了左括号后突然发现输错了,本来只需要简单地按一下退格键,将刚才输入的左括号 删除就行了,但现在 VIM 自动加了一个右括号,退格键只能删除左括号,这个自动加上右括号还得按一下 DELETE 键才能删掉。
所以,我们还需要一个功能,如果按退格键删除了左括号,那么也要自动地把对应的右括号删除。这个操作使用简单的键盘映射就有点难度了,需要借助函数,如下:
01 |
" 按退格键时判断当前光标前一个字符,如果是左括号,则删除对应的右括号以及括号中间的内容 |
02 |
function! RemovePairs() |
03 |
let l:line = getline(".") |
04 |
let l:previous_char = l:line[col(".")-1] " 取得当前光标前一个字符 |
06 |
if index(["(", "[", "{"], l:previous_char) != -1 |
07 |
let l:original_pos = getpos(".") |
09 |
let l:new_pos = getpos(".") |
12 |
if l:original_pos == l:new_pos |
17 |
let l:line2 = getline(".") |
18 |
if len(l:line2) == col(".") |
20 |
execute "normal! v%xa" |
23 |
execute "normal! v%xi" |
30 |
" 用退格键删除一个左括号时同时删除对应的右括号 |
31 |
inoremap :call RemovePairs()a |
这样就比较完美了。不过在非括号时其实还有个小问题(比如“<行首>a<光标>bcde”这样的情况下,按了退格键后,“a”虽然被删除了,但光标不是移到行首,而是移到 b 的后面),但应该不会对使用造成太大影响。
另外,在自动补全了右括号之后,如果用户再输入右括号会怎么样呢?一般来说,比较合理的做法似乎是忽略掉这个后输入的多余的右括号,直接将光标向右移到一格。代码如下:
01 |
" 输入一个字符时,如果下一个字符也是括号,则删除它,避免出现重复字符 |
02 |
function! RemoveNextDoubleChar(char) |
03 |
let l:line = getline(".") |
04 |
let l:next_char = l:line[col(".")] " 取得当前光标后一个字符 |
06 |
if a:char == l:next_char |
09 |
execute "normal! i" . a:char . "" |
12 |
inoremap ) :call RemoveNextDoubleChar(')')a |
13 |
inoremap ] :call RemoveNextDoubleChar(']')a |
14 |
inoremap } :call RemoveNextDoubleChar('}')a |
这样,在 VIM 中输入或删除括号就方便多了!
个人觉得下面这条很实用!!!
:inoremap ;; A;
定义了“;;”快捷键,主要是方便的在多重括号中直接移动到行尾,并添加“;”
无聊的时候,还可以试试:
- :help!
- :help 42
- :help holy-grail