EVAL

*eval.txt*      For Vim version 7.1.  最近更新: 2007年5月


                  VIM 参考手册    by Bram Moolenaar
                                译者: Willis
                                http://vimcdoc.sf.net


表达式求值                              *expression* *expr* *E15* *eval*

用户手册第 41 章 |usr_41.txt| 有使用表达式的介绍。

注意: 表达式求值可以在编译时关闭。如果你这么做,本文档介绍的特性就不复存在。见
|+eval| 和 |no-eval-feature|。

1.  变量                |variables|
    1.1 变量类型
    1.2 函数引用                |Funcref|
    1.3 列表                    |Lists|
    1.4 字典                    |Dictionaries|
    1.5 变量的更多细节          |more-variables|
2.  表达式语法          |expression-syntax|
3.  内部变量            |internal-variables|
4.  内建函数            |functions|
5.  定义函数            |user-functions|
6.  花括号名字          |curly-braces-names|
7.  命令                |expression-commands|
8.  例外处理            |exception-handling|
9.  示例                |eval-examples|
10. 不包含 +eval 特性   |no-eval-feature|
11. 沙盘 (sandbox)      |eval-sandbox|
12. 文本锁              |textlock|

{Vi 无此功能}


1. 变量 *variables*

1.1 变量类型 *E712* 有五种类型的变量: 数值 32 位带符号整数。 示例: -123 0x10 0177 字符串 NUL 结尾的 8 位无符号字符 (即字节) 的串。 示例: "ab\txx\"--" 'x-z''a,c' 函数引用 指向一个函数的引用 |Funcref|。 示例: function("strlen") 列表 项目的有序的序列 |List|。 示例: [1, 2, ['a', 'b']] 字典 关联的无序数组: 每个项目包含一个键和一个值。|Dictionary| 示例: {'blue': "#0000ff", 'red': "#ff0000"} 数值和字符串类型之间会根据使用的情况自动转换。 数值到字符串的转换使用数值的 ASCII 表示。例如: 数值 123 --> 字符串 "123" 数值 0 --> 字符串 "0" 数值 -1 --> 字符串 "-1" 字符串到数值的转换则把字符串开头的一系列数字位转换成数值。十六进制 "0xf9" 和八 进制 "017" 形式的数值可以识别。如果字符串不以数字开始,则结果为零。例如: 字符串 "456" --> 数值 456 字符串 "6bar" --> 数值 6 字符串 "foo" --> 数值 0 字符串 "0xf1" --> 数值 241 字符串 "0100" --> 数值 64 字符串 "-8" --> 数值 -8 字符串 "+8" --> 数值 0 要强制从字符串转换到数值,给它加零: :echo "0100" + 0 64 要避免开头的零导致八进制的转换,或者想换不同的基底,用 |str2nr()|。 布尔型的操作使用数值类型。零代表假值 (FALSE),非零代表真值 (TRUE)。 注意 在命令 :if "foo" 里,"foo" 被转换成 0,也就是假值。要测试字符串非空,应该使用 strlen(): :if strlen("foo") *E745* *E728* *E703* *E729* *E730* *E731* 列表、字典和函数引用类型不会自动进行转换。 *E706* 如果你试图改变变量类型,你会得到错误。先 |:unlet| 可以避免此错误。不过,字符串 和数值被认为是等价的类型。考虑如下的命令序列: :let l = "string" :let l = 44 " 类型从字符串改为数值 :let l = [1, 2, 3] " 出错! 1.2 函数引用 *Funcref* *E695* *E718* 函数引用变量可以通过 |function()| 函数得到。可以在表达式里用它来代替函数名,在 围绕参数的括号之前,以调用它引用的函数。例如: :let Fn = function("MyFunc") :echo Fn() *E704* *E705* *E707* 函数引用变量必须以大写字母、"s:"、"w:"、"t:" 或 "b:" 开始。函数引用变量不能和 任何函数重名。 特例是可以定义函数并直接把它的函数引用赋给字典的一个项目。例如: :function dict.init() dict : let self.val = 0 :endfunction 该字典的键可以用小写字母开始。这里不用实际的函数名。另见 |numbered-function|。 函数引用可以用 |:call| 命令调用: :call Fn() :call dict.init() 所引用的函数的名字可以用 |string()| 得到, :let func = string(Fn) 你可以用 |call()| 来调用函数引用并用一个列表变量来传递参数: :let r = call(Fn, mylist) 1.3 列表 *List* *Lists* *E686* 列表是项目的有序序列。项目可以是任何类型,用索引号可以进行访问。可以在序列的任 何位置上增加或者删除项目。 列表建立 *E696* *E697* 列表用方括号里逗号分隔的项目序列建立。例如: :let mylist = [1, two, 3, "four"] :let emptylist = [] 项目可以是任何表达式。用列表作为项目就能建立列表的列表: :let nestlist = [[11, 12], [21, 22], [31, 32]] 忽略末项之后额外的逗号。 列表索引 *list-index* *E684* 在列表之后的方括号中放上索引号可以访问列表项目。索引从零开始,也就是说,第一个 项目的索引值为零。 :let item = mylist[0] " 得到第一个项目: 1 :let item = mylist[2] " 得到第三个项目: 3 如果返回的项目本身是列表,可以重复这样的操作: :let item = nestlist[0][1] " 得到第一个列表的第二个项目: 12 负索引从尾端开始计算。索引 -1 指向列表的最后一个项目,-2 指向倒数第二个项目, 依此类推。 :let last = mylist[-1] " 得到最后一个项目: "four" 要避免非法索引值产生的错误,用 |get()| 函数。如果项目不存在,它返回零或者你指 定的缺省值: :echo get(mylist, idx) :echo get(mylist, idx, "NONE") 列表连接 两个列表可以用 "+" 操作符连接: :let longlist = mylist + [5, 6] :let mylist += [7, 8] 要在前面或后面附加项目,在项目外面加上 [] 从而把它变为一个列表。要改变列表内部 的值,见下 |list-modification|。 子列表 列表的一部分可以通过指定首末两个索引获得,方括号内以冒号分隔两者: :let shortlist = mylist[2:-1] " 得到列表 [3, "four"] 首索引的省略类似于用 0。末索引的省略类似于用 -1。 :let endlist = mylist[2:] " 从项目 2 到结束: [3, "four"] :let shortlist = mylist[2:2] " 单个项目的列表: [3] :let otherlist = mylist[:] " 复制列表 如果首索引在列表末项之后或者末索引小于首索引,返回空列表。没有错误信息。 如果末索引大于等于列表的长度,使用列表长度减一: :let mylist = [0, 1, 2, 3] :echo mylist[2:8] " 返回: [2, 3] 注意: mylist[s:e] 意味着用变量 "s:e" 作为索引。在 ":" 之前用单个字母作为变量要 小心。需要的话加上空格: mylist[s : e]。 列表同一 *list-identity* 如果变量 "aa" 是列表,把它赋给另一个变量 "bb" 后,两个变量指向同一列表。因此, 对列表 "aa" 的修改也同时修改了 "bb": :let aa = [1, 2, 3] :let bb = aa :call add(aa, 4) :echo bb [1, 2, 3, 4] |copy()| 函数可以复制列表。如上所述,用 [:] 也可。这种方式建立列表的浅备份: 改 变列表中的列表项目仍然会修改复制列表的相应项目: :let aa = [[1, 'a'], 2, 3] :let bb = copy(aa) :call add(aa, 4) :let aa[0][1] = 'aaa' :echo aa [[1, aaa], 2, 3, 4] :echo bb [[1, aaa], 2, 3] 要建立一个完全独立的列表,用 |deepcopy()|。它递归地建立列表值的备份。最深可达 100 层。 可用操作符 "is" 检查两个变量是否指向同一个列表。"isnot" 刚好相反。与此对照, "==" 比较两个列表的值是否相同。 :let alist = [1, 2, 3] :let blist = [1, 2, 3] :echo alist is blist 0 :echo alist == blist 1 比较列表时 注意: 如果长度相同,所有项目用 "==" 的比较的结果也相同,两个列表就 认为相同。有一个例外: 数值和字符串总被认为不相同。这里不进行自动类型转换,而在 变量间直接用 "==" 却不是如此。例如: echo 4 == "4" 1 echo [4] == ["4"] 0 因此可以说,列表的比较比数值和字符串的比较更严格。你同样可以用这种方式比较简单 类型的值,把它们放到字符串 (译者注: 方括号?) 里就行了: :let a = 5 :let b = "5" echo a == b 1 echo [a] == [b] 0 列表解包 要给列表项目解包,即把它们分别存入单独的变量,用方括号把变量括起来,如同把它们 当作列表项目: :let [var1, var2] = mylist 如果变量和列表的项目数量不同,报错。要处理列表中所有额外的项目,加上 ";" 和单 个变量: :let [var1, var2; rest] = mylist 它的工作方式就像: :let var1 = mylist[0] :let var2 = mylist[1] :let rest = mylist[2:] 如果只有两个项目,不会报错。这时 "rest" 成为空表。 列表修改 *list-modification* 要修改列表的指定项目,用 |:let|: :let list[4] = "four" :let listlist[0][3] = item 要修改列表的一部分,可以指定要修改的首末项目。提供的值的个数必须不少于该范围内 的项目数: :let list[3:5] = [3, 4, 5] 给列表增加和删除项目可以通过函数完成。一些例子如下: :call insert(list, 'a') " 在最前面插入 'a' :call insert(list, 'a', 3) " 在 list[3] 前插入项目 'a' :call add(list, "new") " 在最后附加字符串项目 :call add(list, [1, 2]) " 在最后附加新的列表项目 :call extend(list, [1, 2]) " 在最后扩展列表,使之多包含两个项目 :let i = remove(list, 3) " 删除项目 3 :unlet list[3] " 同上 :let l = remove(list, 3, -1) " 从项目 3 删除到最后 :unlet list[3 : ] " 同上 :call filter(list, 'v:val !~ "x"') " 删除有 'x' 的项目 改变列表项目的顺序: :call sort(list) " 按字母给列表排序 :call reverse(list) " 反转项目的顺序 For 循环 |:for| 循环为每个列表项目执行命令。一个变量被依次设为每个列表项目。例如: :for item in mylist : call Doit(item) :endfor 它的工作方式就像: :let index = 0 :while index < len(mylist) : let item = mylist[index] : :call Doit(item) : let index = index + 1 :endwhile 注意 所有列表项目必须是相同类型,不然会报错 |E706|。要避免这一点,在循环尾部 |:unlet| 该变量。 如果你只是想要修改每个列表项目,|map()| 函数比 for 循环简单得多。 就像 |:let| 命令,|:for| 也可以接受变量的列表。这需要参数是列表的列表。 :for [lnum, col] in [[1, 3], [2, 8], [3, 0]] : call Doit(lnum, col) :endfor 这就像对列表的每个项目使用了 |:let| 命令。重复一次,类型必须相同,否则会报错。 也可以用变量保存列表变量的其余项目: :for [i, j; rest] in listlist : call Doit(i, j) : if !empty(rest) : echo "remainder: " . string(rest) : endif :endfor 列表的相关函数 *E714* 可用于列表的函数: :let r = call(funcname, list) " 调用带参数列表的函数 :if empty(list) " 检查 list 是否为空 :let l = len(list) " list 项目的数量 :let big = max(list) " list 项目的最大值 :let small = min(list) " list 项目的最小值 :let xs = count(list, 'x') " 计算 list 里 'x' 出现的次数 :let i = index(list, 'x') " list 第一个 'x' 的位置 :let lines = getline(1, 10) " 得到缓冲区十行文本行 :call append('$', lines) " 附加若干文本行到缓冲区尾部 :let list = split("a b c") " 用字符串中的项目建立列表 :let string = join(list, ', ') " 用 list 项目构造字符串 :let s = string(list) " list 的字符串表示 :call map(list, '">> " . v:val') " 在每个项目前加上 ">> " 不要忘记组合使用不同功能可以简化任务。例如,要计算列表中所有数值的总和: :exe 'let sum = ' . join(nrlist, '+') 1.4 字典 *Dictionaries* *Dictionary* 字典是关联数组: 每个项目有一个键和一个值。用键可以定位项目,而项目的存储不能确 定任何特定顺序。 字典建立 *E720* *E721* *E722* *E723* 字典通过花括号里逗号分隔的项目列表建立。每个项目包含以冒号分隔的键和值。一个键 只能出现一次。例如: :let mydict = {1: 'one', 2: 'two', 3: 'three'} :let emptydict = {} *E713* *E716* *E717* 键必须是字符串。用数值也可以,但它总被自动转换为字符串。所以字符串 '4' 和数值 4 总会找到相同的项目。注意 字符串 '04' 和数值 04 是不一样的,因为后者被转换成 字符串 '4'。 值可以是任何表达式。如果值本身是字典,就可以建立嵌套的字典: :let nestdict = {1: {11: 'a', 12: 'b'}, 2: {21: 'c'}} 忽略末项之后的逗号。 访问项目 常见的访问项目的方式是把键放入方括号: :let val = mydict["one"] :let mydict["four"] = 4 用这种方式可以给已存在的字典增加新项目,这和列表不同。 如果键只包含字母、数字和下划线,可以使用如下形式 |expr-entry|: :let val = mydict.one :let mydict.four = 4 因为项目可以是包括列表和字典的任何类型,你可以反复使用索引和键进行访问: :echo dict.key[idx].key 字典到列表的转换 你可以循环遍历字典的所有项目。为此,你需要把字典转为列表,然后把它传递给 |:for|。 通常,你期望遍历所有的键,用 |keys()| 函数就可以了: :for key in keys(mydict) : echo key . ': ' . mydict[key] :endfor 键列表没有经过排序。你可能希望先进行排序: :for key in sort(keys(mydict)) 要遍历所有的值,用 |values()| 函数: :for v in values(mydict) : echo "value: " . v :endfor 如果你想同时得到键和值,用 |items()| 函数。它返回一个列表,其中每个项目是两个 项目的列表: 键和值: :for [key, value] in items(mydict) : echo key . ': ' . value :endfor 字典同一 *dict-identity* 就像列表那样,你需要用 |copy()| 和 |deepcopy()| 来构造字典的备份。否则,赋值产 生的结果会引用同一个字典: :let onedict = {'a': 1, 'b': 2} :let adict = onedict :let adict['a'] = 11 :echo onedict['a'] 11 如果所有的键-值组对的比较结果相同,两个字典比较的结果也相同。详情见 |list-identity|。 字典修改 *dict-modification* 要修改字典已经存在的项目或者增加新的项目,用 |:let|: :let dict[4] = "four" :let dict['one'] = item 从字典里删除项目可以通过 |remove()| 或 |:unlet| 完成。 从 dict 里删除键 "aaa" 的项目有三种方法: :let i = remove(dict, 'aaa') :unlet dict.aaa :unlet dict['aaa'] 两个字典的合并可以用 |extend()|: :call extend(adict, bdict) 这使得 adict 得到扩展,加入所有的 bdict 项目。对于重复的键,adict 项目被覆盖。 可选的第三个参数可以改变这一点。 注意 这不影响字典项目的顺序,不要希望 ":echo adict" 会先显示原有 adict 项目, 然后再显示 bdict 的项目。 从字典里删除多个项目可以用 |filter()| 完成: :call filter(dict, 'v:val =~ "x"') 删除 "dict" 里所有值不匹配 "x" 的项目。 字典函数 *Dictionary-function* *self* *E725* 定义函数时,如果带有 "dict" 属性,可以以一种特殊方式使用字典。例如: :function Mylen() dict : return len(self.data) :endfunction :let mydict = {'data': [0, 1, 2, 3], 'len': function("Mylen")} :echo mydict.len() 这类似于面向对象编程的方法。字典项目用作 |Funcref|。局部变量 "self" 引用函数所 在的字典。 字典里也可以加入指向没有 "dict" 属性的函数的函数引用,不过这时无法使用 "self" 变量。 *numbered-function* *anonymous-function* 要避免额外的函数名,可以定义时直接赋给字典: :let mydict = {'data': [0, 1, 2, 3]} :function mydict.len() dict : return len(self.data) :endfunction :echo mydict.len() 该函数会得到一个编号,而 dict.len 的值是指向此函数的 |Funcref|。该函数只能通过 |Funcref| 访问。如果没有任何 |Funcref| 引用,它会被自动删除。 编号函数不一定要有 "dict" 属性。 字典相关函数 *E715* 可以用于字典的函数: :if has_key(dict, 'foo') " 如果 dict 有带 "foo" 键的项目则为真 :if empty(dict) " 如果 dict 为空则为真 :let l = len(dict) " dict 项目的数量 :let big = max(dict) " dict 项目的最大值 :let small = min(dict) " dict 项目的最小值 :let xs = count(dict, 'x') " 统计 dict 里 'x' 出现的数目 :let s = string(dict) " dict 的字符串表示 :call map(dict, '">> " . v:val') " 在每个项目前加上 ">> " 1.5 变量的更多细节 *more-variables* 如果你需要知道变量或表达式的类型,使用 |type()| 函数。 如果 'viminfo' 选项包含 '!' 标志位,大写开头且不包含小写字母的全局变量被保存在 viminfo 文件里 |viminfo-file|。 如果 'sessionoptions' 选项包含 "global",大写开头且包含至少一个小写字母的全局 变量被保存在会话文件里 |session-file|。 变量名 可以保存的位置 my_var_6 无 My_Var_6 会话文件 MY_VAR_6 viminfo 文件 可以使用花括号来构造变量名,见 |curly-braces-names|。

