免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2249 | 回复: 1
打印 上一主题 下一主题

vimrc编程 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2006-01-21 18:14 |只看该作者 |倒序浏览

                *41.1*  简介                                  *vim-script-intro*
你最初接触到 Vim 脚本是在 vimrc 文件里。当 Vim 启动时它将读取该文件的内容
并执行其中的命令。你可以在其中设置可选项。你可以在其中使用任何冒号命令 (以
":" 开头的命令; 这些命令有时也被称作 Ex 命令或命令行命令)。
   语法文件其实也是 Vim 脚本。专为某种文件类型设定选项的文件也是。一个很复
杂的宏可以被单独的定义在一个 Vim 脚本文件中。你还可以想到其它的应用。
让我们从一个简单的例子开始:
        :let i = 1
        :while i
        备注:
        那些 ":" 字符并非必须的。它们只是在当你键入命令时才需要。在编写 Vim
        脚本时可以去掉。在这里用一是为了清楚,二是为了区别于普通模式命令。
":let" 命令给一个变量赋值。通常的用法是:
        :let {变量} = {表达式}
在例子中变量名是 "i" 而表达式是一个简单的数值 -- 1。
   ":while" 命令开始一个循环。通常的用法是:
        :while {条件}
        :  {语句}
        :endwhile
只要条件为真,"while" 和 ":endwhile" 包围的语句总被执行。在例子中使用的条件是
表达式 "i
        count is 1
接着是另一个 ":let i =" 命令。所用的表达式是 "i + 1"。这将在变量 i 上加一并将
新的值赋给同一个变量。
   本例的输出是:
        count is 1
        count is 2
        count is 3
        count is 4
        备注:
        如果你碰巧写了一个死循环语句,你可以用 CTRL-C 来终止 (在 MS-Windows
        中使用 CTRL-Break)。
三 种 数 字
数字可以是十进制,十六进制,或者八进制的。以 "0x" 或 "0X" 开始的数字是十六
进制的。例如 "0x1f" 代表 31。以零开始的数字是八进制的。"017" 代表 15。当心:
不要在十进制数前加零,那样该数字将会被作为八进制数对待!
   ":echo" 命令总以十进制格式打印数字。例:
        :echo 0x7f 036
       127 30
在一个数字前加上减号会将其变为负值。十六进制数和八进制数亦然。减号也用于减法
操作。将下例与前面的比较:
        :echo 0x7f -036
       97
表达式中的空白字符将被忽略。然而,为了增加表达式的易读性,建议在不同项之间使用。
例如,为了不和负号混淆,在减号和之后的数字前加入一个空格:
        :echo 0x7f - 036
--------------------------------------------------------------------------------
*41.2*  变量
一个变量名可以由 ASCII 字符,数字和下划线组成。但是变量名不能以数字开始。
以下是几个有效的变量名:
        counter
        _aap3
        very_long_variable_name_with_dashes
        FuncLength
        LENGTH
"foo+bar" 和 "6var" 都是无效的变量名。
   这些变量都是全局的。要列出当前定义的所有变量可以用这个命令:
        :let
你可以在任何地方使用全局变量。这同时也意味着: 当一个脚本文件使用 "count"变量时,
可能另一个脚本文件也使用了这个变量。这至少会引起混乱,严重时会导致脚本无法正常
工作。为避免这种情况发生,你可以在变量名前加上 "s:" 使其变成脚本文件的本地变量。
例如,一脚本包含以下代码:
        :let s:count = 1
        :while s:count
        \n              , 换行
        \r              ,
        \e              
        \b              , 退格
        \"              "
        \\              \, 反斜杠
        \         
        \          CTRL-W
最后两个只是用来举例子的。"\" 的形式可以被用来表示特殊的键 "name"。
   在 |expr-quote| 中列出了全部的特殊字符。
--------------------------------------------------------------------------------
*41.3*  表达式
Vim 脚本支持的表达式很丰富,也很容易使用。你可以在这里读到表达式的定义:
|expression-syntax|。这里我们只看看常用的几个。
   已经提到的那些数值,字符串常量和变量都属于表达式。因此任何可以使用表达式的
地方,数值,字符串变量和常量都可以使用。其它基本的表达式有:
        $NAME           环境变量
        &name           选项
        @r              寄存器
例子:
        :echo "The value of 'tabstop' is" &ts
        :echo "Your home directory is" $HOME
        :if @a > 5
&name 这种形式可以被用来暂时改变一个选项的值。例:
        :let save_ic = &ic
        :set noic
        :/The Start/,$delete
        :let &ic = save_ic
这样既确保了在匹配 "The Start" 模式时 'ignorecase' 选项
是关闭的,同时也保留了用户原来的选项值。
算 术
我们把这些基本的东西都混合起来用就更有趣了。先来看看算术运算:
        a + b           加
        a - b           减
        a * b           乘
        a / b           除
        a % b           余
先乘除,后加减。例如:
        :echo 10 + 5 * 2
       20
