Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1458302
  • 博文数量: 408
  • 博客积分: 10036
  • 博客等级: 上将
  • 技术积分: 4440
  • 用 户 组: 普通用户
  • 注册时间: 2006-04-06 13:57
文章分类

全部博文(408)

文章存档

2011年(1)

2010年(2)

2009年(1)

2008年(3)

2007年(7)

2006年(394)

我的朋友

分类: LINUX

2006-07-13 10:36:17



  作者:1  发布时间:2006-04-05 13:58:09.0  
   前面两部分讲的都是如何使用现有的 Vim 系统,本部分则会通过实例来讲如何定制 Vim 的行为。良好的定制可以让使用 Vim 变得更为得心应手;同时,在掌握了基本的定制之后,也许你就会想进一步写一些自己的 Vim 脚本,从而真正地成为一个Vim专家。  
 

在 .vimrc 文件中,和在第二章提到的插件和语法文件中,使用的语言就是 Vim 脚本语言。这种脚本语言语法有点像 BASIC,表达式有点像 C,还是比较容易理解的。本章中并不打算对其作很系统的介绍(要完整了解的话,请参见":help usr_41.txt"),而只是介绍一些基本知识,特别是,了解定制.vimrc 所需要的基本知识。

Vim脚本相当于可直接在命令模式 下执行的命令,只是不需要输入前面的冒号(如果用了冒号也不会出错)。因此,像设置选项、创建键盘映射这样的命令是直接可用的。当然,作为一种脚本语言, 除了普通键盘上会输入的命令外,我们还需要一些更复杂的功能,特别是:变量,表达式,条件和循环语句,函数。

Vim中使用如下的语法对变量进行赋值(创建变量):

变量类型有两种,整数和字符串,在第一次赋值之前都不能使用。变量名除了可使用常规的字母、下划线和数字外,还可以使用几种特殊的前缀:

  • "b:"--只对当前缓冲区(buffer)有效的变量;
  • "w:"--只对当前编辑窗口(window)有效的变量。
  • "g:"--全局变量(在函数中访问全局变量必须使用该前缀,不加前缀的话则认为是函数内的局部变量);
  • "s:"--变量名只在当前脚本中有效;
  • "a:"--函数的参数;
  • "v:"--Vim内部预定义的特殊变量(参见":help vim-variable")。

下面三个前缀用来访问特殊的数值,由于行为和变量较为相似(可以读取和修改),也放在这儿一起讲:

  • "$"--访问环境变量;
  • "&"--访问Vim选项;
  • "@"--访问寄存器。

当变量不再使用时,可以使用"unlet 变量名"删除变量。

和C 非常类似,可以使用变量和常量,可以使用括号,可以调用函数("函数名(...)"),支持加法("+")、减法("-")、乘法("*")、除法 ("/")和取模("%"),支持逻辑操作("&&"、"||"和"!"),支持三元条件表达式("a ? b : c")。字符串操作方面当然比C要强,可以使用"."进行字符串拼接;可使用"=="、"<="等进行字符串大小比较,可使用"=~"和"!~"进 行正则表达式匹配,而且可以在比较操作符后面添加"#"或"?"来强制进行大小写敏感或不敏感的比较(缺省受Vim选项ignorecase影响)。显示 一个表达式的结果,可以使用":echo 表达式"显示到状态栏上,或者在插入模式下使用"Ctrl-R=表达式"插入到缓冲区的文本中。

和 其它很多在Unix下成长起来的语言一样,Vim的字符串常量有双引号和单引号两种方式。使用单引号的话,单引号间的任何字符都是字符串的一部分,其中不 能再包含单引号。使用双引号的话,则可以使用"\"产生换码序列(具体可参考":help expr-quote"),如"\n"代表换行符,"\""代表双引号,"\\"代表反斜杠本身,等等。