2. 表达式语法 *expression-syntax*

表达式语法小结,优先级从低到高排列: |expr1| expr2 ? expr1 : expr1 if-then-else |expr2| expr3 || expr3 .. 逻辑或 |expr3| expr4 && expr4 .. 逻辑与 |expr4| expr5 == expr5 等于 expr5 != expr5 不等于 expr5 > expr5 大于 expr5 >= expr5 大于等于 expr5 < expr5 小于 expr5 <= expr5 小于等于 expr5 =~ expr5 匹配正规表达式 expr5 !~ expr5 不匹配正规表达式 expr5 ==? expr5 等于,忽略大小写 expr5 ==# expr5 等于,匹配大小写 等等 如上,? 忽略大小写,# 则匹配之 expr5 is expr5 相同的 |List| 实例 expr5 isnot expr5 不同的 |List| 实例 |expr5| expr6 + expr6 .. 数值加法或列表连接 expr6 - expr6 .. 数值减法 expr6 . expr6 .. 字符串连接 |expr6| expr7 * expr7 .. 数值乘法 expr7 / expr7 .. 数值除法 expr7 % expr7 .. 数值求余 |expr7| ! expr7 逻辑非 - expr7 一元减法: 取反 + expr7 一元加法: 原值 |expr8| expr8[expr1] 字符串里的字节或者 |List| 的项目 expr8[expr1 : expr1] 字符串子串或 |List| 的子列表 expr8.name |Dictionary| 的项目 expr8(expr1, ...) 使用 |Funcref| 变量的函数调用 |expr9| number 数值常数 "string" 字符串常数,反斜杠有特殊含义 'string' 字符串常数,' 加倍 [expr1, ...] |List| {expr1: expr1, ...} |Dictionary| &option 选项值 (expr1) 嵌套表达式 variable 内部变量 va{ria}ble 带花括号的内部变量 $VAR 环境变量 @r 寄存器 'r' 的值 function(expr1, ...) 函数调用 func{ti}on(expr1, ...) 带花括号的函数调用 ".." 标明这一层上的操作可以连接。比如: &nu || &list && &shell == "csh" 同一层的表达式从左到右进行分析。 expr1 *expr1* *E109*


expr2 ? expr1 : expr1

'?' 之前的表达式作为数值求值。如果结果非零,最终的结果是 '?' 和 ':' 之间的表达
式的值,不然最终的结果是 ':' 之后的表达式的值。例如:
        :echo lnum == 1 ? "top" : lnum

因为第一个表达式是 "expr2",它不能包含另一个 ?:。另外两个表达式则没有这个限
制,从而使得递归使用 ?: 成为可能。例如:
        :echo lnum == 1 ? "top" : lnum == 1000 ? "last" : lnum

要使之可读,建议使用续行符 |line-continuation|:
        :echo lnum == 1
        :\      ? "top"
        :\      : lnum == 1000
        :\              ? "last"
        :\              : lnum

在 ':' 前,你总是应该加上空格,否则它可能被错误用在如 "a:1" 这样的变量里。


expr2 和 expr3                                          *expr2* *expr3*


                                        *expr-barbar* *expr-&&*
"||" 和 "&&" 操作符左右两边各接受一个参数。参数是 (或转化为) 数值。运算结果是:

         输入                            输出 
n1              n2              n1 || n2        n1 && n2 
零              零              零              零
零              非零            非零            零
非零            零              非零            零
非零            非零            非零            非零

操作符可以连接。比如:

        &nu || &list && &shell == "csh"

注意 "&&" 比 "||" 优先级高,所以这等价于:

        &nu || (&list && &shell == "csh")

一旦结果可以确定,表达式使用 "短路" 计算,也就是,不再计算后面的参数,这和 C
的情形类似。比如:

        let a = 1
        echo a || b

这是合法的,即使没有叫 "b" 的变量也是如此。因为 "a" 已经是非零值,结果必然是非
零。下面的情形类似:

        echo exists("b") && b == "yes"

无论 "b" 定义与否,这是合法的。第二个子句只有在 "b" 定义的时候才会被计算。


expr4                                                   *expr4*


expr5 {cmp} expr5

比较两个 expr 表达式,如果结果为假,返回 0,如果结果为真,返回 1。

                        *expr-==*  *expr-!=*  *expr->*   *expr->=*
                        *expr-<*   *expr-<=*  *expr-=~*  *expr-!~*
                        *expr-==#* *expr-!=#* *expr->#*  *expr->=#*
                        *expr-<#*  *expr-<=#* *expr-=~#* *expr-!~#*
                        *expr-==?* *expr-!=?* *expr->?*  *expr->=?*
                        *expr-<?*  *expr-<=?* *expr-=~?* *expr-!~?*
                        *expr-is*
                使用 'ignorecase'    匹配大小写     忽略大小写 
等于                    ==              ==#             ==?
不等于                  !=              !=#             !=?
大于                    >               >#              >?
大于等于                >=              >=#             >=?
小于                    <               <#              <?
小于等于                <=              <=#             <=?
匹配正规表达式          =~              =~#             =~?
不匹配正规表达式        !~              !~#             !~?
相同实例                is
不同实例                isnot

示例:
"abc" ==# "Abc"   结果为 0
"abc" ==? "Abc"   结果为 1
"abc" == "Abc"    如果置位了 'ignorecase',结果为 1,不然结果为 0

                                                        *E691* *E692*
|List| 只能和 |List| 比较,而且只能用 "等于"、"不等于" 和 "is"。比较针对列表的
值,递归进行。忽略大小写意味着比较项目的值时忽略大小写。

                                                        *E735* *E736*
|Dictionary| 只能和 |Dictionary| 比较,而且只能用 "等于"、"不等于" 和 "is"。比
较针对 |Dictionary| 的键/值,递归进行。忽略大小写意味着比较项目的值时忽略大小
写。

                                                        *E693* *E694*
|Funcref| 只能和 |Funcref| 比较,而且只能用 "等于" 和 "不等于"。这里永不忽略大
小写。

|List| 用 "is" 或 "isnot" 时,检查表达式是否指向同一个 |List| 实例。|List| 的
备份和原来的 |List| 不同。如果不是 |List|,用 "is" 等价于用 "等于",而 "isnot"
等价于 "不等于",有一点区别: 不同的类型总认为有不同的值。"4 == '4'" 为真,而
"4 is '4'" 为假。

如果比较字符串和数值,字符串被转化成数值,而比较是在数值之间进行的。这意味着
"0 == 'x'" 为真,因为 'x' 被转化成数值 0。

如果比较两个字符串,使用 strcmp() 或 stricmp()。因而,比较的是数学上的差异 (比
较字节码),而不必然是本地语言的字母的差异。

如果操作符后带上 '#',或者 'ignorecase' 关闭时使用无 '#' 的版本时,比较使用
strcmp(): 大小写相关。

如果操作符后带上 '?',或者 'ignorecase' 打开时使用无 '?' 的版本时,比较使用
stricmp(): 大小写无关。

这里 'smartcase' 不适用。

"=~" 和 "!~" 操作符使用右边的参数作为模式来匹配左边的参数。模式的定义见
|pattern|。匹配进行时,总是假设置位了 'magic' 并且 'cpoptions' 为空,无论
'magic' 或 'cpoptions' 实际的值为何。这使得脚本可移植。要避免在正规表达式里使
用的反斜杠需要加倍的问题,可以使用单引号的字符串,见 |literal-string|。
既然字符串假定为单行,多行的模式 (包含 \n,即反斜杠-n) 不会被匹配。不过,按本
义出现的单个 NL 字符可以像普通字符一样匹配。比如:
        "foo\nbar" =~ "\n"      结果为 1
        "foo\nbar" =~ "\\n"     结果为 0


expr5 和 expr6                                          *expr5* *expr6*

expr6 +  expr6 ..       数值加法或 |List| 连接                  *expr-+*
expr6 -  expr6 ..       数值减法                                *expr--*
expr6 .  expr6 ..       字符串连接                              *expr-.*

|Lists| 只能用 "+",而且两个 expr6 必须都是列表。返回两者连接以后的新列表。

expr7 *  expr7 ..       数值乘法                                *expr-star*
expr7 /  expr7 ..       数值除法                                *expr-/*
expr7 %  expr7 ..       数值求余                                *expr-%*

除了 "." 以外,这里所有的操作都把字符串转化成数值。

注意 "+" 和 "." 的差异:
        "123" + "456" = 579
        "123" . "456" = "123456"

如果 '/' 的右边为零,结果为 0x7fffffff。
如果 '%' 的右边为零,结果为 0。

这里没有能用于 |Funcref| 的操作。


expr7                                                   *expr7*

! expr7                 逻辑非                  *expr-!*
- expr7                 一元减法: 取反          *expr-unary--*
+ expr7                 一元加法: 原值          *expr-unary-+*

'!' 把非零变为零,零变为 1。
'-' 改变数值的符号。
'+' 保持原值。

字符串会先转化为数值。

可以重复和混合这三种运算。例如:
        !-1         == 0
        !!8         == 1
        --9         == 9


expr8                                                   *expr8*

expr8[expr1]            字符串或 |List| 的项目          *expr-[]* *E111*

如果 expr8 是数值或字符串,结果是字符串,包含 expr8 里第 expr1 个字节。expr8
视作字符串,expr1 视作数值。注意 这里不识别多字节编码。

索引 0 给出第一个字符。这和 C 类同。要小心: 文本列号可是从 1 开始的!例如,要
得到光标所在的字符:
        :let c = getline(line("."))[col(".") - 1]

如果字符串的长度小于索引值,结果为空字符串。负索引总是给出空字符串 (原因: 反向
兼容)。用 [-1:] 得到最后一个字节。

如果 expr8 是 |List|,返回索引值为 expr1 的项目。可用的索引值见 |list-index|。
如果索引越界,产生错误。例如:
        :let item = mylist[-1]          " 得到最后一个项目

一般的,如果 |List| 索引大于等于 |List| 的长度,或者比 |List| 的长度更负,产生
错误。


expr8[expr1a : expr1b]  子字符串或子列表                *expr-[:]*

如果 expr8 是数值或字符串,结果是子字符串,包含第 expr1a 到第 expr1b (包含) 个
字节。expr8 视作字符串,expr1a 和 expr1b 视作数值。注意 这里不识别多字节编码。

如果省略 expr1a,用零。如果省略 expr1b,用字符串的长度减一。

可以用负数来从字符串尾部开始计算位置。-1 代表最后一个字符,-2 倒数第二个,依此
类推。

如果索引越界,忽略这些字符。如果 expr1b 小于 expr1a,结果是空字符串。

例如:
        :let c = name[-1:]              " 字符串最后一个字节
        :let c = name[-2:-2]            " 字符串倒数第二个字节
        :let s = line(".")[4:]          " 从第五个字节到最后
        :let s = s[:-3]                 " 删除最后两个字节

如果 expr8 是 |List|,结果是新的 |List|,包含 expr1 和 expr1b 索引指定的项目。
和上面描述的字符串情形类似,除了越界的索引会报错以外。例如:
        :let l = mylist[:3]             " 前四个项目
        :let l = mylist[4:4]            " 单个项目的列表
        :let l = mylist[:]              " 列表的浅备份

在 |Funcref| 上用 expr8[expr1] 或 expr8[expr1a : expr1b] 出错。


expr8.name              |Dictionary| 的项目             *expr-entry*

如果 expr8 是一个 |Dictionary| 且后跟句号再跟一个名字,该名字用作 |Dictionary|
的键。这相当于: expr8[name]。

该名字必须由字母数字字符组成。这和变量名一样,不过这里可以用数字开始。但不能用
花括号。

句号前后不能用空白。

例如:
        :let dict = {"one": 1, 2: "two"}
        :echo dict.one
        :echo dict .2

注意 句号也用于字符串连接。要避免混淆,用于字符串连接的句号前后加上空白。


expr8(expr1, ...)       |Funcref| 函数调用

如果 expr8 是 |Funcref| 类型的变量,调用它指向的函数。



                                                *expr9*
number

number                  数值常数                *expr-number*

十进制、十六进制 (0x 或 0X 开始)、或八进制 (0 开始)。


string                                                  *expr-string* *E114*

"string"                字符串常数              *expr-quote*

注意 使用的是双引号。

字符串常数接受以下特殊字符:
\...    三位八进制数 (例如,"\316")
\..     两位八进制数 (必须后跟非数字)
\.      一位八进制数 (必须后跟非数字)
\x..    两位十六进制数指定的字节 (例如,"\x1f")
\x.     一位十六进制数指定的字节 (必须后跟非十六进制数字)
\X..    等同于 \x..
\X.     等同于 \x.
\u....  四位十六进制指定的字符。根据 'encoding' 的当前值决定的编码进行存贮 (例
        如,"\u02a4")
\U....  等同于 \u.....
\b      退格 <BS>
\e      escape <Esc>
\f      换页 <FF>
\n      换行 <NL>
\r      回车 <CR>
\t      制表 <Tab>
\\      反斜杠
\"      双引号
\<xxx>  "xxx" 命名的特殊字符,例如 "\<C-W>" 代表 CTRL-W注意 "\xff" 保存为字节 255,在某些编码中它是不合法的。使用 "\u00ff" 可以按照
'encoding' 的当前值保存字符 255。

注意 "\000" 和 "\x00" 强制字符串结束。


literal-string                                          *literal-string* *E115*

'string'                字符串常数                      *expr-'*

注意 使用的是单引号。

字符串这里按原义出现。不去掉反斜杠,它也没有特殊含义。唯一的特例是两个单引号代
表一个单引号。

单引号字符串有助于模式的使用,因为反斜杠不再需要加倍。以下两个命令等价:
        if a =~ "\\s*"
        if a =~ '\s*'


option                                          *expr-option* *E112* *E113*

&option                 选项值,如有存在,使用局部值
&g:option               全局选项值
&l:option               局部选项值

例如:
        echo "tabstop is " . &tabstop
        if &insertmode

这里可以使用任何选项值。见 |options|。如果指定要使用局部值,但不存在局部于缓冲
区或局部于窗口的选项,则还是使用全局值。


register                                                *expr-register* *@r*

@r                      寄存器 'r' 的值

结果是命名寄存器的内容,以单个字符串表达。换行符在需要时会被插入。要得到无名寄
存器的内容,使用 @" 或 @@。可用寄存器的相关解释可见 |registers|。

如果用 '=' 寄存器,你得到表达式自身,而不是它计算的结果。用 |eval()| 来进行计
算。


nesting                                                 *expr-nesting* *E110*

(expr1)                 嵌套表达式


environment variable                                    *expr-env*

$VAR                    环境变量

任何环境变量的字符串值。如果该环境变量没有定义,结果为空字符串。
                                                *expr-env-expand*
注意 直接使用 $VAR 和使用 expand("$VAR") 有区别。直接使用的形式只能扩展当前
Vim 会话所知的环境变量。使用 expand() 会先尝试当前 Vim 会话所知的环境变量,如
果不成功,则使用外壳扩展该变量。这会变慢,但可以用来扩展只有外壳知道的变量。
例如:
        :echo $version
        :echo expand("$version")
前者可能不会回显任何内容,后者会回显 $version 变量 (如果你的外壳支持的话)。


internal variable                                       *expr-variable*

variable                内部变量
见下面的 |internal-variables|。


function call           *expr-function* *E116* *E118* *E119* *E120*

function(expr1, ...)    函数调用
见下面的 |functions|。



3. 内部变量 *internal-variables* *E121*

*E461* 内部变量的名字由字母、数字和 '_' 组成。但不能由数字开始。可以使用花括号,见 |curly-braces-names|。 内部变量通过 ":let" 命令建立 |:let|。 内部变量通过 ":unlet" 命令显式删除 |:unlet|。 使用非内部变量的名字或引用已经删除的内部变量会产生错误。 变量有不同的命名空间,根据附加的前缀决定: (无) 函数内: 局部于函数;否则: 全局 |buffer-variable| b: 局部于当前缓冲区。 |window-variable| w: 局部于当前窗口。 |tabpage-variable| t: 局部于当前标签页。 |global-variable| g: 全局。 |local-variable| l: 局部于函数。 |script-variable| s: 局部于 |:source| 的 Vim 脚本。 |function-argument| a: 函数参数 (只限于函数内使用)。 |vim-variable| v: Vim 预定义的全局变量。 作用域本身可以用作 |Dictionary|。例如,要删除所有局部于脚本的变量: :for k in keys(s:) : unlet s:[k] :endfor *buffer-variable* *b:var* "b:" 开头的变量名局部于当前缓冲区。这样,你可以为每个缓冲区定义不同的 "b:foo" 变量。这种变量在缓冲区被删除时 (:bwipeout 或 :bdelete |:bdelete|) 同时被删除。 预定义了如下的缓冲区局部变量: *b:changedtick-variable* *changetick* b:changedtick 当前缓冲区的改变次数。每次改变都会递增。撤销命令在此情形下也被 视作一次改变。这可用来在缓冲区发生改变时执行一些动作。比如: :if my_changedtick != b:changedtick : let my_changedtick = b:changedtick : call My_Update() :endif *window-variable* *w:var* "w:" 开头的变量名局部于当前窗口。窗口关闭时被删除。 *tabpage-variable* *t:var* "t" 开始的变量名局部于当前标签页。标签页关闭时,这些变量被删除。{仅当编译时加 入 +windows 特性才有效} *global-variable* *g:var* 函数内部,全局变量可以通过 "g:" 访问。如果不提供前缀,会使用函数的局部变量。在 其他地方,如果你想的话。也可以使用 "g:"。 *local-variable* *l:var* 访问函数的局部变量无需任何前缀。但如果你想要,可以使用 "l:"。不过,如果没有 "l:" 前缀,你可能会和保留的变量名冲突。例如 "count"。它本身指代 "v:count"。但 使用了 "l:count" 你就可以使用同名的局部变量。 *script-variable* *s:var* Vim 脚本里,可以使用 "s:" 开头的变量。它们不能在脚本之外访问,因而可以称为局部 于脚本的变量。 它们可以用于: - 载入脚本时执行的命令 - 脚本定义的函数 - 脚本定义的自动命令 - 脚本定义的函数和自动命令里定义的函数和自动命令 (递归) - 脚本里定义的用户定义命令 但不能用在: - 该脚本载入的其它脚本 - 映射 - 等等 脚本变量可以用来防止和全局变量名的冲突。看看这个例子: let s:counter = 0 function MyCounter() let s:counter = s:counter + 1 echo s:counter endfunction command Tick call MyCounter() 你可以从任何脚本里启动 "Tick",但那个脚本里的 "s:counter" 变量不会被改变,只有 在 "Tick" 定义所在脚本的 "s:counter" 才会。 另一个完成相同功能的例子: let s:counter = 0 command Tick let s:counter = s:counter + 1 | echo s:counter 如果调用函数或者启动用户定义命令,脚本变量的上下文设置为函数和命令定义所在的脚 本。 脚本变量也可用于脚本里定义的函数里定义的函数。例如: let s:counter = 0 function StartCounting(incr) if a:incr function MyCounter() let s:counter = s:counter + 1 endfunction else function MyCounter() let s:counter = s:counter - 1 endfunction endif endfunction 调用 StartCounting() 时,定义 MyCounter() 函数或者递增或者递减计数器。不管 StartCounting() 在哪里调用,s:counter 变量总可以在 MyCounter() 里访问。 如果相同的脚本多次执行,使用的是同一个脚本变量。只要 Vim 还在运行,就保持有 效。这可以用于维护计数: if !exists("s:counter") let s:counter = 1 echo "脚本首次执行" else let s:counter = s:counter + 1 echo "脚本现在执行了 " . s:counter . " 次" endif 注意 这意味着 filetype 插件不能为每个缓冲区提供不同的脚本变量。这时应使用缓冲 区的局部变量 |b:var|。 预定义的 Vim 变量: *vim-variable* *v:var* *v:beval_col* *beval_col-variable* v:beval_col 鼠标指针所在的列号,即 |v:beval_lnum| 行中的字节位置。 仅当计算 'balloonexpr' 选项时有效。 *v:beval_bufnr* *beval_bufnr-variable* v:beval_bufnr 鼠标指针所在的缓冲区号。仅当计算 'balloonexpr' 选项时有效。 *v:beval_lnum* *beval_lnum-variable* v:beval_lnum 鼠标指针所在的行号。仅当计算 'balloonexpr' 选项时有效。 *v:beval_text* *beval_text-variable* v:beval_text 鼠标指针所在或之后的文本。通常是一个单词,可用于调试 C 程序。 此处用到 'iskeyword',但也包括此位置之前的句号和 "->"。如果在 ']' 上,使用它之前的文本,包括匹配的 '[' 和它之前的单词。如果 在单行的可视区域上,使用高亮文本。 仅当计算 'balloonexpr' 选项时有效。 *v:beval_winnr* *beval_winnr-variable* v:beval_winnr 鼠标指针所在的窗口号。仅当计算 'balloonexpr' 选项时有效。 *v:char* *char-variable* v:char 计算 'formatexpr' 时使用的参数。 *v:charconvert_from* *charconvert_from-variable* v:charconvert_from 要转换的文件字符编码名。只在计算 'charconvert' 选项时有效。 *v:charconvert_to* *charconvert_to-variable* v:charconvert_to 转换后的文件字符编码名。只在计算 'charconvert' 选项时有效。 *v:cmdarg* *cmdarg-variable* v:cmdarg 该变量有两个目的: 1. 文件读写命令的额外参数。目前,它们包括 "++enc=" 和 "++ff="。该变量在文件读写命令的自动命令事件激活之前设置。开 头有一个空格,以便直接把该变量附加到读写命令之后。注意: 这 里不包括 "+cmd" 参数,因为它总要被执行的。 2. 使用 ":hardcopy" 打印 PostScript 文件时,":hardcopy" 命令的 参数。在 'printexpr' 里用得到。 *v:cmdbang* *cmdbang-variable* v:cmdbang 文件读写命令时,和 v:cmdarg 设置的时间类似。如果使用了 "!",其 值为 1,不然为 0。注意 它只能用于自动命令。用户命令里可以用 |<bang>|。 *v:count* *count-variable* v:count 最近的普通模式命令使用的计数。在映射前可用于得到计数。只读。 例如: :map _x :<C-U>echo "计数为 " . v:count<CR> 注意: <C-U> 是必要的,它删除紧跟在计数之后 ':' 所给出的行范 围。 也用于计算 'formatexpr' 选项。 为了后向兼容,这里也可以用 "count"。 *v:count1* *count1-variable* v:count1 类似于 "v:count",但没有给出计数时,缺省为 1。 *v:ctype* *ctype-variable* v:ctype 运行环境当前的字符 locale 设置。它使得 Vim 脚本能得到当前的 locale 编码。技术细节: 这就是 LC_CTYPE 的值。如果没有使用 locale,其值为 "C"。 该变量不能直接设置,请使用 |:language| 命令。 见 |multi-lang|。 *v:dying* *dying-variable* v:dying 通常为零。如果捕获到某个 "致命" 的 signal,设为 1。如果同时捕 获到多个 signal,其值相应增加。在自动命令里可以用来检查 Vim 是否被异常终止。{仅限于 Unix} 例如: :au VimLeave * if v:dying | echo "\nAAAAaaaarrrggghhhh!!!\n" | endif *v:errmsg* *errmsg-variable* v:errmsg 最近给出的错误信息。该变量可以设置。 例如: :let v:errmsg = "" :silent! next :if v:errmsg != "" : ... handle error 为了后向兼容,这里也可以用 "errmsg"。 *v:exception* *exception-variable* v:exception 最近捕获且没有完成的例外的值。见 |v:throwpoint| 和 |throw-variables|。 例如: :try : throw "oops" :catch /.*/ : echo "caught" v:exception :endtry 输出: "caught oops"。 *v:fcs_reason* *fcs_reason-variable* v:fcs_reason 激活 |FileChangedShell| 事件的原因。 可以在自动命令里用来决定该做什么和/或如何设置 v:fcs_choice。可 能的值是: deleted 文件不再存在 conflict 文件内容、模式或修改时间被改变,而缓冲 区同时被修改 changed 文件内容被改变 mode 文件模式被改变 time 文件修改时间被改变 *v:fcs_choice* *fcs_choice-variable* v:fcs_choice |FileChangedShell| 事件激活后该做什么。可以在自动命令里用来告 诉 Vim 如何处理涉及的缓冲区: reload 重新载入缓冲区 (如果文件已删除,不能工 作)。 ask 询问用户该做什么,就像没有自动命令一 样。不过,如果只有修改时间被改变,不做 任何事。 <空> 不做任何事。自动命令应该已经处理完毕。 缺省为空。如果使用别的 (非法的) 值,Vim 的行为就像它为空一样。 不会有警告信息。 *v:fname_in* *fname_in-variable* v:fname_in 输入文件名。在计算以下选项时合法: 选项 用于 'charconvert' 要转换的文件 'diffexpr' 原始文件 'patchexpr' 原始文件 'printexpr' 要打印的文件 |SwapExists| 里设为交换文件名。 *v:fname_out* *fname_out-variable* v:fname_out 输出文件名。只有在计算以下选项时才合法: 选项 用于 'charconvert' 生成的转换完成的文件 (*) 'diffexpr' diff 的结果 'patchexpr' 产生的补丁文件 (*) 如果用于为写入命令进行转换 (比如,":w file"),等价于 v:fname_in。如果用于为读入命令进行转换 (比如,":e file"),它是 一个临时文件名,和 v:fname_in 不同。 *v:fname_new* *fname_new-variable* v:fname_new 文件新版本的名字。只有在计算 'diffexpr' 的时候才有效。 *v:fname_diff* *fname_diff-variable* v:fname_diff 比较结果 (或补丁) 的文件名。只有在计算 'patchexpr' 的时候才有 效。 *v:folddashes* *folddashes-variable* v:folddashes 用于 'foldtext': 反映关闭的折叠的折叠级别的连字符。 |sandbox| 里只读。|fold-foldtext| *v:foldlevel* *foldlevel-variable* v:foldlevel 用于 'foldtext': 关闭的折叠的折叠级别。 |sandbox| 里只读。|fold-foldtext| *v:foldend* *foldend-variable* v:foldend 用于 'foldtext': 关闭的折叠的最后一行。 |sandbox| 里只读。|fold-foldtext| *v:foldstart* *foldstart-variable* v:foldstart 用于 'foldtext': 关闭的折叠的第一行。 |sandbox| 里只读。|fold-foldtext| *v:insertmode* *insertmode-variable* v:insertmode 用于 |InsertEnter| 和 |InsertChange| 自动命令事件。取值: i 插入模式 r 替换模式 v 虚拟替换模式 *v:key* *key-variable* v:key |Dictionary| 里当前项目的键。只有在 |map()| 和 |filter()| 里计 算表达式时有效。 只读。 *v:lang* *lang-variable* v:lang 运行环境当前的消息 locale 设置。它使得 Vim 脚本能得到当前使用 的语言。技术细节: 这就是 LC_MESSAGES 的值。该值和系统有关。 该变量不能直接设置,请使用 |:language| 命令。 它和 |v:ctype| 不同,因为消息可能使用不同于字符编码的语言。见 |multi-lang|。 *v:lc_time* *lc_time-variable* v:lc_time 运行环境当前的时间消息 locale 设置。它使得 Vim 脚本能得到当前使用的语言。技术细节: 这就是 LC_TIME 的值。 该变量不能直接设置,请使用 |:language| 命令。见 |multi-lang|。 *v:lnum* *lnum-variable* v:lnum 'foldexpr' |fold-expr| 和 'indentexpr' 表达式里的行号,还有 'guitablevel' 和 'guitabtooltip' 里的标签页号。只有在计算这些 表达式的时候才合法。|sandbox| 里只读。 *v:mouse_win* *mouse_win-variable* v:mouse_win 用 |getchar()| 得到鼠标点击时所在的窗口号。首个窗口的编号为 1 ,就像 |winnr()| 那样。如果那时没有鼠标点击,该值为零。 *v:mouse_lnum* *mouse_lnum-variable* v:mouse_lnum 用 |getchar()| 得到鼠标点击时所在的行号。这是文本行号,不是屏 幕行号。如果那时没有鼠标点击,该值为零。 *v:mouse_col* *mouse_col-variable* v:mouse_col 用 |getchar()| 得到鼠标点击时所在的列号。这是屏幕列号,就像 |virtcol()| 那样。如果那时没有鼠标点击,该值为零。 *v:prevcount* *prevcount-variable* v:prevcount 倒数第二次的普通模式命令使用的计数,也就是再上一个命令用的 v:count 的值。可以用来先中止可视模式,然后使用计数。 :vmap % <Esc>:call MyFilter(v:prevcount)<CR> 只读。 *v:profiling* *profiling-variable* v:profiling 通常为零。开始用 ":profile start" 之后设为一。见 |profiling|。 *v:progname* *progname-variable* v:progname 包含 Vim 启动时使用的名字 (路径已被去掉)。可以用来为 "view"、 "evim" 等符号链接到 Vim 的名字提供特殊的设置。 只读。 *v:register* *register-variable* v:register 最近的普通模式命令使用的寄存器名字。如果没有使用过,为空。 |getreg()| |setreg()| *v:scrollstart* *scrollstart-variable* v:scrollstart 指示使屏幕上滚的脚本或函数的字符串。只有在原来为空时才设置,因 此只记住第一个原因。如果来自输入的命令,设为 "Unknown"。 可以用来发现你的脚本为什么产生 hit-enter 提示。 *v:servername* *servername-variable* v:servername 如果有的话,注册过的 |x11-clientserver| 名字。 只读。 *v:shell_error* *shell_error-variable* v:shell_error 最近一次外壳命令的返回值。如果非零,最近一次外壳命令有错。如果 为零,则该命令成功返回。这只有在外壳把错误代码返回给 Vim 的时 候才工作。-1 通常用来告知该命令无法执行。只读。 例如: :!mv foo bar :if v:shell_error : echo '不能把 "foo" 换名为 "bar"!' :endif 为了后向兼容,这里也可以用 "shell_error"。 *v:statusmsg* *statusmsg-variable* v:statusmsg 最近给出的状态消息。可以设置该变量。 *v:swapname* *swapname-variable* v:swapname 只有在执行 |SwapExists| 自动命令时才合法: 找到的交换文件名。只 读。 *v:swapchoice* *swapchoice-variable* v:swapchoice |SwapExists| 自动命令可以设置此值,以选择如何处理已有交换文件: 'o' 以只读方式打开 'e' 仍然编辑 'r' 恢复 'd' 删除交换文件 'q' 退出 'a' 中止 该值应是单个字符的字符串。如果为空,用户会被询问,就像没有 SwapExists 自动命令那样。缺省为空。 *v:swapcommand* *swapcommand-variable* v:swapcommand 打开文件后执行的普通模式命令。可以用于 |SwapExists| 自动命令, 用以让另一个 Vim 打开文件并跳转到合适的位置。例如,要跳转到某 标签,用的值是 ":tag tagname\r"。":edit +cmd file" 用的值是 ":cmd\r"。 *v:termresponse* *termresponse-variable* v:termresponse 使用 |t_RV| termcap 项目返回的终端的转义序列。Vim 收到 ESC [ 或者 CSI 开始,以一个 'c' 结束,并且其间只包含数字,';' 和 '.' 的转义序列的时候,会设置该值。 如果设置该选项,会激活 TermResponse 自动命令事件,这样你就可以 对终端的应答做出反应。 新的 xterm 的应答是: "<Esc>[ Pp ; Pv ; Pc c"。 Pp 是终端类型: 0 代表 vt100,而 1 代表 vt220。 Pv 是补丁号 (因为这是 patch 95 引入的,补丁号应该总是 95 会更高)。Pc 总是零。 {仅当编译时加入 |+termresponse| 特性才有效} *v:this_session* *this_session-variable* v:this_session 最近载入或者保存的会话文件的文件名 |:mksession|。可以设置该变 量。如果没有保存过会话文件,该变量为空。 为了后向兼容,这里也可以用 "this_session"。 *v:throwpoint* *throwpoint-variable* v:throwpoint 最近捕获且未完成的例外的抛出位置。输入的命令不会设置此变量。另 见 |v:exception| 和 |throw-variables|。 例如: :try : throw "oops" :catch /.*/ : echo "Exception from" v:throwpoint :endtry 输出: "Exception from test.vim, line 2" *v:val* *val-variable* v:val |List| 或 |Dictionary| 当前项目的值。只有在计算 |map()| 和 |filter()| 里的表达式时才有效。只读。 *v:version* *version-variable* v:version Vim 的版本号: 主版本号乘以 100 加上副版本号。5.0 版本对应的是 500。5.1 版本 (5.01) 则是 501。只读。为了后向兼容,这里也可以 用 "version"。 用 |has()| 可以检查是否包含某补丁,例如: if has("patch123") 注意 补丁号和版本有关,5.0 和 5.1 版本都有补丁号 123,但完全不 同。 *v:warningmsg* *warningmsg-variable* v:warningmsg 最近给出的警告消息。该变量可以设置。

4. 内建函数 *functions*

|function-list| 提供了按功能分组的一个函数列表。 (在函数名上使用 CTRL-] 跳转到完整的功能说明。) 用法 结果 描述 add( {list}, {item}) 列表 在 |List| {list} 最后附加 {item} append( {lnum}, {string}) 数值 在第 {lnum} 行下附加字符串 {string} append( {lnum}, {list}) 数值 在第 {lnum} 行下附加行 {list} argc() 数值 参数列表的文件数目 argidx() 数值 参数列表的当前索引 argv( {nr}) 字符串 参数列表第 {nr} 个参数 argv( ) 列表 参数列表 browse( {save}, {title}, {initdir}, {default}) 字符串 启动文件请求窗口 browsedir( {title}, {initdir}) 字符串 启动目录请求窗口 bufexists( {expr}) 数值 如果缓冲区 {expr} 存在则为真 buflisted( {expr}) 数值 如果缓冲区 {expr} 在列表内则为真 bufloaded( {expr}) 数值 如果缓冲区 {expr} 被载入则为真 bufname( {expr}) 字符串 缓冲区 {expr} 的名字 bufnr( {expr}) 数值 缓冲区 {expr} 的数目 bufwinnr( {expr}) 数值 缓冲区 {expr} 的窗口号 byte2line( {byte}) 数值 第 {byte} 个字节所在的行号 byteidx( {expr}, {nr}) 数值 {expr} 里第 {nr} 个字符的字节位置 call( {func}, {arglist} [, {dict}]) 可变 调用函数 {func},使用参数 {arglist} changenr() 数值 当前改变号 char2nr( {expr}) 数值 {expr} 里第一个字符串的 ASCII 值 cindent( {lnum}) 数值 第 {lnum} 行的 C 缩进 col( {expr}) 数值 光标或位置标记的列号 complete({startcol}, {matches}) 字符串 设置插入模式补全 complete_add( {expr}) 数值 增加补全匹配 complete_check() 数值 补全时检查输入的键 confirm( {msg} [, {choices} [, {default} [, {type}]]]) 数值 用户选择的序号 copy( {expr}) 可变 提供 {expr} 的浅备份 count( {list}, {expr} [, {start} [, {ic}]]) 数值 计算 {list} 里有多少个 {expr} cscope_connection( [{num} , {dbpath} [, {prepend}]]) 数值 检查 cscope 连接是否存在 cursor( {lnum}, {col} [, {coladd}]) 数值 移动光标到 {lnum}{col}{coladd} cursor( {list}) 数值 移动光标到 {list} 里的位置 deepcopy( {expr}) 可变 提供 {expr} 的完整备份 delete( {fname}) 数值 删除文件 {fname} did_filetype() 数值 如果使用过 FileType 自动命令事件则为真 diff_filler( {lnum}) 数值 {lnum} 行之上的 diff 填充行数 diff_hlID( {lnum}, {col}) 数值 {lnum}/{col} 位置的 diff 高亮 empty( {expr}) 数值 如果 {expr} 为空则为真 escape( {string}, {chars}) 字符串 在 {string} 里用 '\' 转义 {chars} eval( {string}) 可变 计算 {string},返回结果 eventhandler( ) 数值 如果在事件处理中则为真 executable( {expr}) 数值 如果可执行文件 {expr} 存在则为 1 exists( {expr}) 数值 如果 {expr} 存在则为真 extend({expr1}, {expr2} [, {expr3}]) 列表/字典 把 {expr2} 里的项目插入 {expr1} expand( {expr}) 字符串 扩展 {expr} 里的特殊关键字 feedkeys( {string} [, {mode}]) 数值 给预输入缓冲区加入键序列 filereadable( {file}) 数值 如果 {file} 是个可读文件则为真 filewritable( {file}) 数值 如果 {file} 是个可写文件则为真 filter( {expr}, {string}) 列表/字典 删除 {expr}{string} 为 0 的项目 finddir( {name}[, {path}[, {count}]]) 字符串 在 {path} 里寻找目录 {name} findfile( {name}[, {path}[, {count}]]) 字符串 在 {path} 里寻找文件 {name} fnamemodify( {fname}, {mods}) 字符串 修改文件名 foldclosed( {lnum}) 数值 {lnum} 所在折叠的首行,如果是关闭的话 foldclosedend( {lnum}) 数值 {lnum} 所在折叠的末行,如果是关闭的话 foldlevel( {lnum}) 数值 {lnum} 的折叠级别 foldtext( ) 字符串 关闭的折叠显示的行 foldtextresult( {lnum}) 字符串 {lnum} 所在的关闭的折叠的文本 foreground( ) 数值 把 Vim 窗口带到前台 function( {name}) 函数引用 函数 {name} 的引用 garbagecollect() 无 释放内存,打破循环引用 get( {list}, {idx} [, {def}]) 可变 得到 {list}{def} 的项目 {idx} get( {dict}, {key} [, {def}]) 可变 得到 {dict}{def} 的项目 {idx} getbufline( {expr}, {lnum} [, {end}]) 列表 缓冲区 {expr}{lnum}{end} 行 getbufvar( {expr}, {varname}) 可变 缓冲区 {expr} 的变量 {varname} getchar( [expr]) 数值 让用户输入一个字符 getcharmod( ) 数值 最近输入字符的修饰符 getcmdline() 字符串 返回当前命令行 getcmdpos() 数值 返回命令行的光标位置 getcmdtype() 字符串 返回当前命令行类型 getcwd() 字符串 当前工作目录 getfperm( {fname}) 字符串 文件 {fname} 的文件权限 getfsize( {fname}) 数值 字节计算的文件 {fname} 大小 getfontname( [{name}]) 字符串 使用的字体名 getftime( {fname}) 数值 文件的最新修改时间 getftype( {fname}) 字符串 文件 {fname} 类型的描述 getline( {lnum}) 字符串 当前缓冲区的第 {lnum} 行 getline( {lnum}, {end}) 列表 当前缓冲区第 {lnum}{end} 行 getloclist({nr}) 列表 位置列表项目的列表 getpos( {expr}) 列表 光标、位置标记等的位置 getqflist() 列表 quickfix 项目的列表 getreg( [{regname} [, 1]]) 字符串 寄存器内容 getregtype( [{regname}]) 字符串 寄存器类型 gettabwinvar( {tabnr}, {winnr}, {name}) 可变 {tabnr} 标签页 {winnr} 窗口的 {name} getwinposx() 数值 GUI Vim 窗口以像素计的 X 坐标 getwinposy() 数值 GUI Vim 窗口以像素计的 Y 坐标 getwinvar( {nr}, {varname}) 可变 窗口 {expr} 的变量 {varname} glob( {expr}) 字符串 扩展 {expr} 里的文件通配符 globpath( {path}, {expr}) 字符串 在 {path} 所有目录下执行 glob({expr}) has( {feature}) 数值 如果支持特性 {feature} 则为真 has_key( {dict}, {key}) 数值 如果 {dict} 有项目 {key} 则为真 haslocaldir() 数值 如果当前窗口执行过 |:lcd| hasmapto( {what} [, {mode} [, {abbr}]]) 数值 如果 {what} 的映射存在则为真 histadd( {history},{item}) 字符串 在历史里增加项目 histdel( {history} [, {item}]) 字符串 从历史里删除项目 histget( {history} [, {index}]) 字符串 得到历史的第 {index} 项 histnr( {history}) 数值 历史里最高的项目号 hlexists( {name}) 数值 如果高亮组 {name} 存在则为真 hlID( {name}) 数值 高亮组 {name} 的语法 ID hostname() 字符串 Vim 运行的机器名字 iconv( {expr}, {from}, {to}) 字符串 转换 {expr} 的编码 indent( {lnum}) 数值 第 {lnum} 行的缩进 index( {list}, {expr} [, {start} [, {ic}]]) 数值 {list} 列表里出现 {expr} 的项目的索引 input( {prompt} [, {text} [, {completion}]]) 字符串 从用户得到输入 inputdialog( {p} [, {t} [, {c}]]) 字符串 类似于 input(),但使用 GUI 对话框 inputlist( {textlist}) 数值 让用户从选择列表里挑选 inputrestore() 数值 恢复预输入 inputsave() 数值 保存和清除预输入 inputsecret( {prompt} [, {text}]) 字符串 类似于 input(),但隐藏文本 insert( {list}, {item} [, {idx}]) 列表 在 {list} 里插入 {item} [{idx} 之前] isdirectory( {directory}) 数值 如果 {directory} 是目录则为真 islocked( {expr}) 数值 如果 {expr} 被锁住则为真 items( {dict}) 列表 {dict} 里的键-值组对 join( {list} [, {sep}]) 字符串 连接 {list} 的项目成为一个字符串 keys( {dict}) 列表 {dict} 的所有键 len( {expr}) 数值 {expr} 的长度 libcall( {lib}, {func}, {arg}) 字符串 调用库 {lib} 的函数 {func},使用参数 {arg} libcallnr( {lib}, {func}, {arg}) 数值 同上,但返回数值 line( {expr}) 数值 光标所在、末行或者位置标记所在的行号 line2byte( {lnum}) 数值 行 {lnum} 的字节位置 lispindent( {lnum}) 数值 行 {lnum} 的 Lisp 缩进 localtime() 数值 当前时间 map( {expr}, {string}) 列表/字典 {expr} 的每个项目改变为 {string} maparg( {name}[, {mode} [, {abbr}]]) 字符串 模式 {mode} 的映射 {name} 的右边 mapcheck( {name}[, {mode} [, {abbr}]]) 字符串 检查匹配 {name} 的映射 match( {expr}, {pat}[, {start}[, {count}]]) 数值 {expr}{pat} 的匹配位置 matcharg( {nr}) 列表 |:match| 的参数 matchend( {expr}, {pat}[, {start}]) 数值 {expr}{pat} 的结束位置 matchlist( {expr}, {pat}[, {start}[, {count}]]) 列表 {expr}{pat} 的匹配和子匹配 matchstr( {expr}, {pat}[, {start}[, {count}]]) 字符串 第 {count}{expr}{pat} 的匹配文 本 max({list}) 数值 {list} 的项目的最大值 min({list}) 数值 {list} 的项目的最小值 mkdir({name} [, {path} [, {prot}]]) 数值 建立目录 {name} mode() 字符串 当前编辑模式 nextnonblank( {lnum}) 数值 第一个 >= {lnum} 的非空白行的行号 nr2char( {expr}) 字符串 ASCII 值为 {expr} 的单个字符 pathshorten( {expr}) 字符串 缩短路径里的目录名 prevnonblank( {lnum}) 数值 最后一个 <= {lnum} 的非空白行的行号 printf( {fmt}, {expr1}...) 字符串 排版文本 pumvisible() 数值 弹出窗口是否可见 range( {expr} [, {max} [, {stride}]]) 列表 从 {expr}{max} 的序列 readfile({fname} [, {binary} [, {max}]]) 列表 得到文件 {fname} 的行列表 reltime( [{start} [, {end}]]) 列表 得到时间值 reltimestr( {time}) 字符串 把时间值转化为字符串 remote_expr( {server}, {string} [, {idvar}]) 字符串 发送表达式 remote_foreground( {server}) 数值 把 Vim 服务器带到前台 remote_peek( {serverid} [, {retvar}]) 数值 检查应答字符串 remote_read( {serverid}) 字符串 读入应答字符串 remote_send( {server}, {string} [, {idvar}]) 字符串 发送键序列 remove( {list}, {idx} [, {end}]) 可变 从 {list} 里删除项目 {idx}-{end} remove( {dict}, {key}) 可变 从 {dict} 里删除项目 {key} rename( {from}, {to}) 数值 换名 (移动) 文件,从 {from}{to} repeat( {expr}, {count}) 字符串 重复 {expr} {count} 次 resolve( {filename}) 字符串 解析快捷方式对应的文件名 reverse( {list}) 列表 反转 {list},直接修改 {list} search( {pattern} [, {flags}]) 数值 搜索 {pattern} searchdecl({name} [, {global} [, {thisblock}]]) 数值 搜索变量声明 searchpair( {start}, {middle}, {end} [, {flags} [, {skip} [, {stopline}]]]) 数值 搜索 start/end 对的另一侧 searchpairpos( {start}, {middle}, {end} [, {flags} [, {skip} [, {stopline}]]]) 列表 搜索 start/end 队的另一侧 searchpos( {pattern} [, {flags} [, {stopline}]]) 列表 搜索 {pattern} server2client( {clientid}, {string}) 数值 发送应答字符串 serverlist() 字符串 得到可用的服务器列表 setbufvar( {expr}, {varname}, {val}) 设置缓冲区 {expr}{varname}{val} setcmdpos( {pos}) 数值 设置命令行的光标位置 setline( {lnum}, {line}) 数值 设置第 {lnum} 行的内容为 {line} setloclist( {nr}, {list}[, {action}]) 数值 用 {list} 修改位置列表 setpos( {expr}, {list}) 无 设置 {expr} 的位置为 {list} setqflist( {list}[, {action}]) 数值 用 {list} 修改 quickfix 列表 setreg( {n}, {v}[, {opt}]) 数值 设置寄存器的值和类型 settabwinvar( {tabnr}, {winnr}, {varname}, {val}) 无 设置标签页 {tabnr} 窗口 {winnr}{varname} 变量为 {val} setwinvar( {nr}, {varname}, {val}) 设置窗口 {expr}{varname}{val} shellescape( {string}) 字符串 转义 {string} 以便用作外壳命令的参数 simplify( {filename}) 字符串 尽可能简化文件名 sort( {list} [, {func}]) 列表 排序 {list},用比较函数 {func} soundfold( {word}) 字符串 按发音折叠 {word} spellbadword() 字符串 光标所在的拼写错误的单词 spellsuggest( {word} [, {max} [, {capital}]]) 列表 拼写建议 split( {expr} [, {pat} [, {keepempty}]]) 列表 从 {pat} 分割的 {expr} 里构造 |List| str2nr( {expr} [, {base}]) 数值 把字符串转换为数值 strftime( {format}[, {time}]) 字符串 指定格式的时间 stridx( {haystack}, {needle}[, {start}]) 数值 {haystack}{needle} 的位置 string( {expr}) 字符串 {expr} 值得字符串表示 strlen( {expr}) 数值 字符串 {expr} 的长度 strpart( {src}, {start}[, {len}]) 字符串 {src}{start} 开始的 {len} 个字节 strridx( {haystack}, {needle} [, {start}]) 数值 {haystack} 里最后一个 {needle} 的位置 strtrans( {expr}) 字符串 翻译字符串,使之可以显示 submatch( {nr}) 字符串 ":substitute" 的特定匹配 substitute( {expr}, {pat}, {sub}, {flags}) 字符串 {expr} 里的所有 {pat}{sub} 替代 synID( {lnum}, {col}, {trans}) 数值 {lnum}{col} 列所在的语法 ID synIDattr( {synID}, {what} [, {mode}]) 字符串 syntax ID {synID}{what} 属性 synIDtrans( {synID}) 数值 {synID} 经过翻译的语法 ID system( {expr} [, {input}]) 字符串 外壳命令/过滤 {expr} 的输出 tabpagebuflist( [{arg}]) 列表 标签页里的缓冲区号列表 tabpagenr( [{arg}]) 数值 当前或最后标签页的编号 tabpagewinnr( {tabarg}[, {arg}]) 数值 标签页里当前窗口的编号 taglist( {expr}) 列表 匹配 {expr} 的标签列表 tagfiles() 列表 使用的标签文件 tempname() 字符串 临时文件的文件名 tolower( {expr}) 字符串 字符串 {expr} 变为小写 toupper( {expr}) 字符串 字符串 {expr} 变为大写 tr( {src}, {fromstr}, {tostr}) 字符串 把 {src} 里的 {fromstr} 字符翻译为 {tostr} 字符 type( {name}) 数值 变量 {name} 的类型 values( {dict}) 列表 {dict} 的所有值 virtcol( {expr}) 数值 光标或位置标记的屏幕列 visualmode( [expr]) 字符串 最近使用的可视模式 winbufnr( {nr}) 数值 窗口 {nr} 的缓冲区号 wincol() 数值 光标所在的窗口列 winheight( {nr}) 数值 窗口 {nr} 的高度 winline() 数值 光标所在的窗口行 winnr( [{expr}]) 数值 当前窗口的编号 winrestcmd() 字符串 返回恢复窗口大小的命令 winrestview({dict}) 无 恢复当前窗口的视图 winsaveview() 字典 保存当前窗口的视图 winwidth( {nr}) 数值 窗口 {nr} 的宽度 writefile({list}, {fname} [, {binary}]) 数值 把行列表写到文件 {fname} add({list}, {expr}) *add()* 在 |List| {list} 最后附加项目 {expr}。返回新产生的 |List|。例 如: :let alist = add([1, 2, 3], item) :call add(mylist, "woodstock") 注意 如果 {expr} 是 |List|,它被作为单个项目附加进去。 |extend()| 可以用来连接 |List|。 |insert()| 可以用来把一个项目加到其它的位置上。 append({lnum}, {expr}) *append()*{expr} 为 |List|: 把每个 |List| 项目作为文本行,附加到当前 缓冲区第 {lnum} 行之下。 否则,把 {expr} 作为单个文本行,附加于当前缓冲区第 {lnum} 行之 下。 {lnum} 可以为零,用于在第一行前插入一行。如果失败 ({lnum} 越 界),返回 1,成功则返回 0。例如: :let failed = append(line('$'), "# THE END") :let failed = append(0, ["Chapter 1", "the beginning"]) *argc()* argc() 返回当前窗口参数列表的文件数目。见 |arglist|。 *argidx()* argidx() 返回参数列表的当前索引。0 是第一个文件。argc() - 1 是最后一 个。见 |arglist|。 *argv()* argv([{nr}]) 返回当前窗口参数列表第 {nr} 个参数。见 |arglist|。"argv(0)" 是 第一个。 例如: :let i = 0 :while i < argc() : let f = escape(argv(i), '. ') : exe 'amenu Arg.' . f . ' :e ' . f . '<CR>' : let i = i + 1 :endwhile 如果没有 {nr} 参数,返回完整的 {arglist} 的 |List|。 *browse()* browse({save}, {title}, {initdir}, {default}) 启动文件请求窗口。只有在 "has("browse")" 返回非零时 (只有在一 些 GUI 版本里) 才可以。 输入的字段包括: {save} 非零时,选择要写入的文件 {title} 请求窗口的标题 {initdir} 开始浏览的目录 {default} 缺省文件名 如果按了 "Cancel" 按钮、出错、或者无法浏览,返回空字符串。 *browsedir()* browsedir({title}, {initdir}) 启动目录请求窗口。只有在 "has("browse")" 返回非零时 (只有在一 些 GUI 版本里) 才能工作。 有的系统上不支持目录浏览器,这时使用文件浏览器。此时: 选择要用 的目录里的文件。 输入的字段包括: {title} 请求窗口的标题 {initdir} 开始浏览的目录 如果按了 "Cancel" 按钮、出错、或者无法浏览,返回空字符串。 bufexists({expr}) *bufexists()* 返回数值,如果名为 {expr} 的缓冲区存在的话,返回非零。 如果 {expr} 参数是数值,指定缓冲区号。 如果 {expr} 参数是字符串,缓冲区的名字必须与其完全匹配。该名字 可以是: - 相对于当前目录。 - 完整路径。 - 'filetype' 设为 "nofile" 的缓冲区名。 - URL 名。 列表外缓冲区也会被找到。 注意 帮助文件在 |:buffers| 里列出的是它们的短名字。但 bufexists() 需要它们的长名字才能找到它们。 使用 "bufexists(0)" 可以测试是否存在轮换文件名。