括号内的先计算。这也没什么奇怪的。例如:
        :echo (10 + 5) * 2
       30
用 "." 可以把两个字符串联结起来。例如:
        :echo "foo" . "bar"
       foobar
一般的,当 ":echo" 命令遇到多个参数时,会在它们之间加入空格。但上例中参数是
是一个表达式,所以不会有空格。
下面的条件表达式很显然是从 C 语言里借来的:
        a ? b : c
如果 "a" 为真用 "b",否则用 "c"。例如:
        :let i = 4
        :echo i > 5 ? "i is big" : "i is small"
       i is small
在整个表达式被求值前,结构中的三部分总是先被求值的。因此你可以将其视为:
        (a) ? (b) : (c)
--------------------------------------------------------------------------------
*41.4*  条件语句
":if" 命令在条件满足的前提下,执行其后直到 ":endif" 的所有语句。常用的形式为:
        :if {condition}
           {statements}
        :endif
语句 {statements} 仅当表达式 {condition} 为真(非零)时才被执行。这些语句还必须
是有效的。否则 Vim 无法找到相应的 ":endif".
   你也可以使用 ":else".  常用形式为:
        :if {condition}
           {statements}
        :else
           {statements}
        :endif
第二组 {statements} 仅当条件不满足时被执行。
   最后还有 ":elseif":
        :if {condition}
           {statements}
        :elseif {condition}
           {statements}
        :endif
这种形式就像 ":else" 接着 "if" 一样,但是少出现一个 ":endif".
   下面是一个有用的例子(可以用在你的 vimrc 文件里):它检查 'term' 选项并
根据不同的值做不同的操作:
        :if &term == "xterm"
        :  " Do stuff for xterm
        :elseif &term == "vt100"
        :  " Do stuff for a vt100 terminal
        :else
        :  " Do something for other terminals
        :endif
逻 辑 操 作
实际上我们在前面的几个例子中已经是用到了。下面是几个最常用的形式:
        a == b          等于
        a != b          不等于
        a >  b          大于
        a >= b          大于等于
        a = 600
        :  echo "祝贺"
        :else
        :  echo "你在使用旧的版本,升级!"
        :endif
这里 "v:version" 是 Vim 定义的变量,用来存放 Vim 的版本号。600 意为 6.0 版。
6.1 版的值为 601。这对编写可以在不同版本的 Vim 上运行的脚本很有用。参阅
|v:version|
对数字和字符串都可以做逻辑操作。两个字符串的算术差被用来比较它们的值。差是
通过字节值来计算的,对于某些语言可能无法得到正确的结果。
   在比较一个字符串和一个数字时,该字符串将先被转换成一个数值。这容易出错,
因为当一个字符串看起来不像数字时,它会被当作 0 对待。例如:
        :if 0 == "one"
        :  echo "yes"
        :endif
上面的例子将显示 "yes", 因为 "one" 看起来不像一个数字所以被转换为 0 了。
对于字符串来说还有两种操作:
        a =~ b          匹配
        a !~ b          不匹配
左边的 "a" 被当作一个字符串。右边的 "b" 被当作一个匹配模式,正如做查找操作
一样。例如:
        :if str =~ " "
        :  echo "字符串包括空格"
        :endif
        :if str !~ '\.$'
        :  echo "字符串以句号结尾"
        :endif
注意 在匹配模式中用单引号是很有用的。因为匹配模式中通常有很多反斜杠,而反斜杠
在双引号字符串中必须双写才有效。
在做字符串比较时 'ignorecase' 选项被用到。如果你不希望使用该选项,可以在比较
是加上 "#" 或 "?"。"#" 表示大小写敏感;"?" 表示忽略大小写。因此 "==?" 比较
两字符串是否相等,不计大小写。"!~#" 检查一个模式是否被匹配,同时也考虑大小写。
|expr-==| 有一个完整的字符串比较/匹配操作列表。
循 环 详 述
":while" 命令已经在前面提到了。还有另外两条语句可以在 ":while" 和 ":endwhile":
之间使用。
        :continue               跳回 while 循环的开始; 继续循环
        :break                  跳至 ":endwhile"; 循环结束
例:
        :while counter "
这将在当前行插入 "new text "。注意 这里使用了特殊键 "\"。这样就避免了在
你的脚本当中键入真正的  字符。
--------------------------------------------------------------------------------
*41.6*  使用函数
Vim 定义了大量的函数并通过这些函数提供了丰富的功能。本节将给出一些例子。你可以
在 |functions| 找到一个完整的列表。
一个函数可以被 ":call" 命令调用。参数列表要用括号括起来,并用逗号分割。例如:
        :call search("Date: ", "W")
这将以 "Date: " 和 "W" 为参数调用 search() 函数。search() 函数的第一个参数是
一个查找模式,第二个是一个标志。标志 "W" 表示查找操作遇到文件尾时不折返。
在一个表达式内也可以调用函数。例如:
        :let line = getline(".")
        :let repl = substitute(line, '\a', "*", "g")
        :call setline(".", repl)