需要注意的话,双引号除了可以表示字符串常量外,还可以表示注释。行首的""",以及表达式中出现的成单的""",都表示"""后面的部分全部是注释。

条件语句形式如下:

if 表达式
  语句
endif

if 表达式
  语句
else
  语句
endif

if 表达式
  语句
elseif 表达式
  语句
endif

循环语句形式如下:

while 表达式
  语句
endwhile

条件和循环语句都可以嵌套。这些比较简单,就不多加说明了。

在表达式中使用函数时,就跟C里面的方式类似,直接使用函数名加括号,括号里写上参数(可选)。在不需要返回值的情况下调用函数时,稍稍有些不同,要使用"call"命令,后面跟函数名和括号(括号里面写上可能有的参数)。

定义函数使用下面的语法:

function 函数名称(参数列表)
  语句
endfunction

如果已有同名函数存在,Vim 会报错,除非在"function"后面加上一个"!"。

如 果参数中不包含"...",那么参数的数量是固定的,函数的调用者必须提供跟定义同样多的参数(在函数定义中使用参数名之前加上"a:"进行访问)。如果 参数中包含"...",那么参数的数量不固定,除了可以使用参数名称访问传递过来的参数外,还可以使用"a:0"知道额外传递的参数数量,使用"a: 1"、"a:2"等访问这些额外传递的参数。

要在函数的中间返回,或者要返回数值的话,可以使用"return"语句。

Vim内部定义了一百多个函数,详细列表请参见":help function-list"。

作为一个 Vim 脚本的一个具体示例,我将讲解一下最实用的情况,我的.vimrc文件。文件 .vimrc.html (请下载到本地打开) 是我的 .vimrc 文件通过以下步骤生成的 HTML 文件:

1. 在 Vim 中打开 .vimrc 文件;

2. 执行命令":colorscheme koehler"(缺省配色可能在浏览器中效果不佳)

3. 执行命令":%!nl -w4 -s' '"

4. 执行命令":TOhtml"

5. 执行命令":w"

可以把浏览器中的文本内容粘贴到 Vim 中,然后使用下面这个替换命令":%s/^ \+[0-9]\+ //"删除前面的行号,来恢复出最初的 .vimrc 文件。

下面逐行进行讲解,并包含理解其内容所需的资料的链接。建议大家直接阅读 .vimrc 文件的内容,并在有疑问时查阅下面的解释。

第1行:注释(1.2节末段),其中包含一个模式行。

第 2 行:首先判断系统是否具有"自动命令"(autocmd)的支持,有的话才执行第 3 到第六行的内容(":help has"和":help feature-list")。

第3行:纯注释(后面我将跳过注释行不再说明)。

第4行:清除所有的自动命令(":help autocmd-remove"),以方便调试,可以使用"source ~/.vimrc"查看一些修改后的效果(":help source")。

第6行:对于后缀为".asm"的文件,认为其是微软的Macro Assembler格式(":help masm-syntax")。

第7行:与第2行的if语句配对。

第8-10行:当使用了图形界面时(":help feature-list"),确保所有的文件类型会在菜单"语法"("Syntax")下出现,而不是出现一个菜单项"Show filetypes in menu"。缺省行为可以让Vim启动得更快一点点。

第11-13行:当使用了图形界面,并且环境变量LANG中不含"."(即没有规定编码)时,把Vim的内部编码设为UTF-8。

第14行:不需要保持和vi非常兼容(":help 'compatible'")。

第15行:执行Vim缺省提供的.vimrc文件的示例,包含了打开语法加亮显示等最常用的功能。

第16行:打开自动缩进。

第17行:缺省不产生备份文件(":help 'backup'")。

第18行:在输入括号时光标会短暂地跳到与之相匹配的括号处,不影响输入(":help 'showmatch'")。

第19行:正确地处理中文字符的折行和拼接。

第20行:可自动识别的文件类型为带BOM字符的Unicode文件、UTF-8编码的文件和GBK编码的文件。

第21行:设置状态行,使其能额外显示文件的编码信息,如图 2 中的"gbk"和"big5"(":help 'statusline'")。



图2

第22-24行:如果该Vim支持鼠标,则启用鼠标支持。

第25-29行:判断Vim是否包含多字节语言支持(multi_byte特性),并且版本号(":help v:version")大于6.1(包含ambiwidth选项)。

第26-28行:如果Vim的语言(":help v:lang";受环境变量LANG影响)是中文(zh)、日文(ja)或韩文(ko)的话,将模糊宽度的Unicode字符的宽度(ambiwidth选项)设为双宽度(double)。

第31 -36行:改变上、下方向键行为方式:通常情况下这些键的作用范围是逻辑行,所以如果行很长的话光标的移动可能会不太方便;这些键盘映射把这些键的作用范 围改成屏幕行("help gk"),还为习惯使用"j"、"k"的人增加了映射"Ctrl-j"和"Ctrl-k"作用于屏幕行。前面四个映射使用的命令是"noremap",作 用于正常模式、可视模式和命令执行时;后面两个映射使用的命令是"inoremap",仅作用于插入模式,其中使用"Ctrl-O"临时执行一个普通模式 的命令(":help i_CTRL-O")。

第38-41行:在Vim中的插入模式中可以使用"Ctrl-R ="计算整数表达式的数值,但Vim本身没有计算浮点表达式的能力。这四个映射提供了浮点表达式的计算能力:使用"\ma"(假设Leader字符为缺省的"\",参见":help ") 可将计算的结果放到下一行上(待计算的表达式为当前行或在可视模式选中的内容),使用"\mr"则用计算的结果替换待计算的表达式(同样为当前行或在可视 模式选中的内容)。这些映射假设有一个命令"calcu"可用来计算一个表达式的内容。该命令可用下面的shell脚本简单实现:

#! /bin/sh
echo "$*" | sed -e $'s/\r$//' -e 's/sin *(/s(/g' -e 's/cos *(/c(/g' -e 's/atan *
(/a(/g' -e 's/log *(/l(/g' -e 's/exp *(/e(/g' | bc -l

该脚本把表达式转换成bc 0能接受的形式(把"sin(x)"转换成"s(x)",等等),并通过标准输出送到bc的标准输入。

该 映射较为复杂,此处不详加解释了--其中心思想都是选取待计算的表达式,放到无名寄存器中,然后使用"Ctrl-R""粘贴到命令行上,使用calcu进 行计算,再把结果粘贴回正在编辑的缓冲区中;最后一个最复杂,因为为了替换原先的表达式,还需要记住原先被选中的内容的起始和结束位置,你可能希望看一下 ":help gv"、":help v_o"、":help m"、":help `",并复习节。可以注意一下,在映射中使用了""(":help map-"),这会防止命令行上回显执行的内容。

第43-44行:允许用户使用F2来取消搜索/替换的加亮显示。此处一个映射用于正常模式(nmap),一个用于插入模式(imap)。上面已经提过一次,"Ctrl-O"可以在插入模式中执行一个正常模式的命令。

第46-47行:这两个映射用于taglist插件,使用 F9 直接打开(或关闭)taglist的窗口。

第49-50行:方便快速修订窗口的使用,可使用F11(和F12)查看下一个(上一个)错误(或grep项等)。

第52-65行:一些适用于文本模式运行的Vim的设定;详见下面的具体说明。

第54-56行:将变量Tlist_Inc_Winwidth的值设为0,防止taglist插件改变终端窗口的大小(有些情况下会引起系统不稳定)。使用"has('eval')"是让该语句仅在功能较为完整、至少支持表达式的Vim版本中运行。

第58-64行:在系统支持wildmenu特性(":help 'wildmenu'")启用文本模式的菜单。

第59行:打开wildmenu选项,启动具有菜单项提示的命令行自动完成。

第60行:确保字符序列""被理解为Ctrl-Z而不是分开的五个字符(":help 'cpoptions'")。

第61行:设置使用Ctrl-Z激活自动完成提示。

第62-63行:把正常模式和插入模式下的F10映射成执行菜单项,并自动提示菜单内容。注意缺省菜单仍不会自动载入,我使用该特性的主要目的是在文本模式的Vim中使用CVS菜单。图16是按F10键后再按Tab键的结果。



图2

第66-161行:使用自动命令(autocmd)特性的设置。使用"has"来防止该部分内容在不支持自动命令的Vim版本中运行。

第67 -129行:定义了若干个下面的自动命令会用到的函数,具体在下面的自动命令中讲。请注意在每个"function"之后都用了一个"!"(":help E122"):这也是为了方便调试,让"source ~/.vimrc"能正确运行而不会报告函数已定义的错误。

第131-133行:只 要没有将环境变量VIM_HATE_SPACE_ERRORS的值设为零,则把变量c_space_errors的值设为1--效果是在C/C++代码中 "不正确"的空白字符(行尾的空白字符和紧接在制表符之前的空格字符)将会被高亮显示。图17所示的代码中,第3行的行尾多了两个空格,第5行的第一个制 表符之前多了个空格。Vim提示#935里有一些额外的说明。同时请参看对第160行的说明。



图 17

第135 行:使用的英文拼写变体为加拿大风格,即:使用拼写"abridgement"(而不是"abridgment")、"colour"(而不是 "color")、"realize"(而不是"realise")、"theatre"(而不是"theater")等,比较符合中国人一般的英语教科 书中的拼写方式,也比较适合于写"国际"英语。

第138行:使用键盘映射"\a"来查看光标下字符的属性,主要用于调试Vim的语法文件。 图18显示了光标下的字符所属的语法"组"为vimOption,使用配色方案中的PreProc(预处理符号)项,前景色为紫色(RGB: #a020f0)。有兴趣可查看Vim脚本#383的具体内容。



图18

第140 行:在函数找不到时(":help FuncUndefined"),自动在运行环境(Linux下一般为~/.vim)的autoload目录下读入与函数名同名的.vim文件。这是脚本 #383的建议安装方式(SyntaxAttr.vim文件放在autoload目录下,仅在执行时载入)。

第142行:设置适用于C/C++文件的选项。

第143行:把补丁文件的缩进和制表符宽度设定设成和C/C++文件相同。

第144行:取消Vim对HTML标记自动产生的缩进,但打开自动缩进选项。

第145行:对于变更日志类型的文件,设置行宽为76个字符。

第147 行:当文件后缀为".gb"时,认为这是一个GBK编码的文件,在读入文件之前(":help BufReadPre")调用函数SetFileEncodings把原先的fileencodings选项的内容保存在本缓冲区的一个变量中(1.1 节),然后把fileencodings设成gbk,即只尝试对文件内容作为GBK字符序列来解释。

第148行:类似于上面把".big5"后缀的文件当作Big5编码的文件,在读入文件之前把fileencodings设成big5,只尝试对文件内容作为Big5字符序列来解释。

第149行:类似于上面把".nfo"后缀的文件当作CP437编码(即英文DOS的OEM字符集编码)的文件。效果可参看图19。



图19

第150行:在读入.gb、.big5或.nfo文件之后(":help BufReadPost"),调用函数RestoreFileEncodings恢复保存起来的fileencodings原数值。

第151 行:对于.txt后缀的文件,在显示文件时(":help BufWinEnter",确保在模式行被执行之后)调用函数CheckFileEncoding检查文件是否已修改并且fileencoding设有数 值。条件满足的话说明该文件在模式行中修改了fileencoding,因而使用该编码(":help ++enc")重新强制("!")读入该文件以保证文件被正确解码。Vim提示#911里有一些额外的说明。

第153行:在遇到HTML文 件时,如果Vim判断出的编码类型和HTML代码中使用""规定的编码不一致,将使用网页中规定的编码重新读入该文件。函数 ConvertHtmlEncoding会把一些网页中使用的编码名称转换成Vim能够正确处理的编码名称;函数DetectHtmlEncoding在 判断文件类型确实是HTML之后,会记下当前的光标位置,并搜索上面这样的HTML代码行,找出字符集编码后,在编码不等于当前文件编码 (fileencoding)时且当前文件编码为空或等于系统判断出的文件编码时,使用该编码强制重新读入文件,忽略任何错误("silent!")。该 自动命令写成是可嵌套执行的(":help autocmd-nested"),目的是保证语法高亮显示有效,且上次打开文件的光标位置能够正确保持。Vim提示#1074里有一些额外的说明。

第155 -156行:确保把/usr/include/c++和/usr/include/g++-3目录下的所有文件都当成C++类型的文件,不管Vim原先认 定这些文件类型是什么(":help BufEnter")。C++的很多标准头文件(如"algorithm")没有文件后缀,缺省情况下不会被Vim当作C++文件。

第158行:第142行把C/C++文件的制表符宽度设成了4(个人设置),但系统的源代码一般使用GNU编码规范,制表符宽度为8。该行设置所有/usr目录下的文件都使用GNU编码规范。

第160 行:在写文件之前(":help BufWritePre"),调用函数RemoveTrailingSpace:只要没有将环境变量VIM_HATE_SPACE_ERRORS的值设为 零,则对于文件类型为C、C++、Vim脚本类型的文件,自动悄悄清除所有的行尾空白字符;"normal m`"记忆当前的光标位置,"normal ``"恢复记忆下来的光标位置。

至此为此,我已经介绍了Vim的基本知识、很多实用技巧和一些最常用的Vim插件,并通过定制.vimrc 文件介绍了脚本的基本知识。如果有需要进一步深入学习Vim或是想提什么关于Vim的特定问题的话,不妨参加从Vim的网站上参加Vim的邮件讨论列表, 应该会获益良多。而作者也希望本文至此也已经完成了引导读者学习、了解Vim的高级特性的任务。

  • bc: (Unix)


吴咏炜,通过 可以和他联系。

本文转载自 IBM developerworks,版权归 IBM developerworks 所有。

阅读(782) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~