Nvim :help
页面,生成 自 源代码 使用 tree-sitter-vimdoc 解析器。
{"blue": "#0000ff", "red": "#ff0000"} #{blue: "#0000ff", red: "#ff0000"}Blob 二进制大对象。 存储任何字节序列。 有关详细信息,请参阅 Blob。 例如:0zFF00ED015DAF 0z 是一个空的 Blob。
:echo "0100" + 0
:if "foo" :" NOT executed"foo" 被转换为 0,这意味着 FALSE。 如果字符串以非零数字开头,则表示 TRUE
:if "8foo" :" executed要测试非空字符串,请使用 empty()
:if !empty("foo")
:let Fn = function("MyFunc") :echo Fn()
:function dict.init() dict : let self.val = 0 :endfunctionDictionary 的键可以以小写字母开头。 此处不使用实际的函数名。 另请参阅 numbered-function。
:call Fn() :call dict.init()可以使用 string() 获取引用的函数的名称。
:let func = string(Fn)您可以使用 call() 调用 Funcref 并使用列表变量作为参数
:let r = call(Fn, mylist)
let Cb = function('Callback', ['foo'], myDict) call Cb('bar')这将调用函数,就像使用
call myDict.Callback('foo', 'bar')请注意,将函数绑定到 Dictionary 也会在函数是 Dictionary 的成员时发生
let myDict.myFunction = MyFunction call myDict.myFunction()在此,MyFunction() 将接收 myDict 作为 "self" 传递。 这是在访问 "myFunction" 成员时发生的。 当将 "myFunction" 分配给 otherDict 并调用它时,它将绑定到 otherDict
let otherDict.myFunction = myDict.myFunction call otherDict.myFunction()现在 "self" 将是 "otherDict"。 但是,当字典被显式绑定时,这种情况不会发生
let myDict.myFunction = function(MyFunction, myDict) let otherDict.myFunction = myDict.myFunction call otherDict.myFunction()在此,"self" 将是 "myDict",因为它被显式绑定了。
:let mylist = [1, two, 3, "four"] :let emptylist = []项目可以是任何表达式。 使用列表作为项目将创建一个列表的列表
:let nestlist = [[11, 12], [21, 22], [31, 32]]最后一个项目后的额外逗号将被忽略。
:let item = mylist[0] " get the first item: 1 :let item = mylist[2] " get the third item: 3当生成的项目是列表时,可以重复此操作
:let item = nestlist[0][1] " get the first list, second item: 12
:let last = mylist[-1] " get the last item: "four"要避免对无效索引的错误,请使用 get() 函数。 当项目不可用时,它会返回零或您指定的默认值
:echo get(mylist, idx) :echo get(mylist, idx, "NONE")
:let longlist = mylist + [5, 6] :let longlist = [5, 6] + mylist要将项目添加到开头或结尾,请将其转换为列表,方法是在其周围加上 []。
:let shortlist = mylist[2:-1] " get List [3, "four"]省略第一个索引类似于零。 省略最后一个索引类似于 -1。
:let endlist = mylist[2:] " from item 2 to the end: [3, "four"] :let shortlist = mylist[2:2] " List with one item: [3] :let otherlist = mylist[:] " make a copy of the List请注意,最后一个索引是包含的。 如果您更喜欢使用排他索引,请使用 slice() 方法。
:let mylist = [0, 1, 2, 3] :echo mylist[2:8] " result: [2, 3]注意:mylist[s:e] 表示使用变量 "s:e" 作为索引。 注意在 ":" 之前使用单个字母变量的情况。 在需要时插入空格:mylist[s : e]。
:let aa = [1, 2, 3] :let bb = aa :call add(aa, 4) :echo bb
:let aa = [[1, 'a'], 2, 3] :let bb = copy(aa) :call add(aa, 4) :let aa[0][1] = 'aaa' :echo aa
:echo bb
:let alist = [1, 2, 3] :let blist = [1, 2, 3] :echo alist is blist
:echo alist == blist
echo 4 == "4"
echo [4] == ["4"]
:let a = 5 :let b = "5" :echo a == b
:echo [a] == [b]
:let [var1, var2] = mylist如果变量的数量与列表中的项的数量不匹配,这将产生错误。要处理列表中的任何额外项,请附加 ";" 和一个变量名
:let [var1, var2; rest] = mylist这类似于
:let var1 = mylist[0] :let var2 = mylist[1] :let rest = mylist[2:]除了如果只有两个项,则不会出错。 "rest" 将是一个空列表。
:let list[4] = "four" :let listlist[0][3] = item要更改列表的一部分,您可以指定要修改的第一项和最后一项。该值至少必须包含范围内的项数。
:let list[3:5] = [3, 4, 5]要将项添加到列表中,您可以使用 :let+= (list-concatenation)。
:let listA = [1, 2] :let listA += [3, 4]
:let listA = [1, 2] :let listB = listA :let listB += [3, 4] :echo listA [1, 2, 3, 4]
:call insert(list, 'a') " prepend item 'a' :call insert(list, 'a', 3) " insert item 'a' before list[3] :call add(list, "new") " append String item :call add(list, [1, 2]) " append a List as one new item :call extend(list, [1, 2]) " extend the list with two more items :let i = remove(list, 3) " remove item 3 :unlet list[3] " idem :let l = remove(list, 3, -1) " remove items 3 to last item :unlet list[3 : ] " idem :call filter(list, 'v:val !~ "x"') " remove items with an 'x'更改列表中项的顺序
:call sort(list) " sort a list alphabetically :call reverse(list) " reverse the order of items :call uniq(sort(list)) " sort and remove duplicates
: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如果您只想修改列表中的每个项,那么使用 map() 函数比使用 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对于 Blob,一次使用一个字节。
for c in text echo 'This character is ' .. c endfor
:let r = call(funcname, list) " call a function with an argument list :if empty(list) " check if list is empty :let l = len(list) " number of items in list :let big = max(list) " maximum value in list :let small = min(list) " minimum value in list :let xs = count(list, 'x') " count nr of times 'x' appears in list :let i = index(list, 'x') " index of first 'x' in list :let lines = getline(1, 10) " get ten text lines from buffer :call append('$', lines) " append text lines in buffer :let list = split("a b c") " create list from items in a string :let string = join(list, ', ') " create string from list items :let s = string(list) " String representation of list :call map(list, '">> " .. v:val') " prepend ">> " to each item不要忘记,功能的组合可以使事情变得简单。例如,要将列表中的所有数字加起来
:exe 'let sum = ' .. join(nrlist, '+')
:let mydict = {1: 'one', 2: 'two', 3: 'three'} :let emptydict = {}
:let mydict = #{zero: 0, one_key: 1, two-key: 2, 333: 3}请注意,此处的 333 是字符串 "333"。使用 #{} 不允许使用空键。
:let nestdict = {1: {11: 'a', 12: 'b'}, 2: {21: 'c'}}最后一个条目后面的额外逗号将被忽略。
:let val = mydict["one"] :let mydict["four"] = 4与列表不同,您可以通过这种方式将新条目添加到现有字典中。
:let val = mydict.one :let mydict.four = 4由于条目可以是任何类型,包括列表和字典,因此可以重复索引和键查找
:echo dict.key[idx].key
: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
:let onedict = {'a': 1, 'b': 2} :let adict = onedict :let adict['a'] = 11 :echo onedict['a'] 11如果所有键值对都比较相等,则两个字典比较相等。有关更多信息,请参见 list-identity。
:let dict[4] = "four" :let dict['one'] = item从字典中删除条目是通过 remove() 或 :unlet 完成的。从字典中删除键为 "aaa" 的条目的三种方法
:let i = remove(dict, 'aaa') :unlet dict.aaa :unlet dict['aaa']将字典与另一个字典合并是通过 extend() 完成的
:call extend(adict, bdict)这将使用 bdict 中的所有条目扩展 adict。重复的键会导致 adict 中的条目被覆盖。可选的第三个参数可以更改此行为。请注意,字典中条目的顺序无关紧要,因此不要指望 ":echo adict" 在 adict 中的旧条目之后显示 bdict 中的项。
:call filter(dict, 'v:val =~ "x"')这将删除 "dict" 中所有值为 'x' 的条目。这也可以用于删除所有条目
call filter(dict, 0)
:function Mylen() dict : return len(self.data) :endfunction :let mydict = {'data': [0, 1, 2, 3], 'len': function("Mylen")} :echo mydict.len()这类似于面向对象编程中的方法。字典中的条目是 Funcref。局部变量 "self" 指向调用该函数的字典。
:let mydict = {'data': [0, 1, 2, 3]} :function mydict.len() : return len(self.data) :endfunction :echo mydict.len()然后,该函数将获得一个数字,并且 dict.len 的值是 Funcref,它引用该函数。该函数只能通过 Funcref 使用。当不再存在引用它的 Funcref 时,它将自动删除。
:function g:42
:if has_key(dict, 'foo') " TRUE if dict has entry with key "foo" :if empty(dict) " TRUE if dict is empty :let l = len(dict) " number of items in dict :let big = max(dict) " maximum value in dict :let small = min(dict) " minimum value in dict :let xs = count(dict, 'x') " count nr of times 'x' appears in dict :let s = string(dict) " String representation of dict :call map(dict, '">> " .. v:val') " prepend ">> " to each item
:let b = 0zFF00ED015DAF可以在字节(十六进制字符对)之间插入点以提高可读性,它们不会更改值
:let b = 0zFF00.ED01.5DAF可以使用 readfile() 从文件读取 Blob,并将
{type}
参数设置为 "B",例如:let b = readfile('image.png', 'B')
:let myblob = 0z00112233 :let byte = myblob[0] " get the first byte: 0x00 :let byte = myblob[2] " get the third byte: 0x22负索引从末尾开始计数。索引 -1 指向 Blob 中的最后一个字节,-2 指向倒数第二个字节,依此类推。
:let last = myblob[-1] " get the last byte: 0x33为了避免因无效索引而导致错误,请使用 get() 函数。如果项不可用,则返回 -1 或您指定的默认值
:echo get(myblob, idx) :echo get(myblob, idx, 999)
:for byte in 0z112233 : call Doit(byte) :endfor这将使用 0x11、0x22 和 0x33 调用 Doit()。
:let longblob = myblob + 0z4455 :let longblob = 0z4455 + myblob
:let myblob += 0z6677
:let myblob = 0z00112233 :let shortblob = myblob[1:2] " get 0z1122 :let shortblob = myblob[2:-1] " get 0z2233省略第一个索引类似于零。 省略最后一个索引类似于 -1。
:let endblob = myblob[2:] " from item 2 to the end: 0z2233 :let shortblob = myblob[2:2] " Blob with one byte: 0z22 :let otherblob = myblob[:] " make a copy of the Blob如果第一个索引超出 Blob 的最后一个字节,或者第二个索引在第一个索引之前,则结果为空 Blob。不会显示错误消息。
:echo myblob[2:8] " result: 0z2233
:let blob[4] = 0x44如果索引恰好在 Blob 末尾之后,则将该字节追加到 Blob 中。任何更高的索引都会导致错误。
let blob[1:3] = 0z445566替换字节的长度必须与提供的值完全相同。 E972
:let blob[3:5] = 0z334455要将项目就地添加到 Blob,可以使用 :let+= (blob-concatenation)
:let blobA = 0z1122 :let blobA += 0z3344
:let blobA = 0z1122 :let blobB = blobA :let blobB += 0z3344 :echo blobA 0z11223344
if blob == 0z001122以及是否具有相同的标识
if blob is otherblob
:let blob = 0z112233 :let blob2 = blob :echo blob == blob2
:echo blob is blob2
:let blob3 = blob[:] :echo blob == blob3
:echo blob is blob3
'string'
字符串常量,' 需加倍 [expr1, ...] List {expr1: expr1, ...}
Dictionary #{key: expr1, ...} Dictionary &option 选项值 (expr1) 嵌套表达式 变量 内部变量 va{ria}ble 内部变量,带大括号 $VAR 环境变量 @r 寄存器 "r" 的内容 function(expr1, ...) 函数调用 func{ti}on(expr1, ...) 带大括号的函数调用 {args -> expr1}
lambda 表达式&nu || &list && &shell == "csh"同一级别内的所有表达式都从左到右解析。
: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"。
echo theList ?? 'list is empty' echo GetName() ?? 'unknown'这些相似,但不相等
expr2 ?? expr1 expr2 ? expr2 : expr1在第二行中,"expr2" 被评估了两次。
&nu || &list && &shell == "csh"请注意,"&&" 的优先级高于 "||",因此这具有以下含义
&nu || (&list && &shell == "csh")一旦结果已知,表达式 "短路",即不会评估进一步的参数。 这就像在 C 中发生的情况一样。 例如
let a = 1 echo a || b即使没有名为 "b" 的变量,这也是有效的,因为 "a" 为 TRUE,因此结果必须为 TRUE。 类似地,在下面
echo exists("b") && b == "yes"无论 "b" 是否已定义,这都是有效的。 只有在 "b" 已定义的情况下才会评估第二个子句。
{cmp}
expr5if get(Part1, 'name') == get(Part2, 'name') " Part1 and Part2 refer to the same function使用 "is" 或 "isnot" 与 List、Dictionary 或 Blob 进行比较,会检查表达式是否引用同一个 List、Dictionary 或 Blob 实例。List 的副本与原始 List 不同。当使用 "is" 时,如果没有 List、Dictionary 或 Blob,它等同于使用 "equal",使用 "isnot" 等同于使用 "not equal"。除了不同类型意味着值不同。
echo 4 == '4' 1 echo 4 is '4' 0 echo 0 is [] 0"is#"/"isnot#" 和 "is?"/"isnot?" 可用于匹配和忽略大小写。
echo 0 == 'x' 1因为 'x' 转换为数字为零。但是
echo [0] == ['x'] 0在列表或字典中,这种转换不会被使用。
1 . 90 + 90.0作为
(1 . 90) + 90.0这有效,因为字符串 "190" 会自动转换为数字 190,可以将其添加到浮点数 90.0 中。但是
1 . 90 * 90.0应读取为
1 . (90 * 90.0)因为 '.' 的优先级低于 '*'。这不起作用,因为这尝试连接浮点数和字符串。
byteidx()
获取替代方法,或使用 split()
将字符串转换为字符列表。例如,要获取光标下的字节:let c = getline(".")[col(".") - 1]索引 0 表示第一个字节。这与 C 中的工作方式类似。注意:文本列号从 1 开始!例如,要获取光标下的字节
:let c = getline(".")[col(".") - 1]索引 0 表示第一个字节。注意:文本列号从 1 开始!
:let item = mylist[-1] " get last item一般来说,如果 List 索引等于或大于 List 的长度,或者比 List 的长度更负,则会导致错误。
:let c = name[-1:] " last byte of a string :let c = name[0:-1] " the whole string :let c = name[-2:-2] " last but one byte of a string :let s = line(".")[4:] " from the fifth byte to the end :let s = s[:-3] " remove last two bytes
:let l = mylist[:3] " first four items :let l = mylist[4:4] " List with one item :let l = mylist[:] " shallow copy of a List如果 expr8 是 Blob,则结果是一个新的 Blob,其中包含索引为 expr1a 和 expr1b(包括)的字节。示例
:let b = 0zDEADBEEF :let bs = b[1:2] " 0zADBE :let bs = b[] " copy of 0zDEADBEEF在 Funcref 上使用 expr8[expr1] 或 expr8[expr1a : expr1b] 会导致错误。
mylist[n:] " uses variable n mylist[s:] " uses namespace s:, error!expr8.name Dictionary 中的条目 expr-entry
:let dict = {"one": 1, 2: "two"} :echo dict.one " shows "1" :echo dict.2 " shows "two" :echo dict .2 " error because of space before the dot请注意,点也用于字符串连接。为了避免混淆,始终在点周围加空格以进行字符串连接。
mylist->filter(filterexpr)->map(mapexpr)->sort()->join()
GetPercentage()->{x -> x * 100}()->printf('%d%%')
mylist \ ->filter(filterexpr) \ ->map(mapexpr) \ ->sort() \ ->join()使用 lambda 形式时,在 } 和 之间不能有空格
{N}
和 {M}
是数字。{N}
和 {M}
必须都存在,并且只能包含数字。[-+] 表示可选的正负号。{exp}
是指数,10 的幂。只接受小数点,不接受逗号。无论当前区域设置如何。{M}
1e40 缺少 .{M}:let pi = 3.14159265359 :let e = 2.71828182846或者,如果你不想将它们写成浮点数字面量,你也可以使用函数,比如以下函数
:let pi = acos(-1.0) :let e = exp(1.0)
:echo printf('%.15e', atan(1))
<BS>
\e 转义 <Esc>
\f 换页 0x0C \n 换行 <NL>
\r 回车 <CR>
\t 制表符 <Tab>
\\ 反斜杠 \" 双引号 \<xxx> 名称为 "xxx" 的特殊键。例如,CTRL-W
的 "\<C-W>"。这是在映射中使用的,0x80 字节被转义。要使用双引号字符,必须对其进行转义:"<M-\">"。不要使用 <Char-xxxx>
来获取 UTF-8 字符,请使用上面提到的 \uxxxx。\<*xxx> 与 \<xxx> 相同,但会在前面添加一个修饰符而不是将其包含在字符中。例如,"\<C-w>" 是一个字符 0x17,而 "\<*C-w>" 是四个字节:3 个用于 CTRL 修饰符,然后是字符 "W"。:let b = 0zFF00ED015DAF
if a =~ "\\s*" if a =~ '\s*'
let your_name = input("What's your name? ")
echo echo $"Hello, {your_name}!"
echo $"The square root of {{9}} is {sqrt(9)}"
{9}
的平方根是 3.0echo "tabstop is " .. &tabstop if &expandtab此处可以使用任何选项名称。请参阅 options。使用本地值时,如果不存在缓冲区级本地值或窗口级本地值,则仍然使用全局值。
getenv()
和 setenv()
也可以使用,并且适用于名称不包含字母数字字符的环境变量。函数 environ()
可用于获取包含所有环境变量的 Dict。:echo $shell :echo expand("$shell")第一个可能不会回显任何内容,第二个回显 $shell 变量(如果你的 shell 支持它)。
:let F = {arg1, arg2 -> arg1 - arg2} :echo F(5, 2)
:let F = {-> 'error function'} :echo F('ignored')
:function Foo(arg) : let i = 3 : return {x -> x + i - a:arg} :endfunction :let Bar = Foo(4) :echo Bar(6)
if has('lambda')使用 lambda 表达式与 sort()、map() 和 filter() 的示例
:echo map([1, 2, 3], {idx, val -> val + 1})
:echo sort([3,7,2,1,4], {a, b -> a - b})
:let timer = timer_start(500, \ {-> execute("echo 'Handler called'", "")}, \ {'repeat': 3})
function Function() let x = 0 let F = {-> x} endfunction闭包使用函数作用域中的 "x",而该作用域中的 "F" 引用了闭包。这种循环会导致内存无法释放。建议:不要这样做。
<lambda>
42'。如果你遇到 lambda 表达式的错误,可以使用以下命令找到它是哪个:function <lambda>42另请参阅:numbered-function
:for k in keys(s:) : unlet s:[k] :endfor
:if my_changedtick != b:changedtick : let my_changedtick = b:changedtick : call My_Update() :endif
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这将定义 MyCounter() 函数,用于在调用 StartCounting() 时向上或向下计数。无论从哪里调用 StartCounting(),s:counter 变量都可以在 MyCounter() 中访问。
if !exists("s:counter") let s:counter = 1 echo "script executed for the first time" else let s:counter = s:counter + 1 echo "script executed " .. s:counter .. " times now" endif请注意,这意味着文件类型插件不会为每个缓冲区获得不同的脚本变量集。请改用局部缓冲区变量 b:var。
my_{adjective}_variable当 Vim 遇到这种情况时,它会计算大括号内的表达式,并将该表达式替换为表达式本身,然后重新解释整个表达式作为变量名称。因此,在上面的示例中,如果变量 "adjective" 被设置为 "noisy",则引用将为 "my_noisy_variable",而如果 "adjective" 被设置为 "quiet",则引用将为 "my_quiet_variable"。
echo my_{&background}_message将输出 "my_dark_message" 或 "my_light_message" 的内容,具体取决于 'background' 的当前值。
echo my_{adverb}_{adjective}_message...甚至嵌套它们
echo my_{ad{end_of_word}}_message其中 "end_of_word" 是 "verb" 或 "jective"。
:let foo='a + b' :echo c{foo}d...因为扩展结果是 "ca + bd",这不是变量名称。
:let func_end='whizz' :call my_func_{func_end}(parameter)这将调用函数 "my_func_whizz(parameter)"。
:let i = 3 :let @{i} = '' " error :echo @{i} " error
{var-name}
= {expr1}
:let E18 将内部变量 {var-name}
设置为表达式 {expr1}
的结果。该变量将从 {expr}
中获取类型。如果 {var-name}
之前不存在,它将被创建。{var-name}
[{idx}
] = {expr1}
E689{expr1}
的结果。{var-name}
必须引用一个列表,{idx}
必须是该列表中的有效索引。对于嵌套列表,索引可以重复。这不能用来将项添加到 列表 中。这不能用来在字符串中设置字节。您可以这样做:let var = var[0:2] .. 'X' .. var[4:]
{var-name}
[{idx1}
:{idx2}] = {expr1}
E708 E709 E710 将 列表 中的一系列项设置为表达式 {expr1}
的结果,该表达式必须是包含正确数量项的列表。{idx1}
可以省略,将使用零代替。{idx2}
可以省略,表示列表的末尾。当选择的项范围部分超出列表末尾时,将添加项。{var}
+= {expr1}
像 ":let {var}
= {var}
+ {expr1}
"。:let {var}
-= {expr1}
像 ":let {var}
= {var}
- {expr1}
"。:let {var} *= {expr1}
像 ":let {var}
= {var}
* {expr1}
"。:let {var}
/= {expr1}
像 ":let {var}
= {var}
/ {expr1}
"。:let {var}
%= {expr1}
像 ":let {var}
= {var}
% {expr1}
"。:let {var}
.= {expr1}
像 ":let {var}
= {var}
. {expr1}
"。:let {var}
..= {expr1}
像 ":let {var}
= {var}
.. {expr1}
"。如果 {var}
尚未设置,以及当 {var}
和 {expr1}
的类型不符合运算符时,这些操作将失败。+=
会就地修改 列表 或 Blob,而不是创建新的列表或 Blob。{expr1}
:let-environment :let-$ 将环境变量 {env-name}
设置为表达式 {expr1}
的结果。类型始终为字符串。:let ${env-name} .= {expr1}
将 {expr1}
附加到环境变量 {env-name}
。如果环境变量之前不存在,则此操作与 "=" 相同。{expr1}
:let-register :let-@ 将表达式 {expr1}
的结果写入寄存器 {reg-name}
。{reg-name}
必须是一个字母,并且必须是可写寄存器的名称(参见 寄存器)。"@@" 可以用来表示无名寄存器,"@" 用来表示搜索模式。如果 {expr1}
的结果以 <CR>
或 <NL>
结尾,则寄存器将设置为行模式,否则将设置为字符模式。这可以用来清除上次搜索模式:let @/ = ""
{expr1}
将 {expr1}
附加到寄存器 {reg-name}
。如果寄存器为空,则相当于将其设置为 {expr1}
。{expr1}
:let-option :let-& 将选项 {option-name}
设置为表达式 {expr1}
的结果。字符串或数字值始终转换为选项的类型。对于窗口或缓冲区局部选项,效果与使用 :set 命令相同:本地值和全局值都将更改。示例:let &path = &path .. ',/usr/local/include':let &{option-name} .=
{expr1}
对于字符串选项:将 {expr1}
附加到值。不会像 :set+= 一样插入逗号。{expr1}
:let &{option-name} -= {expr1}
对于数字或布尔选项:添加或减去 {expr1}
。{expr1}
:let &l:{option-name} .= {expr1}
:let &l:{option-name} += {expr1}
:let &l:{option-name} -= {expr1}
与上面相同,但仅设置选项的本地值(如果存在)。工作方式类似于 :setlocal。{expr1}
:let &g:{option-name} .= {expr1}
:let &g:{option-name} += {expr1}
:let &g:{option-name} -= {expr1}
与上面相同,但仅设置选项的全局值(如果存在)。工作方式类似于 :setglobal。{name1}
, {name2}
, ...] = {expr1}
:let-unpack E687 E688 {expr1}
必须计算为一个 列表。列表中的第一个项目被分配给 {name1}
,第二个项目被分配给 {name2}
,依此类推。名称的数量必须与 列表 中项目的数量匹配。每个名称都可以是上面提到的 ":let" 命令中的一个项目。示例:let [s, item] = GetItem(s)
{expr1}
首先被计算,然后按顺序进行分配。如果 {name2}
依赖于 {name1}
,这一点很重要。示例:let x = [0, 1] :let i = 0 :let [i, x[i]] = [1, 2] :echo x
{name1}
, {name2}
, ...] .= {expr1}
:let [{name1}
, {name2}
, ...] += {expr1}
:let [{name1}
, {name2}
, ...] -= {expr1}
与上面相同,但为每个 列表 项目附加/添加/减去值。{name}
, ..., ; {lastname}
] = {expr1}
E452{lastname}
。如果没有剩余项目,则 {lastname}
被设置为一个空列表。示例:let [a, b; rest] = ["aval", "bval", 3, 4]
{name}
, ..., ; {lastname}
] .= {expr1}
:let [{name}
, ..., ; {lastname}
] += {expr1}
:let [{name}
, ..., ; {lastname}
] -= {expr1}
与上面相同,但为每个 列表 项目附加/添加/减去值。{var-name}
=<< [trim] [eval] {endmarker}
text... text... {endmarker}
将内部变量 {var-name}
设置为包含由字符串 {endmarker}
限制的文本行的 列表。{expr}
的任何 Vim 表达式都会被计算,并且结果会替换该表达式,就像使用 插值字符串 一样。其中 $HOME 被扩展的示例let lines =<< trim eval END some text See the file {$HOME}/.vimrc more text END
{endmarker}
必须不包含空格。{endmarker}
不能以小写字母开头。最后一行应该只以 {endmarker}
字符串结尾,不包含任何其他字符。注意 {endmarker}
后面的空格!{endmarker}
之前指定了 "trim",则会删除缩进,这样你就可以进行let text =<< trim END if ok echo 'done' endif END
["if ok", " echo 'done'", "endif"]
标记必须与 "let" 对齐,并且第一行的缩进将从所有文本行中删除。具体来说:从输入行中删除与第一行非空文本行的前导缩进完全匹配的所有前导缩进。从包含 {endmarker}
的行中删除与 let
前面的前导缩进完全匹配的所有前导缩进。请注意,空格和制表符之间的区别在此处很重要。{var-name}
之前不存在,它会被创建。不能在后面跟着另一个命令,但可以跟着注释。set cpo+=C let var =<< END \ leading backslash END set cpo-=C
let var1 =<< END Sample text 1 Sample text 2 Sample text 3 END let data =<< trim DATA 1 2 3 4 5 6 7 8 DATA let code =<< trim eval CODE let v = {10 + 20} let h = "{$HOME}" let s = "{Str1()} abc {Str2()}" let n = {MyFunc(3, 4)} CODE
{var-name}
.. 列出变量 {var-name}
的值。可以给出多个变量名。这里识别的特殊名称:E738<nothing>
字符串 # 数字 * 函数引用{name}
... :unlet :unl E108 E795 删除内部变量 {name}
。可以给出多个变量名,它们都被删除。名称也可以是 列表 或 字典 项目。使用 [!] 不会为不存在的变量显示错误消息。可以从 列表 中删除一个或多个项目:unlet list[3] " remove fourth item :unlet list[3:] " remove fourth item to last
:unlet dict['two'] :unlet dict.two
{env-name}
。可以在一个 :unlet 命令中混合 {name}
和 ${env-name}。对于不存在的变量不会显示错误消息,即使没有使用 !。如果系统不支持删除环境变量,则将其清空。{var-name}
= {expr1}
:cons[t] [{name1}
, {name2}
, ...] = {expr1}
:cons[t] [{name}
, ..., ; {lastname}
] = {expr1}
:cons[t] {var-name}
=<< [trim] [eval] {marker}
text... text... {marker}
与 :let 相似,但在设置值后还会锁定变量。这与在 :let 之后立即使用 :lockvar 锁定变量相同,因此:const x = 1
:let x = 1 :lockvar! x
const ll = [1, 2, 3] let ll[1] = 5 " Error!
let lvar = ['a'] const lconst = [0, lvar] let lconst[0] = 2 " Error! let lconst[1][0] = 'b' " OK
{name}
... :lockvar :lockv 锁定内部变量 {name}
。锁定意味着它不能再更改(直到它被解锁)。锁定变量可以被删除:lockvar v :let v = 'asdf' " fails! :unlet v " works
{name}
"。如果您尝试锁定或解锁内置变量,您将收到错误消息 "E940: Cannot lock or unlock variable {name}
"。{name}
,但不锁定其值。1 锁定 列表 或 字典 本身,不能添加或删除项目,但仍然可以更改其值。2 也锁定值,不能更改项目。如果一个项目是 列表 或 字典,不能添加或删除项目,但仍然可以更改其值。3 与 2 相同,但针对 列表 / 字典 中的 列表 / 字典,更深一层。默认的 [depth] 为 2,因此当 {name}
是 列表 或 字典 时,值不能被更改。let mylist = [1, 2, 3] lockvar 0 mylist let mylist[0] = 77 " OK call add(mylist, 4) " OK let mylist = [7, 8, 9] " Error!
:let l = [0, 1, 2, 3] :let cl = l :lockvar l :let cl[1] = 99 " won't work!
{name}
不存在,则不会显示错误。{expr1}
:if :end :endif :en E171 E579 E580 :en[dif] 如果 {expr1}
计算结果为非零,则执行命令,直到遇到下一个匹配的 :else
或 :endif
。虽然可以使用简短形式,但建议始终使用 :endif
以避免混淆并使自动缩进正常工作。:if
和 :endif
之间的每个 Ex 命令都会被忽略。这两个命令只是为了在保持向后兼容的同时允许未来扩展。嵌套是允许的。请注意,任何 :else
或 :elseif
都会被忽略,else
部分也不会被执行。:if version >= 500 : version-5-specific-commands :endif
endif
。有时,旧版本的 Vim 会遇到新命令的问题。例如,:silent
被识别为 :substitute
命令。在这种情况下,:execute
可以避免问题:if version >= 600 : execute "silent 1,$delete" :endif
:append
和 :insert
命令在 :if
和 :endif
之间不能正常工作。{expr1}
:while :endwhile :wh :endw E170 E585 E588 E733 :endw[hile] 只要 {expr1}
的值为非零,就重复 :while
和 :endwhile
之间的命令。当循环内部的命令检测到错误时,执行将继续在 endwhile
之后。示例:let lnum = 1 :while lnum <= line("$") :call FixLine(lnum) :let lnum = lnum + 1 :endwhile
:append
和 :insert
命令在 :while
和 :for
循环内部无法正常工作。{var}
in {object}
:for E690 E732 :endfo[r] :endfo :endfor 对于 {object}
中的每个项目,重复 :for
和 :endfor
之间的命令。{object}
可以是 列表、Blob 或 字符串。{var}
设置为每个项目的 value。endfor
之后。在循环内部更改 {object}
会影响使用的项目。如果不需要,请创建副本。:for item in copy(mylist)
{object}
是 列表 并且没有创建副本时,Vim 会在使用当前项目执行命令之前将对 列表 中下一个项目的引用存储起来。因此,可以移除当前项目而不会影响后续操作。移除任何后续项目意味着它将找不到。因此,以下示例可以正常工作(一种使 列表 为空的低效方法)for item in mylist call remove(mylist, 0) endfor
{object}
是 字符串 时,每个项目都是一个包含一个字符的字符串,再加上任何组合字符。{var1}
, {var2}
, ...] in {listlist}
:endfo[r] 与上面的 :for
类似,但 {listlist}
中的每个项目都必须是一个列表,其每个项目都分配给 {var1}
、{var2}
等。示例:for [lnum, col] in [[1, 3], [2, 5], [3, 8]] :echo getline(lnum)[col] :endfor
:try
之后但匹配的 :finally
之前使用(如果存在),则首先执行 :finally
后面的命令,直到匹配的 :endtry
。此过程适用于循环内部的所有嵌套 :try
。然后最外层的 :endtry
跳回到循环开头。:while
或 :for
循环内部使用时,跳过匹配的 :endwhile
或 :endfor
之后的命令。如果它在循环内部的 :try
之后但匹配的 :finally
之前使用(如果存在),则首先执行 :finally
后面的命令,直到匹配的 :endtry
。此过程适用于循环内部的所有嵌套 :try
。然后最外层的 :endtry
跳到循环之后的命令。:try
和 :endtry
之间的命令的错误处理,包括跨 :source
命令、函数调用或自动命令调用执行的所有内容。:finally
命令时,执行将继续在 :finally
之后。否则,或者当 :endtry
之后到达时,将检查下一个(动态)包围的 :try
以查找相应的 :finally
等。然后脚本处理将终止。函数定义是否具有“abort”参数无关紧要。示例try | call Unknown() | finally | echomsg "cleanup" | endtry echomsg "not reached"
:try
和 :endtry
内部的错误或中断(动态)将转换为异常。它可以像由 :throw
命令抛出一样被捕获(参见 :catch
)。在这种情况下,脚本处理不会终止。{command}
):{errmsg}”的值,其他错误将转换为形式为“Vim:{errmsg}”的值。{command}
是完整的命令名称,{errmsg}
是如果错误异常未被捕获则显示的消息,始终以错误号开头。示例try | sleep 100 | catch /^Vim:Interrupt$/ | endtry try | edit | catch /^Vim(edit):E\d\+/ | echo "error" | endtry
{pattern}
匹配且尚未被先前 :catch
捕获的异常时,执行以下命令,直到遇到与 :catch
相同 :try
所属的下一个 :catch
、:finally
或 :endtry
。否则,将跳过这些命令。当省略 {pattern}
时,将捕获所有错误。示例:catch /^Vim:Interrupt$/ " catch interrupts (CTRL-C) :catch /^Vim\%((\a\+)\)\=:E/ " catch all Vim errors :catch /^Vim\%((\a\+)\)\=:/ " catch errors and interrupts :catch /^Vim(write):/ " catch all errors in :write :catch /^Vim\%((\a\+)\)\=:E123:/ " catch error E123 :catch /my-exception/ " catch user exception :catch /.*/ " catch everything :catch " same as /.*/
{pattern}
周围使用另一个字符而不是 /,只要它没有特殊含义(例如,'|' 或 '"')并且不在 {pattern}
内部出现即可。有关异常的信息可在 v:exception 中找到。另请参见 throw-variables。 注意: 对错误消息的 TEXT 进行 ":catch" 并不可靠,因为错误消息在不同的语言环境中可能有所不同。:try
和 :finally
之间的部分退出,就会执行以下命令,直到匹配的 :endtry
:要么是直接进入 :finally
,要么是通过 :continue
、:break
、:finish
或 :return
,要么是通过错误或中断或异常(参见 :throw
)。{expr1}
{expr1}
被计算并作为异常抛出。如果 :throw
在 :try
之后但在第一个对应的 :catch
之前使用,则跳过命令,直到遇到第一个与 {expr1}
匹配的 :catch
。如果没有这样的 :catch
,或者如果 :throw
在 :catch
之后但在 :finally
之前使用,则执行 :finally
后面的命令(如果存在),直到匹配的 :endtry
。如果 :throw
在 :finally
之后,则跳过直到 :endtry
的命令。在 :endtry
处,此过程将再次应用于下一个动态包围的 :try
(它可能在调用函数或源脚本中找到),直到找到匹配的 :catch
。如果异常未被捕获,则命令处理将终止。示例:try | throw "oops" | catch /^oo/ | echo "caught" | endtry
{expr1}
.. 回显每个 {expr1}
,并在它们之间添加一个空格。第一个 {expr1}
从新行开始。另请参见 :comment。使用 "\n" 开始新行。使用 "\r" 将光标移动到第一列。使用 :echohl
命令设置的突出显示。不能后跟注释。示例:echo "the value of 'shell' is" &shell
:echo
之前的命令导致稍后重绘(重绘通常会推迟到您键入内容为止),请使用 :redraw
命令强制进行重绘。示例:new | redraw | echo "there is a new window"
:let l = [] :call add(l, l) :let l2 = [] :call add(l2, [l2]) :echo l l2
{expr1}
.. 回显每个 {expr1}
,不添加任何内容。另请参见 :comment。使用 :echohl
命令设置的突出显示。不能后跟注释。示例:echon "the value of 'shell' is " &shell
:echo
(这是一个 Vim 命令)和 :!echo
(这是一个外部 shell 命令)之间的区别。:!echo % --> filename
:!echo "%" --> filename or "filename"
:echo % --> nothing
:echo "%" --> %
:echo expand("%") --> filename
{name}
对以下 :echo
、:echon
和 :echomsg
命令使用突出显示组 {name}
。也用于 input()
提示。示例:echohl WarningMsg | echo "Don't panic!" | echohl None
{expr1}
.. 将表达式作为真实消息回显,并将消息保存在 消息历史记录 中。与 :echo
命令一样,在参数之间添加空格。但不可打印字符将被显示,而不是解释。解析方式与 :echo
略有不同,更类似于 :execute
。所有表达式将先被计算并连接起来,然后再回显任何内容。如果表达式没有计算为数字或字符串,则使用 string() 将其转换为字符串。使用 :echohl
命令设置的突出显示。示例:echomsg "It's a Zizzer Zazzer Zuzz, as you can plainly see."
{expr1}
.. 将表达式作为错误消息回显,并将消息保存在 消息历史记录 中。当在脚本或函数中使用时,将添加行号。与 :echomsg
命令一样,在参数之间添加空格。当在 try 条件内部使用时,消息将被提升为错误异常(参见 try-echoerr)。示例:echoerr "This script just failed!"
:echohl
。为了获得提示音:exe "normal \<Esc>"
append()
调用将文本列表追加到缓冲区。这类似于 :call
,但适用于任何表达式。:ev
或 :eva
,但它们难以识别,因此不应使用。{expr1}
.. 将对 {expr1}
求值后得到的字符串作为 Ex 命令执行。多个参数将连接在一起,并在它们之间加上空格。若要避免额外的空格,请使用 ".." 运算符将字符串连接成一个参数。{expr1}
用作处理后的命令,命令行编辑键不会被识别。不能后跟注释。示例:execute "buffer" nextbuf :execute "normal" count .. "w"
:execute '!ls' | echo "theend"
:execute "normal ixxx\<Esc>"
<Esc>
字符,参见 expr-string。:execute "e " .. fnameescape(filename) :execute "!ls " .. shellescape(filename, 1)
:if 0 : execute 'while i > 5' : echo "test" : endwhile :endif
:execute 'while i < 5 | echo i | let i = i + 1 | endwhile'
:echo "foo" | "this is a comment
:try : ... : ... TRY BLOCK : ... :catch /{pattern}/ : ... : ... CATCH CLAUSE : ... :catch /{pattern}/ : ... : ... CATCH CLAUSE : ... :finally : ... : ... FINALLY CLAUSE : ... :endtrytry 条件句允许您监视代码是否有异常,并采取相应的措施。来自 try 块的异常可以被捕获。来自 try 块以及捕获子句的异常可能会导致执行清理操作。当在执行 try 块时没有抛出异常时,控制权将被转移到 finally 子句(如果有)。在执行完 finally 子句后,脚本将继续执行 ":endtry" 之后的下一行。当在执行 try 块时发生异常时,try 块中剩余的行将被跳过。该异常将与作为 ":catch" 命令参数指定的模式进行匹配。第一个匹配的 ":catch" 之后的捕获子句将被执行,其他捕获子句将不会被执行。捕获子句将在遇到下一个 ":catch"、":finally" 或 ":endtry" 命令时结束 - 以最先遇到的命令为准。然后,将执行 finally 子句(如果有)。当遇到 ":endtry" 时,脚本执行将像往常一样从下一行继续执行。当在 try 块中抛出与任何 ":catch" 命令指定的模式都不匹配的异常时,该异常不会被该 try 条件句捕获,并且不会执行任何捕获子句。只有 finally 子句(如果有)会被执行。在执行 finally 子句期间,异常将挂起。它将在 ":endtry" 处恢复,因此 ":endtry" 之后的命令将不会被执行,并且异常可能会在其他地方被捕获,参见 try-nesting。当在执行捕获子句时抛出另一个异常时,该捕获子句中剩余的行将不会被执行。新的异常不会与同一 try 条件句中任何 ":catch" 命令的模式进行匹配,并且不会执行其任何捕获子句。但是,如果有 finally 子句,则会执行该子句,并且异常将在其执行期间挂起。":endtry" 之后的命令不会被执行。但是,新的异常可能会在其他地方被捕获,参见 try-nesting。当在执行 finally 子句(如果有)时抛出异常时,finally 子句中剩余的行将被跳过。如果由于 try 块或某个捕获子句中的异常而执行了 finally 子句,则原始(挂起的)异常将被丢弃。":endtry" 之后的命令不会被执行,并且来自 finally 子句的异常将被传播,并且可以在其他地方被捕获,参见 try-nesting。
:throw 4711 :throw "string"
:throw 4705 + strlen("string") :throw strpart("strings", 0, 6)在对 ":throw" 命令的参数求值期间,可能会抛出异常。除非在该处捕获异常,否则表达式求值将被放弃。然后,":throw" 命令不会抛出新的异常。示例
:function! Foo(arg) : try : throw a:arg : catch /foo/ : endtry : return 1 :endfunction : :function! Bar() : echo "in Bar" : return 4710 :endfunction : :throw Foo("arrgh") + Bar()这会抛出 "arrgh",并且不会显示 "in Bar",因为不会执行 Bar()。
:throw Foo("foo") + Bar()但是,会显示 "in Bar" 并抛出 4711。
:if Foo("arrgh") : echo "then" :else : echo "else" :endif此处既不会显示 "then" 也不会显示 "else"。
:function! Foo(value) : try : throw a:value : catch /^\d\+$/ : echo "Number thrown" : catch /.*/ : echo "String thrown" : endtry :endfunction : :call Foo(0x1267) :call Foo('string')对 Foo() 的第一次调用会显示 "Number thrown",第二次调用会显示 "String thrown"。异常将按照指定顺序与 ":catch" 命令进行匹配。只有第一次匹配有效。因此,您应该将更具体的 ":catch" 放在首位。以下顺序没有意义
: catch /.*/ : echo "String thrown" : catch /^\d\+$/ : echo "Number thrown"此处,第一个 ":catch" 将始终匹配,因此永远不会执行第二个捕获子句。
: catch /^\d\+$/ : echo "Number thrown. Value is" v:exception您可能还想知道在何处抛出了异常。它存储在 v:throwpoint 中。请注意,只要异常没有完成,"v:exception" 和 "v:throwpoint" 就对最近捕获的异常有效。示例
:function! Caught() : if v:exception != "" : echo 'Caught "' .. v:exception .. '" in ' .. v:throwpoint : else : echo 'Nothing caught' : endif :endfunction : :function! Foo() : try : try : try : throw 4711 : finally : call Caught() : endtry : catch /.*/ : call Caught() : throw "oops" : endtry : catch /.*/ : call Caught() : finally : call Caught() : endtry :endfunction : :call Foo()这会显示
Nothing caught Caught "4711" in function Foo, line 4 Caught "oops" in function Foo, line 10 Nothing caught一个实际示例:以下命令 ":LineNumber" 会显示在脚本或函数中使用它的行号
:function! LineNumber() : return substitute(v:throwpoint, '.*\D\(\d\+\).*', '\1', "") :endfunction :command! LineNumber try | throw "" | catch | echo LineNumber() | endtry
:try : try : throw "foo" : catch /foobar/ : echo "foobar" : finally : echo "inner finally" : endtry :catch /foo/ : echo "foo" :endtry内部 try 条件句不会捕获异常,只会执行其 finally 子句。然后,外部 try 条件句会捕获该异常。该示例会显示 "inner finally",然后显示 "foo"。
:function! Foo() : throw "foo" :endfunction : :function! Bar() : try : call Foo() : catch /foo/ : echo "Caught foo, throw bar" : throw "bar" : endtry :endfunction : :try : call Bar() :catch /.*/ : echo "Caught" v:exception :endtry这会显示 "Caught foo, throw bar",然后显示 "Caught bar"。
:function! Bar() : try : call Foo() : catch /.*/ : echo "Rethrow" v:exception : throw v:exception : endtry :endfunction
:try : try : asdf : catch /.*/ : echoerr v:exception : endtry :catch /.*/ : echo v:exception :endtry此代码显示
CTRL-C
中断脚本,则设置将保持不一致状态。在脚本的开发阶段,如果发生错误或你明确抛出未捕获的异常,也可能发生这种情况。你可以使用带 finally 子句的 try 条件语句来解决这些问题,以恢复设置。在正常控制流、错误、显式“:throw”和中断时,保证其执行。(请注意,try 条件语句内部的错误和中断将转换为异常。如果未捕获,它们将在 finally 子句执行完毕后终止脚本。)示例:try : let s:saved_ts = &ts : set ts=17 : : " Do the hard work here. : :finally : let &ts = s:saved_ts : unlet s:saved_ts :endtry此方法应在任何函数或脚本部分更改需要在该函数或脚本部分失败或正常退出时恢复的全局设置时局部使用。
:let first = 1 :while 1 : try : if first : echo "first" : let first = 0 : continue : else : throw "second" : endif : catch /.*/ : echo v:exception : break : finally : echo "cleanup" : endtry : echo "still in while" :endwhile :echo "end"这将显示“first”、“cleanup”、“second”、“cleanup”和“end”。
:function! Foo() : try : return 4711 : finally : echo "cleanup\n" : endtry : echo "Foo still active" :endfunction : :echo Foo() "returned by Foo"这将显示“cleanup”和“4711 returned by Foo”。你无需在 finally 子句中添加额外的“:return”。(最重要的是,这将覆盖返回值。)
:try : try : echo "Press CTRL-C for interrupt" : while 1 : endwhile : finally : unlet novar : endtry :catch /novar/ :endtry :echo "Script still running" :sleep 1如果你需要将可能失败的命令放入 finally 子句中,你应该考虑捕获或忽略这些命令中的错误,参见 catch-errors 和 ignore-errors。
Vim({cmdname}):{errmsg}或
Vim:{errmsg}
{cmdname}
是失败的命令名称;当命令名称未知时,使用第二种形式。{errmsg}
是错误消息,通常在 try 条件语句之外发生错误时产生。它总是以大写字母“E”开头,后跟两位或三位数字的错误号,一个冒号和一个空格。:unlet novar通常会产生错误消息
E108: No such variable: "novar"在 try 条件语句中转换为异常
Vim(unlet):E108: No such variable: "novar"命令
:dwim通常会产生错误消息
E492: Not an editor command: dwim在 try 条件语句中转换为异常
Vim:E492: Not an editor command: dwim你可以通过以下方法捕获所有“:unlet”错误
:catch /^Vim(unlet):/或通过以下方法捕获所有拼写错误的命令名称的错误
:catch /^Vim:E492:/某些错误消息可能由不同的命令产生
:function nofunc和
:delfunction nofunc都分别生成错误消息
E128: Function name must start with a capital: nofunc在 try 条件语句中转换为异常
Vim(function):E128: Function name must start with a capital: nofunc或
Vim(delfunction):E128: Function name must start with a capital: nofunc你可以通过其编号独立于导致它的命令捕获错误,如果你使用以下模式
:catch /^Vim(\a\+):E128:/某些命令,如
:let x = novar会产生多个错误消息,这里是
E121: Undefined variable: novar E15: Invalid expression: novar由于它是最具体的错误消息(参见 except-several-errors),因此仅使用第一个消息作为异常值。因此,你可以通过以下方式捕获它
:catch /^Vim(\a\+):E121:/你可以通过以下方式捕获与名称“nofunc”相关的错误
:catch /\<nofunc\>/你可以通过以下方式捕获“:write”和“:read”命令的所有 Vim 错误
:catch /^Vim(\(write\|read\)):E\d\+:/你可以通过以下模式捕获所有 Vim 错误
:catch /^Vim\((\a\+)\)\=:E\d\+:/
:catch /No such variable/仅在英文区域设置中有效,但在用户通过 :language 命令选择其他语言时无效。但是,在注释中引用消息文本很有帮助
:catch /^Vim(\a\+):E108:/ " No such variable
:try : write :catch :endtry但是强烈建议你不要使用这种简单形式,因为它可能捕获比你想要的更多错误。对于“:write”命令,某些自动命令可能会执行并导致与写入无关的错误,例如
:au BufWritePre * unlet novar甚至可能存在你作为脚本编写者无法负责的此类错误:你的脚本的用户可能已定义了此类自动命令。然后,你将向用户隐藏错误。使用以下方法要好得多
:try : write :catch /^Vim(write):/ :endtry它只捕获真正的写入错误。因此,只捕获你想要故意忽略的错误。
:silent! nunmap k这在 try 条件语句处于活动状态时也有效。
CTRL-C
)将转换为异常“Vim:Interrupt”。你可以像捕获任何异常一样捕获它。然后脚本不会终止。示例:function! TASK1() : sleep 10 :endfunction :function! TASK2() : sleep 20 :endfunction :while 1 : let command = input("Type a command: ") : try : if command == "" : continue : elseif command == "END" : break : elseif command == "TASK1" : call TASK1() : elseif command == "TASK2" : call TASK2() : else : echo "\nIllegal command:" command : continue : endif : catch /^Vim:Interrupt$/ : echo "\nCommand interrupted" : " Caught the interrupt. Continue with next prompt. : endtry :endwhile你可以通过按下
CTRL-C
来中断此处的任务;然后,脚本将提示输入新命令。如果你在提示符处按下 CTRL-C
,脚本将终止。:catch /.*/ :catch // :catch捕获所有内容,包括错误异常、中断异常和由 :throw 命令显式抛出的异常。这在脚本的顶层很有用,以便捕获意外情况。示例
:try : : " do the hard work here : :catch /MyException/ : : " handle known problem : :catch /^Vim:Interrupt$/ : echo "Script interrupted" :catch /.*/ : echo "Internal error (" .. v:exception .. ")" : echo " - occurred at " .. v:throwpoint :endtry :" end of script注意:捕获所有内容可能会捕获比你想要的更多内容。因此,强烈建议你仅捕获可以真正处理的问题,方法是为“:catch”指定模式参数。示例:捕获所有内容可能会使通过按下
CTRL-C
来中断脚本变得几乎不可能。:while 1 : try : sleep 1 : catch : endtry :endwhile
:autocmd User x try :autocmd User x throw "Oops!" :autocmd User x catch :autocmd User x echo v:exception :autocmd User x endtry :autocmd User x throw "Arrgh!" :autocmd User x echo "Should not be displayed" : :try : doautocmd User x :catch : echo v:exception :endtry这将显示“Oops!”和“Arrgh!”。
:autocmd BufWritePre * throw "FAIL" :autocmd BufWritePre * echo "Should not be displayed" : :try : write :catch : echo "Caught:" v:exception "from" v:throwpoint :endtry这里,“:write”命令不会写入当前正在编辑的文件(你可以通过检查 'modified' 来查看),因为 BufWritePre 自动命令的异常放弃了“:write”。然后捕获异常,脚本将显示
Caught: FAIL from BufWrite Auto commands for "*"
:autocmd BufWritePost * echo "File successfully written!" : :try : write /i/m/p/o/s/s/i/b/l/e :catch : echo v:exception :endtry这只会显示
Vim(write):E212: Can't open file for writing (/i/m/p/o/s/s/i/b/l/e)如果你真的需要在主要操作失败时执行自动命令,请从 catch 子句中触发事件。示例
:autocmd BufWritePre * set noreadonly :autocmd BufWritePost * set readonly : :try : write /i/m/p/o/s/s/i/b/l/e :catch : doautocmd BufWritePost /i/m/p/o/s/s/i/b/l/e :endtry
:let x = "ok" :let v:errmsg = "" :autocmd BufWritePost * if v:errmsg != "" :autocmd BufWritePost * let x = "after fail" :autocmd BufWritePost * endif :try : silent! write /i/m/p/o/s/s/i/b/l/e :catch :endtry :echo x这将显示“after fail”。
:autocmd BufWritePost * throw ":-(" :autocmd BufWritePost * echo "Should not be displayed" : :try : write :catch : echo v:exception :endtry
:if !exists("cnt") : let cnt = 0 : : autocmd BufWriteCmd * if &modified : autocmd BufWriteCmd * let cnt = cnt + 1 : autocmd BufWriteCmd * if cnt % 3 == 2 : autocmd BufWriteCmd * throw "BufWriteCmdError" : autocmd BufWriteCmd * endif : autocmd BufWriteCmd * write | set nomodified : autocmd BufWriteCmd * if cnt % 3 == 0 : autocmd BufWriteCmd * throw "BufWriteCmdError" : autocmd BufWriteCmd * endif : autocmd BufWriteCmd * echo "File successfully written!" : autocmd BufWriteCmd * endif :endif : :try : write :catch /^BufWriteCmdError$/ : if &modified : echo "Error on writing (file contents not changed)" : else : echo "Error after writing" : endif :catch /^Vim(write):/ : echo "Error on writing" :endtry当在进行更改后多次源此脚本时,它将首先显示
File successfully written!然后
Error on writing (file contents not changed)然后
Error after writing等。
:autocmd BufWritePre * try : :autocmd BufWritePost * catch :autocmd BufWritePost * echo v:exception :autocmd BufWritePost * endtry : :write
:function! CheckRange(a, func) : if a:a < 0 : throw "EXCEPT:MATHERR:RANGE(" .. a:func .. ")" : endif :endfunction : :function! Add(a, b) : call CheckRange(a:a, "Add") : call CheckRange(a:b, "Add") : let c = a:a + a:b : if c < 0 : throw "EXCEPT:MATHERR:OVERFLOW" : endif : return c :endfunction : :function! Div(a, b) : call CheckRange(a:a, "Div") : call CheckRange(a:b, "Div") : if (a:b == 0) : throw "EXCEPT:MATHERR:ZERODIV" : endif : return a:a / a:b :endfunction : :function! Write(file) : try : execute "write" fnameescape(a:file) : catch /^Vim(write):/ : throw "EXCEPT:IO(" .. getcwd() .. ", " .. a:file .. "):WRITEERR" : endtry :endfunction : :try : : " something with arithmetic and I/O : :catch /^EXCEPT:MATHERR:RANGE/ : let function = substitute(v:exception, '.*(\(\a\+\)).*', '\1', "") : echo "Range error in" function : :catch /^EXCEPT:MATHERR/ " catches OVERFLOW and ZERODIV : echo "Math error" : :catch /^EXCEPT:IO/ : let dir = substitute(v:exception, '.*(\(.\+\),\s*.\+).*', '\1', "") : let file = substitute(v:exception, '.*(.\+,\s*\(.\+\)).*', '\1', "") : if file !~ '^/' : let file = dir .. "/" .. file : endif : echo 'I/O error for "' .. file .. '"' : :catch /^EXCEPT/ : echo "Unspecified error" : :endtryVim 本身(在发生错误或按下
CTRL-C
时)引发的异常使用扁平层次结构:它们都在“Vim”类中。你不能自己抛出以“Vim”为前缀的异常;它们是为 Vim 保留的。Vim 错误异常使用失败的命令名称进行参数化(如果已知)。参见 catch-errors。:try : try : throw 4711 : catch /\(/ : echo "in catch with syntax error" : catch : echo "inner catch-all" : finally : echo "inner finally" : endtry :catch : echo 'outer catch-all caught "' .. v:exception .. '"' : finally : echo "outer finally" :endtry这会显示
inner finally outer catch-all caught "Vim(catch):E54: Unmatched \(" outer finally原始异常将被丢弃,取而代之的是抛出错误异常。
:try | unlet! foo # | catch | endtry为 ":unlet!" 参数后的尾随字符引发错误异常,但不会识别 ":catch" 和 ":endtry" 命令,因此错误异常被丢弃,并且显示 "E488: Trailing characters" 消息。
echo novar导致
E121: Undefined variable: novar E15: Invalid expression: novartry 条件语句中的错误异常的值为
Vim(echo):E121: Undefined variable: novar
unlet novar #导致
E108: No such variable: "novar" E488: Trailing characterstry 条件语句中的错误异常的值为
Vim(unlet):E488: Trailing characters之所以这样做是因为语法错误可能会以用户意想不到的方式改变执行路径。示例
try try | unlet novar # | catch | echo v:exception | endtry catch /.*/ echo "outer catch:" v:exception endtry这将显示 "outer catch: Vim(unlet):E488: Trailing characters",然后给出 "E600: Missing :endtry" 错误消息,请参见 except-single-line。
:" The function Nr2Bin() returns the binary string representation of a number. :func Nr2Bin(nr) : let n = a:nr : let r = "" : while n : let r = '01'[n % 2] .. r : let n = n / 2 : endwhile : return r :endfunc :" The function String2Bin() converts each character in a string to a :" binary string, separated with dashes. :func String2Bin(str) : let out = '' : for ix in range(strlen(a:str)) : let out = out .. '-' .. Nr2Bin(char2nr(a:str[ix])) : endfor : return out[1:] :endfunc使用示例
:echo Nr2Bin(32)结果:"100000"
:echo String2Bin("32")结果:"110011-110010"
:func SortBuffer() : let lines = getline(1, '$') : call sort(lines, function("Strcmp")) : call setline(1, lines) :endfunction作为单行代码
:call setline(1, sort(getline(1, '$'), function("Strcmp")))
:" Set up the match bit :let mx='\(\f\+\),\s*\(\d\+\),\s*\(\d\+\)' :"get the part matching the whole expression :let l = matchstr(line, mx) :"get each item out of the match :let file = substitute(l, mx, '\1', '') :let lnum = substitute(l, mx, '\2', '') :let col = substitute(l, mx, '\3', '')输入在变量 "line" 中,结果在变量 "file","lnum" 和 "col" 中。(想法来自 Michael Geddes)
:scriptnames
命令可用于获取已加载的所有脚本文件的列表。还有 getscriptinfo()
函数,但返回的信息并不完全相同。如果你需要操作 scriptnames
的输出,可以使用这段代码" Get the output of ":scriptnames" in the scriptnames_output variable. let scriptnames_output = '' redir => scriptnames_output silent scriptnames redir END " Split the output into lines and parse each line. Add an entry to the " "scripts" dictionary. let scripts = {} for line in split(scriptnames_output, "\n") " Only do non-blank lines. if line =~ '\S' " Get the first number in the line. let nr = matchstr(line, '\d\+') " Get the file name, remove the script number " 123: ". let name = substitute(line, '.\+:\s*', '', '') " Add an item to the Dictionary let scripts[nr] = name endif endfor unlet scriptnames_output
'foldexpr'
,'formatexpr'
,'includeexpr'
,'indentexpr'
,'statusline'
和 'foldtext'
选项可以在沙箱中进行评估。这意味着你免受这些表达式产生负面副作用的影响。这为从模式行设置这些选项提供了一些安全性。它也用于从标签文件执行命令以及在命令行中执行 CTRL-R
=。沙盒也用于 :sandbox
命令。i_CTRL-R_=
,c_CTRL-\_e
,quote=
中输入的表达式由内置表达式解析器进行突出显示。它使用下面表格中描述的突出显示组,这些组可以被配色方案覆盖。hl-NvimInvalidError
的 NvimInvalid,并且还存在一些其他中间组。=
在 :let
中 hl-NvimAugmentedAssignment NvimAssignment 通用,+=
/`-=`/`.=` hl-NvimAssignmentWithAddition NvimAugmentedAssignment +=
在 :let+=
中 hl-NvimAssignmentWithSubtraction NvimAugmentedAssignment -=
在 :let-=
中 hl-NvimAssignmentWithConcatenation NvimAugmentedAssignment .=
在 :let.=
中expr-unary-+
hl-NvimUnaryMinus NvimUnaryOperator expr-unary--
hl-NvimNot NvimUnaryOperator expr-!
expr4
运算符 hl-NvimComparisonModifier NvimComparison #
/`?` 靠近 expr4
运算符 hl-NvimBinaryPlus NvimBinaryOperator expr-+
hl-NvimBinaryMinus NvimBinaryOperator expr--
hl-NvimConcat NvimBinaryOperator expr-.
hl-NvimConcatOrSubscript NvimConcat expr-.
或 expr-entry
hl-NvimOr NvimBinaryOperator expr-barbar
hl-NvimAnd NvimBinaryOperator expr-&&
hl-NvimMultiplication NvimBinaryOperator expr-star
hl-NvimDivision NvimBinaryOperator expr-/
hl-NvimMod NvimBinaryOperator expr-%
{
/`}` 在 lambda
中 hl-NvimNestingParenthesis NvimParenthesis (
/`)` 在 expr-nesting
中 hl-NvimCallingParenthesis NvimParenthesis (
/`)` 在 expr-function
中[
/`]` 在 expr-[]
中 hl-NvimSubscriptColon NvimSubscript :
在 expr-[:]
中 hl-NvimCurly NvimSubscript {
/`}` 在 curly-braces-names
中{
/`}` 在 dict
字面量中 hl-NvimList NvimContainer [
/`]` 在 list
字面量中internal-variables
中的 :
之前的字母 hl-NvimIdentifierScopeDelimiter NvimIdentifier 命名空间字母后的 :
hl-NvimIdentifierName NvimIdentifier 标识符的剩余部分 hl-NvimIdentifierKey NvimIdentifier expr-entry
后的标识符:
在 dict 字面量中 hl-NvimComma 分隔符 ,
在 dict 或 list 字面量或 expr-function 中 hl-NvimArrow 分隔符 ->
在 lambda 中0
用于 octal-number 0x
用于 hex-number 0b
用于 binary-number hl-NvimFloat NvimNumber 浮点数&
在 expr-option 中 hl-NvimOptionScope NvimIdentifierScope 选项范围(如果有) hl-NvimOptionScopeDelimiter NvimIdentifierScopeDelimiter :
位于选项范围之后 hl-NvimOptionName NvimIdentifier 选项名称'
在 expr-' 中 hl-NvimSingleQuotedBody NvimStringBody expr-' 字符串主体的字面量部分 hl-NvimSingleQuotedQuote NvimStringSpecial ''
在 expr-' 字符串主体内部"
在 expr-quote 中 hl-NvimDoubleQuotedBody NvimStringBody expr-quote 主体的字面量部分 hl-NvimDoubleQuotedEscape NvimStringSpecial 有效的 expr-quote 转义序列 hl-NvimDoubleQuotedUnknownEscape NvimInvalidValue 无法识别的 expr-quote 转义序列