getline() 函数从当前文件获取一行文本。其参数是行号。在本例中,"." 表示光标所在行。
   substitute() 函数的功能和 ":substitute" 命令相似。它的第一个参数是要执行替换
操作的原字符串。第二个参数是一个匹配模式,第三个参数是替换字符串。最后一个参数是
一个标志。
   setline() 函数将第一个参数表示的行的文本置为第二个参数表示的字符串。本例中光
标所在的行被 substitute() 函数的结果所替换。因此这三条语句的效果等同于:
        :substitute/\a/*/g
如果你在调用 substitute() 之前或之后有更多的事情要做的话,用就会更有趣了。
*41.7*  定义一个函数
Vim 允许你定义自己的函数。基本的函数声明如下:
        :function {name}({var1}, {var2}, ...)
        :  {body}
        :endfunction
        注意:
        函数名必须以大写字母开始。
让我们来定义一个返回两数中较小者的函数。从下面这一行开始:
        :function Min(num1, num2)
这将告诉 Vim 这个函数名叫 "Min" 并且带两个参数: "num1" 和 "num2"。
   你要做的第一件事就是看看哪个数值小一些:
        :  if a:num1  字符。MS-DOS, Windows, OS/2
机器类似系统使用 。
这对于那些使用  的映射来说很重要。参阅 |:source_crnl|。
空 白 字 符
空行是允许的,但将被忽略。
行首的空白字符 (空格和制表符) 总是被忽略的。参数间的空白字符 (例如象下面命令中
'set' 和 'cpoptions' 之间的空白字符) 仅用作分隔符,会被减少到一个。根据情况的
不同,最后一个 (可见) 的字符后的空白字符可能会被忽略也可能不会,见下。
对于一个带有等号 "=" 的 ":set" 命令,如下:
        :set cpoptions    =aABceFst
紧接着等号之前的空白字符会被忽略。然而其后的空白字符是不允许的!
为了在一个选项值内使用空格,必须像下面例子那样使用反斜杠:
        :set tags=my\ nice\ file
如果写成这样
        :set tags=my nice file
Vim 会给出错误信息,因为它被解释成:
        :set tags=my
        :set nice
        :set file
注 释
双引号字符 " 标记注释的开始。除了那些不考虑注释的命令外(见下例),从双引号起的
直到行末的所有字符都将被忽略。注释可以从一行的任意位置开始。
对于某些命令来说,这里有一个小小的 "陷阱"。例如:
        :abbrev dev development         " shorthand
        :map  o#include             " insert include
        :execute cmd                    " do it
        :!ls *.c                        " list C files
缩写 'dev' 会被展开成 'development     " shorthand'。 的键盘映射会使包括
'" insert include' 在内的那一整行。"execute" 命令会给出错误。"!" 命令会将其后
的所有字符传给 shell,从而引起一个不匹配 '"' 的错误。
   因此,在 ":map", ":abbreviate", ":execute" 和 "!" 命令之后不能有注释。(另外
还有几个命令也是如此)。对于这些命令有一个小窍门:
        :abbrev dev development|" shorthand
        :map  o#include|" insert include
        :execute cmd                    |" do it
'|' 字符被用来将两个命令分隔开。后一个命令仅仅是一个注释。
注意 在 '|' 之前没有空格。这是因为对于这些命令,该行上直到行尾或者 '|' 字符的内
容都是有效的。结果是:你没法总看到这些命令后面包括的空白字符:
        :map  o#include
要避开这个问题,你可以在你的 vimrc 文件内设置 'list' 选项。
陷 阱
下面的例子的问题就更大了:
        :map ,ab o#include
        :unmap ,ab
这里,unmap 命令是行不通的,因为它试着 unmap ",ab "。而这个映射根本就不存在。
因为 'unmap ,ab ' 的末尾的那个空白字符是不可见的,这个错误很难被找出。
在下面这个类似的例子里, 'unmap' 后面带有注释:
        :unmap ,ab     " comment
注释将被忽略。然而,Vim 会尝试 unmap 不存在的 ',ab     '。可以重写成:
        :unmap ,ab|" comment
恢 复 一 个 视 口
有时有你想做一些改动然后回到光标原来的位置。如果能恢复相对位置,把和改动前
同样的行置于窗口顶端就更好了。
   这里的例子拷贝当前行,粘贴到文件的第一行,然后恢复视口:
        map ,p ma"aYHmbgg"aP`bzt`a
解析:
        ma"aYHmbgg"aP`bzt`a
       ma                      在当前位置做标记 a
          "aY                   将当前行拷贝至寄存器 a
             Hmb                移动到窗口的顶行并做标记 b
                gg              移动到文件首行
                  "aP           粘贴拷贝的行到上方
                     `b         移动到刚才的顶行
                       zt       重置窗口中的文本
                         `a     回到标记 a 的地方
封 装
为了避免你的函数名同其它的函数名发生冲突,使用这样的方法:
- 在函数名前加上独特的字符串。我通常使用一个缩写。例如,"OW_" 被用在 option
  window 函数上。
- 将你的函数定义放在一个文件内。设置一个全局变量用来表示这些函数是否已经被加
  载了。当再次 source 这个文件的时候,先将这些函数卸载。
例如:
        " This is the XXX package
        if exists("XXX_loaded")
          delfun XXX_one
          delfun XXX_two
        endif
        function XXX_one(a)
                ... body of function ...
        endfun
        function XXX_two(b)
                ... body of function ...
        endfun
        let XXX_loaded = 1
--------------------------------------------------------------------------------
*41.10* 编写插件                            *write-plugin*
用约定方式编写的脚本能够被除作者外的很多人使用。这样的脚本叫做插件。Vim 用户只
要把你写的脚本放在 plugin 目录下就可以立即使用了: |add-plugin|。
实际上有两种插件:
    全局插件: 适用于所有类型的文件。
文件类型插件: 仅适用于某种类型的文件。
这一节将介绍第一种。很多的东西也同样适用于编写文件类型插件。仅适用于编写文件类型
插件的知识将在下一节 |write-filetype-plugin| 做介绍。
插 件 名
首先你得给你的插件起个名字。这个名字应该很清楚地表示该插件的用途。同时应该避免
同别的插件用同样的名字而用途不同。请将插件名限制在 8 个字符以内,这样可以使得该
插件在老的 Windows 系统也能使用。
一个纠正打字错误的插件可能被命名为 "typecorr.vim"。我们将用这个名字来举例。
为了使一个插件能被所有人使用,要注意一些事项。下面我们将一步步的讲解。最后会给
出这个插件的完整示例。
插 件 体
让我们从做实际工作的插件体开始:
14     iabbrev teh the
15     iabbrev otehr other
16     iabbrev wnat want
17     iabbrev synchronisation
18             \ synchronization
19     let s:count = 4
当然,真正的清单会比这长的多。
上面的行号只是为了方便解释,不要把它们也加入到你的插件文件中去!
插 件 头
你很可能对这个插件做新的修改并很快就有了好几个版本。并且当你发布文件的时候,别
人也想知道是谁编写了这样好的插件或者给作者提点意见。所以,在你的插件头部加上一
些描述性的注释是很必要的:
  1     " Vim global plugin for correcting typing mistakes
  2     " Last Change: 2000 Oct 15
  3     " Maintainer: Bram Moolenaar
关于版权和许可:由于插件很有用,而且几乎不值得限制其发行,请考虑对你的插件使
用公共域 (public domain) 或 Vim 许可 |license|。在文件顶部放置一个 note 就行
了。例如:
  4     " License:      This file is placed in the public domain.
续 行,避 免 副 效 应                                   *use-cpo-save*
在上面的第 18 行中,用到了续行机制 |line-continuation|。那些设置了 'compatible'
选项的用户可能会在这里遇到麻烦。他们会得到一个错误信息。我们不能简单的复位
'compatible' 选项,因为那样会带来很多的副效应。为了避免这些副效应,我们可以将
'cpoptions' 选项设为 Vim 缺省值并在后面恢复之。这将允许续行功能并保证对大多数
用户来讲脚本是可用的。就像下面这样:
11     let s:save_cpo = &cpo
12     set cpo&vim
..
42     let &cpo = s:save_cpo
我们先将 'cpoptions' 的旧值存在 s:save_cpo 变量中。在插件的最后该值将被恢复。
注意 上面使用了脚本本地变量 |s:var|。因为可能有一个全局变量已经在使用了。对于
仅在脚本内用到的变量应该总使用脚本本地变量。
禁 止 加 载
有可能一个用户并不总希望加载这个插件。或者系统管理员在系统的插件目录中已经把
这个插件删除了,而用户希望使用它自己安装的插件。用户应该有机会选择不加载指定
的插件。下面的一段代码就是用来实现这个目的的:
  6     if exists("loaded_typecorr")
  7       finish
  8     endif
  9     let loaded_typecorr = 1
这同时也避免了同一个脚本被加载两次以上。因为那样用户会得到各种各样的错误信息。
比如函数被重新定义,自动命令被多次加入等等。
映 射
现在让我们把这个插件变得更有趣些:我们将加入一个映射用来校正当前光标下的单词。
我们可以任意选一个键组合,但是用户可能已经将其定义为其它的什么功能了。为了使
用户能够自己定义在插件中的键盘映射使用的键,我们可以使用  标识:
22       map  a  TypecorrAdd
那个 "TypecorrAdd" 会做实际的工作,后面我们还会做更多解释。
用户可以将 "mapleader" 变量设为他所希望的开始映射的键组合。比如假设用户这样做:
        let mapleader = "_"
映射将定义为 "_a"。如果用户没有这样做,Vim 将使用缺省值反斜杠。这样就会定义一个
映射 - "\a"。
注意 其中用到了 ,这会使得 Vim 在映射已经存在时给出错误信息。
|:map-|
但是如果用户希望定义自己的键操作呢?我们可以用下面的方法来解决:
21     if !hasmapto('TypecorrAdd')
22       map  a  TypecorrAdd
23     endif
我们先检查对 "TypecorrAdd" 的映射是否存在。仅当不存在时我们才定义映射
"a"。这样用户就可以在他自己的 vimrc 文件中加入:
        map ,c  TypecorrAdd
那么键操作就会是 ",c" 而不是 "_a" 或者 "\a"了。
分 割
如果一个脚本变得相当长,你通常希望将其分割成几部分。你可以在其中使用函数或映射。
但同时又不希望它们在脚本之间相互干扰。例如,你定义了一个函数 Add(),但另一个脚本
也试图定一同名的函数。为了避免这样的情况发生,我们可以在本地函数的前面加上 "s:"。
我们来定义一个用来添加新的错误更正的函数:
30     function s:Add(from, correct)
31       let to = input("type the correction for " . a:from . ": ")
32       exe ":iabbrev " . a:from . " " . to
..
36     endfunction
这样我们就可以在这个脚本之内调用函数 s:Add()。如果另一个脚本也定义 s:Add(),该
函数将只能在其所定义的脚本内部被调用。还可能会存在独立于这两个函数的全局的
Add() 函数 (不带 "s:")。
可以和映射一起使用,用来产生一个脚本的标识。在我们的错误更正插件中我们可
以做以下的定义:
24     noremap   TypecorrAdd  Add
..
28     noremap Add  :call Add(expand(""), 1)
这样当用户键入 "\a" 时,将触发下面的次序:
        \a  ->  TypecorrAdd  ->  Add  ->  :call Add()
如果另一个脚本也定义了映射 Add,该脚本将产生另一个脚本标示。所以它定义的映
射也与前面定义的不同。
注意 在这里我们用了 Add() 而不是 s:Add()。这是因为该映射将被用户键入,
因此是从脚本外部调用的。 被翻译成该脚本的标识。这样 Vim 就知道在那个脚本里
寻找相应的 Add() 函数了。
这的确是有点复杂,但又是使多个插件一起工作所必需的。基本规则是:在映射中使用
Add();在其它地方 (该脚本内部,自动命令,用户命令) 使用 s:Add()。
我们还可以用同一个映射来添加一个菜单选项:
26     noremenu  Plugin.Add\ Correction      Add
建议把插件定义的菜单项都加入到 "Plugin" 菜单下。上面的情况只定义了一个菜单选项。
当有多个选项时,可以创建一个子菜单。例如,一个提供 CVS 操作的插件 可以添加
"Plugin.CVS" 子菜单,并在其中定义 "Plugin.CVS.checkin", "Plugin.CVS.checkout"
等菜单项。
注意 为了避免其它映射引起麻烦,在第 28 行使用了 ":noremap"。比如有人可能
重新映射了 ":call"。在第 24 也用到了 ":noremap",但我们又希望重新映射
"Add"。这就是为什么在这儿要用 ""。这只允许定义脚本本地的映射。
|:map-| 同样的道理在第 25 行也用了 ":noremenu"。|:menu-|
和                                                 *using-*
和  都是用来避免映射的键序列和那些仅仅用于其它映射的映射起冲突。
注意  和  的区别:
  在脚本外部是可见的。它被用来定义那些用户可能定义映射的映射。 是一个
        键盘输入之外的特殊代码。
        使用结构: 脚本名 映射名,可以使得其它插件使用同样次序的字符来定义映
        射的几率变得非常小。在我们上面的例子中,脚本名是 "Typecorr",映射名是 "Add"。
        结果是 "TypecorrAdd"。 只有脚本名和映射名的第一个字符是大写的,所以我
        们可以清楚地看到映射名从什么地方开始。
   是脚本的标识,用来唯一的代表一个脚本。Vim 在内部将  翻译为
        "123_",其中 "123" 可以是任何数字。这样一个函数 "Add()" 可能
        在一个脚本中被命名为 "11_Add()",而在另一个脚本中被命名为
        "22_Add()"。如果你用 ":function" 命令来获得系统中的函数列表你就可
        以看到了。映射中对  的翻译是完全一样的。这样你才有可能通过一个映射
        来调用某个脚本中的本地函数。
用 户 命 令
现在让我们来定义一个用来添加更正的用户命令:
38     if !exists(":Correct")
39       command -nargs=1  Correct  :call s:Add(, 0)
40     endif
这个用户命令只在系统中没有同样名称的命令时才被定义。否则我们会得到一个错误。用
":command!" 来覆盖现存的用户命令是个坏主意。这很可能使用户不明白自己定义的命令
为什么不起作用。|:command|
脚 本 变 量
当一个变量前面带有 "s:" 时,我们将它称为脚本变量。该变量只能在脚本内部被使用。
在脚本以外该变量是不可见的。这样就避免了在不同的脚本中使用同一个变量名的麻烦。
该变量在 Vim 的运行期间都是可用的。当再次调用 (source) 该脚本时使用的是同一个
变量。|s:var|
有趣的是这些变量也可以在脚本定义的函数、自动命令和用户命令中使用。在我们的例子
中我们可以加入几行用来统计更正的个数:
19     let s:count = 4
..
30     function s:Add(from, correct)
..
34       let s:count = s:count + 1
35       echo s:count . " corrections now"
36     endfunction
起初 s:count 被脚本初始化为 4。当后来 s:Add() 函数被调用时,其值被增加了。在哪
里调用函数无关紧要。只要它是定义在该脚本以内的,就可以使用脚本中的本地变量。
结 果
下面就是完整的例子:
  1     " Vim global plugin for correcting typing mistakes
  2     " Last Change: 2000 Oct 15
  3     " Maintainer: Bram Moolenaar
  4     " License:      This file is placed in the public domain.
  5
  6     if exists("loaded_typecorr")
  7       finish
  8     endif
  9     let loaded_typecorr = 1
10
11     let s:save_cpo = &cpo
12     set cpo&vim
13
14     iabbrev teh the
15     iabbrev otehr other
16     iabbrev wnat want
17     iabbrev synchronisation
18             \ synchronization
19     let s:count = 4
20
21     if !hasmapto('TypecorrAdd')
22       map  a  TypecorrAdd
23     endif
24     noremap   TypecorrAdd  Add
25
26     noremenu  Plugin.Add\ Correction      Add
27
28     noremap Add  :call Add(expand(""), 1)
29
30     function s:Add(from, correct)
31       let to = input("type the correction for " . a:from . ": ")
32       exe ":iabbrev " . a:from . " " . to
33       if a:correct | exe "normal viws\\" \b\e" | endif
34       let s:count = s:count + 1
35       echo s:count . " corrections now"
36     endfunction
37
38     if !exists(":Correct")
39       command -nargs=1  Correct  :call s:Add(, 0)
40     endif
41
42     let &cpo = s:save_cpo
第 32 行还没有解释过。它将新定义的更正用在当前光标下的单词上。|:normal| 被用来
使用新的缩写。 注意 虽然这个函数是被一个以 ":noremap" 定义的映射调用的,这
里的映射和缩写还是被展开使用了。
推荐对 'fileformat' 选项使用 "unix" 值。这样的 Vim 脚本就可以在所有系统内使用。
对 'fileformat' 选项使用 "dos" 的脚本无法正常的在 Unix 上使用。参见
|:source_crnl|。为确保该值被城正确设置,在写入文件前执行下面的命令:
        :set fileformat=unix
文 档                                          *write-local-help*
给你的插件写一些文档是个好主意。特别是当用户可以自己定义其中的某些功能时。
关于如何安装文档,请查阅 |add-local-help|。
下面是一个插件帮助文档的简单例子,名叫 "typecorr.txt":
  1     *typecorr.txt*  Plugin for correcting typing mistakes
  2
  3     If you make typing mistakes, this plugin will have them corrected
  4     automatically.
  5
  6     There are currently only a few corrections.  Add your own if you like.
  7
  8     Mappings:
  9     a   or   TypecorrAdd
10             Add a correction for the word under the cursor.
11
12     Commands:
13     :Correct {word}
14             Add a correction for {word}.
15
16                                                     *typecorr-settings*
17     This plugin doesn't have any settings.
其实只有第一行是文档的格式所必需的。Vim 将从该帮助文件中提取该行并加入到
help.txt 的 "LOCAL ADDITIONS:" |local-additions| (本地附加文档) 一节中。
第一个 "*" 一定要在第一行的第一列。加入你的帮助文件之后用 ":help" 来检查
一下各项是否很好的对齐了。
你可以为你的帮助文档在 ** 之间加入更多的标签。但注意不要使用现存的帮助标签。
你最好能在标签内使用插件名用以区别,比如上例中的 "typecorr-settings"。
建议使用 || 来引用帮助系统中的其它部分。这可以使用户很容易得找到相关联的帮助。
小 结                                                 *plugin-special*
关于插件的小结:
s:name                  脚本的本地变量。
                   脚本标识,用于脚本本地的映射和函数。
hasmapto()              用来检测插件定义的映射是否已经存在的函数。
                "mapleader" 的值。用户可以通过该变量定义插件所定义
                        映射的起始字符。
:map            如果一个映射已经存在的话,给出警告信息。
:noremap        仅使用脚本的本地映射,而不使用全局的。
exists(":Cmd")          检查一个用户命令是否存在。
--------------------------------------------------------------------------------
*41.11* 编写文件类型插件        *write-filetype-plugin* *ftplugin*
文件类型插件和全局插件其实很相似。但是它的选项设置和映射等仅对当前缓冲有效。这
类插件的用法请参阅 |add-filetype-plugin|。
请先阅读上面 |41.10| 关于全局插件的叙述。其中所讲得对文件类型插件也都适用。这里
只讲述一些不同之处。最更本的区别是文件类型插件只应该对当前缓冲生效。
禁 用
如果你在编写一个提供很多人使用的文件类型插件,这些用户应该有机会选择不加载该插件。
你应该在插件的顶端加上:
        " Only do this when not done yet for this buffer
        if exists("b:did_ftplugin")
          finish
        endif
        let b:did_ftplugin = 1
这同时也避免了同一插件在同一缓冲内被多次执行的错误 (当使用不带参数的 ":edit"
命令时就会发生)。
现在用户只要编写一个如下的一行的文件类型插件就可以完全避免加载缺省的文件类型插
件了:
        let b:did_ftplugin = 1
当然这要求该文件类型插件所处的文件类型插件目录在 'runtimepath' 所处的位置在
$VIMRUNTIME 之前!
如果你的确希望使用缺省的插件,但是又想自行支配其中的某一选项,你可以用一个类似
下例的插件:
        set textwidth=70
现在将这个文件存入那个 "after" 目录中。这样它就会在调用 Vim 本身的 "vim.vim"
文件类型插件之后被调用 |after-directory|。对于 Unix 系统而言,该目录会是
"~/.vim/after/ftplugin/vim.vim"。注意 缺省的文件类型插件已经设置了
"b:did_ftplugin", 但在这里被忽略了。
选 项
为了确保文件类型插件仅仅影响当前缓冲,应该使用
        :setlocal
命令来设置选项。还要注意只设定缓冲的本地选项 (查查有关选项的帮助)。当
|:setlocal| 被用于设置全局选项或者某窗口的本地选项时,会影响到多个缓冲,这是
文件类型插件应该避免的。
当一个选项的值是多个项目的 "合" 时,考虑使用 "+=" 和 "-=",这样可以保留现有
的值。注意 用户可能已经改变了该选项的值了。通常先将选项的值复位成缺省值再做
改动是个好主意。例:
        :setlocal formatoptions& formatoptions+=ro
映 射
为了确保键盘映射只对当前缓冲生效,应该使用
        :map
命令。这还应该和上面讲述的两步映射法连起来使用。下面是一个例子:
        if !hasmapto('JavaImport')
          map   i JavaImport
        endif
        noremap   JavaImport oimport ""
|hasmapto()| 被用来检查用户是否已经定义了一个对 JavaImport 的映射。如果
没有,该文件类型插件就定义缺省的映射。因为缺省映射是以 || 开始,
就使得用户可以自己定义映射的起始字符。缺省的是反斜杠。 "" 的用途是当
已经存在的了这样的映射或者和已经存在的映射有重叠的时候给出错误信息。
|:noremap| 被用来防止其他用户定义的映射干扰。你可能会希望使用
":noremap " 来允许以  开头的脚本重新定义映射。
一定要给用户保留禁止一个文件类型插件内的映射而不影响其它功能的能力。下面通过
一个邮件文件类型插件来演示如何做到这一点:
        " Add mappings, unless the user didn't want this.
        if !exists("no_plugin_maps") && !exists("no_mail_maps")
          " Quote text by inserting "> "
          if !hasmapto('MailQuote')
            vmap  q MailQuote
            nmap  q MailQuote
          endif
          vnoremap  MailQuote :s/^/> /
          nnoremap  MailQuote :.,$s/^/> /
        endif
其中用到了两个全局变量:
no_plugin_maps          禁止所有文件类型插件中的映射
no_mail_maps            禁止某一特定的文件类型插件的映射
用 户 名 令
在使用 |:command| 命令时,如果加上 "-buffer" 开关,就可以为某一类型的文件加入
一个用户命令,而该命令又只能用于一个缓冲。例:
        :command -buffer  Make  make %:r.s
变 量
文件类型插件对每一个该类型的文件都会被调用。脚本本地变量 |s:var| 会被所有的调
用共享。如果你想定义一个仅对某个缓冲生效的变量,使用缓冲本地变量 |b:var|。
函 数
一个函数只需要定义一次就行了。可是文件类型插件会在每次打开相应类型的文件时都被
调用。下面的结构可以确保函数只被定义一次:
        :if !exists("*s:Func")
        :  function s:Func(arg)
        :    ...
        :  endfunction
        :endif
撤 消
当用户执行 ":setfiletype xyz" 时,之前的文件类型命令应该被撤消。在你的文件类
型插件中设定 b:undo_ftplugin 变量为撤消各种设置的命令。例如:
        let b:undo_ftplugin = "setlocal fo           "maplocalleader" 的值,用户可以通过它来自定
                        义文件类型插件中映射的起始字符
:map            定义一个仅对缓冲有效的本地映射。
:noremap        仅重定义脚本中以  开始的映射。
:setlocal               仅对当前缓冲设定选项。
:command -buffer        定义一个仅对缓冲有效的本地命令。
exists("*s:Func")       查看是否已经定义了某个函数。
参阅所有插件的特殊环节 |plugin-special|。
--------------------------------------------------------------------------------
*41.12* 编写编译器插件                           *write-compiler-plugin*
编译器插件可以用来设定于某一特定编译器相关的选项。用户可以使用 |:compiler|
命令来加载之。主要是用以设定 'errorformat' 及 'makeprg' 选项。
最简单的方法就是学习一个例子。下面的命令将编辑所有缺省安装的编译器插件:
        :next $VIMRUNTIME/compiler/*.vim
用 |:next| 可以查阅下一个插件文件。
这类文件有两个特别之处。一是允许用户否决或者增强缺省文件的机制。缺省的文件以
下面的代码开始:
        :if exists("current_compiler")
        :  finish
        :endif
        :let current_compiler = "mine"
第二个特别之处是:用 ":set" 命令来配合 ":compiler!" 而用 ":setlocal" 来配合
":compiler"。Vim 为此定义了 ":CompilerSet" 用户命令。然而旧版本的 Vim 没有,
因此你的插件应该提供该命令。下面是一个例子:
  if exists(":CompilerSet") != 2
    command -nargs=* CompilerSet setlocal
  endif
  CompilerSet errorformat&              " use the default 'errorformat'
  CompilerSet makeprg=nmake
当你编写一个编译器文件并将其放置在个人运行时目录 (例如, Unix 下的
~/.vim/compiler) 时,你可以给 "current_compiler" 赋值,使得缺省文件不执行
其设定。
当你为 Vim 发行或者整个系统编写编译器插件时,应该使用上面提到的机制。这样
当用户插件已经定义了 "current_compiler" 的时候什么也不做。
当你为了自行定义缺省插件的一些设定而编写编译器插件时,不要检查
"current_compiler"。这个插件应该在最后加载,因此其所在目录应该在 'runtimepath'
的最后。对于 Unix 来说可能是 ~/.vim/after/compiler。
=============================================
3.1.1.  变量
Vim 中使用如下的语法对变量进行赋值(创建变量):
let 变量名 = 数值
变量类型有两种,整数和字符串,在第一次赋值之前都不能使用。变量名除了可使用常规的字母、下划线和数字外,还可以使用几种特殊的前缀:
  • “b:”——只对当前缓冲区(buffer)有效的变量;
  • “w:”——只对当前编辑窗口(window)有效的变量。
  • “g:”——全局变量(在函数中访问全局变量必须使用该前缀,不加前缀的话则认为是函数内的局部变量);
  • “s:”——变量名只在当前脚本中有效;
  • “a:”——函数的参数;
  • “v:”——Vim 内部预定义的特殊变量(参见“:help vim-variable”)。

下面三个前缀用来访问特殊的数值,由于行为和变量较为相似(可以读取和修改),也放在这儿一起讲:
  • “$”——访问环境变量;
  • “&”——访问 Vim 选项;
  • “@”——访问寄存器。

当变量不再使用时,可以使用“unlet 变量名”删除变量。
3.1.2. 表达式

C
非常类似,可以使用变量和常量,可以使用括号,可以调用函数(“函数名(...)”),支持加法(“+”)、减法(“-”)、乘法(“*”)、除法
(“/”)和取模(“%”),支持逻辑操作(“&&”、“||”和“!”),支持三元条件表达式(“a ? b :
c”)。字符串操作方面当然比 C
要强,可以使用“.”进行字符串拼接;可使用“==”、“3.1.3. 条件和循环语句
条件语句形式如下:
if 表达式
  语句
endif

if 表达式
  语句
else
  语句
endif

if 表达式
  语句
elseif 表达式
  语句
endif
循环语句形式如下:
while 表达式
  语句
endwhile
条件和循环语句都可以嵌套。这些比较简单,就不多加说明了。
3.1.4. 函数
在表达式中使用函数时,就跟 C 里面的方式类似,直接使用函数名加括号,括号里写上参数(可选)。在不需要返回值的情况下调用函数时,稍稍有些不同,要使用“call”命令,后面跟函数名和括号(括号里面写上可能有的参数)。
定义函数使用下面的语法:
function 函数名称(参数列表)
  语句
endfunction
如果已有同名函数存在,Vim 会报错,除非在“function”后面加上一个“!”。

果参数中不包含“...”,那么参数的数量是固定的,函数的调用者必须提供跟定义同样多的参数(在函数定义中使用参数名之前加上“a:”进行访问)。如果
参数中包含“...”,那么参数的数量不固定,除了可以使用参数名称访问传递过来的参数外,还可以使用“a:0”知道额外传递的参数数量,使用“a:
1”、“a:2”等访问这些额外传递的参数。
要在函数的中间返回,或者要返回数值的话,可以使用“return”语句。
Vim 内部定义了一百多个函数,详细列表请参见“:help function-list”。
               
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/13329/showart_69712.html

论坛徽章:
0
2 [报告]
发表于 2013-08-09 18:16 |只看该作者
尼玛,被坑死
  :if str =~ " "
        :  echo "字符串包括空格"
        :endif
        :if str !~ '\.$'
        :  echo "字符串以句号结尾"
        :endif
这个句号结尾正常???
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP