Eval

Nvim 的 :help 頁面,是透過 產生原始碼,並使用 tree-sitter-vimdoc 解析器。


表達式求值 expression expr E15 eval
表達式的使用介紹於使用者手冊的第 41 章 usr_41.txt

1. 變數 variables

1.1 變數類型
E712 E896 E897 E899 變數共有七種類型
Number Integer 數字:一個 32 或 64 位元的帶符號數字。expr-number 位元數可透過 v:numbersize 取得。範例:-123 0x10 0177 0o177 0b1011
浮點數:一個浮點數。floating-point-format Float 範例:123.456 1.15e-6 -1.1e3
字串:一個以 NUL 結尾的 8 位元無符號字元(位元組)字串。expr-string 範例:"ab\txx\"--" 'x-z''a,c'
函數參考:一個函數的參考 Funcref。範例:function("strlen") 可以綁定到字典和參數,然後就像 Partial 一樣運作。範例:function("Callback", [arg], myDict)
列表:一個項目的有序序列,詳情請見 List。範例:[1, 2, ['a', 'b']]
字典:一個關聯的、無序的陣列:每個條目都有一個鍵和一個值。Dictionary 範例
{"blue": "#0000ff", "red": "#ff0000"}
#{blue: "#0000ff", red: "#ff0000"}
Blob:二進位大型物件。儲存任何位元組序列。詳情請見 Blob。範例:0zFF00ED015DAF 0z 是一個空的 Blob。
數字和字串類型會根據它們的使用方式自動轉換。
從數字轉換為字串是透過建立該數字的 ASCII 表示形式來完成的。範例
數字 123 --> 字串 "123"
數字 0 --> 字串 "0"
數字 -1 --> 字串 "-1"
八進制
從字串轉換為數字是透過將前幾個數字轉換為數字來完成的。可以識別十六進制 "0xf9"、八進制 "017" 或 "0o17" 和二進制 "0b10" 數字。如果字串不是以數字開頭,則結果為零。範例
字串 "456" --> 數字 456
字串 "6bar" --> 數字 6
字串 "foo" --> 數字 0
字串 "0xf1" --> 數字 241
字串 "0100" --> 數字 64
字串 "0o100" --> 數字 64
字串 "0b101" --> 數字 5
字串 "-8" --> 數字 -8
字串 "+8" --> 數字 0
要強制將字串轉換為數字,請將其加上零
:echo "0100" + 0
64
為了避免前導零導致八進制轉換,或者使用不同的進制,請使用 str2nr()
TRUE FALSE Boolean 對於布林運算子,會使用數字。零為 FALSE,非零為 TRUE。您也可以使用 v:falsev:true。當函數返回 TRUE 時,它會是數字 1,而 FALSE 則是數字零。
請注意在命令中
:if "foo"
:" NOT executed
"foo" 會轉換為 0,表示 FALSE。如果字串是以非零數字開頭,則表示 TRUE
:if "8foo"
:" executed
要測試字串是否為空,請使用 empty()
:if !empty("foo")
falsy truthy 表達式可以用作條件,忽略類型,僅使用該值是否「有點真」或「有點假」。Falsy 是:數字零,空字串、blob、列表或字典。其他值是 truthy。範例:0 falsy 1 truthy -1 truthy 0.0 falsy 0.1 truthy '' falsy 'x' truthy [] falsy [0] truthy {} falsy #{x: 1} truthy 0z falsy 0z00 truthy
非零參數
函數參數的行為通常與 TRUE 略有不同:如果參數存在且求值為非零數字、v:true 或非空字串,則該值會被視為 TRUE。請注意," " 和 "0" 也是非空字串,因此被視為 TRUE。列表、字典或浮點數不是數字或字串,因此求值為 FALSE。
E745 E728 E703 E729 E730 E731 E974 E975 E976 列表字典函數參考Blob 類型不會自動轉換。
E805 E806 E808 當混合數字和浮點數時,數字會轉換為浮點數。否則,不會自動轉換浮點數。您可以使用 str2float() 將字串轉換為浮點數,printf() 將浮點數轉換為字串,以及 float2nr() 將浮點數轉換為數字。
E362 E891 E892 E893 E894 E907 當預期為浮點數時,也可以使用數字,但不能使用其他任何類型。
無類型檢查
如果您嘗試變更變數的類型,不會收到錯誤。
1.2 函數參考
Funcref E695 E718 E1192 函數參考變數是透過 function() 函數、funcref() 函數取得,或是透過 lambda 表達式 expr-lambda 建立。它可以在表達式中使用,以代替函數名稱,在參數周圍的括號之前,來調用它所引用的函數。範例
:let Fn = function("MyFunc")
:echo Fn()
E704 E705 E707 函數參考變數必須以大寫字母 "s:"、"w:"、"t:" 或 "b:" 開頭。您可以使用 "g:",但後面的名稱仍必須以大寫字母開頭。您不能同時擁有函數參考變數和同名的函數。
一個特殊情況是定義一個函數並直接將其函數參考指派給字典條目。範例
: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)
Partial
函數參考可以選擇性地綁定字典和/或參數。這也稱為 Partial。這是透過將字典和/或參數傳遞給 function() 或 funcref() 來建立的。當調用該函數時,字典和/或參數將會傳遞給該函數。範例
let Cb = function('Callback', ['foo'], myDict)
call Cb('bar')
這將調用該函數,如同使用
call myDict.Callback('foo', 'bar')
請注意,當函數是字典的成員時,也會發生將函數綁定到字典的情況
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",因為它是被明確綁定的。
1.3 列表
list 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]                " 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
負索引是從末尾開始計算的。索引 -1 是指列表中的最後一個項目,-2 是指倒數第二個項目,依此類推。
:let last = mylist[-1]                " get the last item: "four"
為了避免因無效索引而產生錯誤,請使用 get() 函數。當項目不可用時,它會返回零或您指定的預設值
:echo get(mylist, idx)
:echo get(mylist, idx, "NONE")
列表串連
list-concatenation
可以使用 "+" 運算子將兩個列表串連在一起
:let longlist = mylist + [5, 6]
:let longlist = [5, 6] + mylist
要前置或附加一個項目,請將其放入 [] 中以將其轉換為列表。
可以使用 :let+=extend() 將一個列表與另一個列表就地串連在一起
:let mylist += [7, 8]
:call extend(mylist, [7, 8])
有關就地變更列表的更多資訊,請參閱下方的 list-modification
子列表
sublist
可以透過在方括號中指定第一個和最後一個索引(以冒號分隔)來取得列表的一部分
: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() 方法。
如果第一個索引超出列表的最後一個項目,或者第二個項目在第一個項目之前,則結果為空列表。沒有錯誤訊息。
如果第二個索引等於或大於列表的長度,則會使用長度減 1
:let mylist = [0, 1, 2, 3]
:echo mylist[2:8]                " result: [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()。這也會遞迴地複製列表中值的副本,最多可達一百層深度。
運算符 "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" 將會是一個空列表。
列表修改
列表修改
若要變更列表的特定項目,請使用 :let,方法如下:
:let list[4] = "four"
:let listlist[0][3] = item
若要變更列表的一部分,您可以指定要修改的第一個和最後一個項目。該值必須至少具有範圍內的項目數量。
:let list[3:5] = [3, 4, 5]
若要在列表中就地加入項目,您可以使用 :let+= ( 列表串接)
: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 迴圈
:for 迴圈會對 列表字串Blob 中的每個項目執行命令。一個變數會依序設定為每個項目。以下為列表的範例:
: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 迴圈更簡單。
如同 :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
對於 Blob,則會一次使用一個位元組。
對於字串,則會使用一個字元,包括任何組合字元,作為字串。範例
for c in text
  echo 'This character is ' .. c
endfor
列表函數
E714
可與列表搭配使用的實用函數
: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, '+')
1.4 字典
Dict dict Dictionaries Dictionary 字典是一種關聯陣列:每個項目都有一個鍵和一個值。可以使用鍵來定位項目。這些項目會以沒有特定順序的方式儲存。
字典建立
E720 E721 E722 E723 字典是使用在大括號中以逗號分隔的項目列表建立的。每個項目都有一個鍵和一個值,以冒號分隔。每個鍵只能出現一次。範例
:let mydict = {1: 'one', 2: 'two', 3: 'three'}
:let emptydict = {}
E713 E716 E717 鍵始終是字串。您可以使用數字,它會自動轉換為字串。因此,字串 '4' 和數字 4 會找到相同的項目。請注意,字串 '04' 和數字 04 是不同的,因為該數字會轉換為字串 '4',開頭的零會被捨棄。空字串也可以用作鍵。literal-Dict #{} 為了避免在每個鍵的周圍加上引號,可以使用 #{} 形式。這確實需要鍵僅由 ASCII 字母、數字、'-' 和 '_' 組成。範例
: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
您可以使用這種方式將新項目新增至現有的字典,這與列表不同。
對於完全由字母、數字和底線組成的鍵,可以使用以下形式 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
字典的識別
字典識別
就像列表一樣,您需要使用 copy()deepcopy() 來建立字典的副本。否則,賦值會導致指向同一個字典。
:let onedict = {'a': 1, 'b': 2}
:let adict = onedict
:let adict['a'] = 11
:echo onedict['a']
11
如果所有鍵值對都相等,則兩個字典會被視為相等。如需更多資訊,請參閱 列表識別
字典修改
字典修改
若要變更字典中已存在的項目或新增項目,請使用 :let,方法如下:
: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 中的項目。
從字典中篩選出項目可以使用 filter() 完成:
:call filter(dict, 'v:val =~ "x"')
這會從 "dict" 中移除所有值與 'x' 不符的項目。這也可以用來移除所有項目:
call filter(dict, 0)
字典函數
Dictionary-function self E725 E862 當使用 "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" 屬性的函數作為 Funcref 新增至字典,但屆時 "self" 變數不可用。
numbered-function anonymous-function 為了避免函數的額外名稱,可以透過以下方式定義函數並直接將其指派給字典:
:let mydict = {'data': [0, 1, 2, 3]}
:function mydict.len()
:   return len(self.data)
:endfunction
:echo mydict.len()
然後函數會取得一個數字,而 dict.len 的值會是一個 Funcref,指向此函數。該函數只能透過 Funcref 使用。當沒有任何 Funcref 指向它時,它會自動刪除。
對於編號函數,不需要使用 "dict" 屬性。
如果您因為編號函數而收到錯誤,您可以透過一個技巧找出錯誤。假設該函數是 42,則該命令是:
:function g:42
字典的函數
E715
可以與字典搭配使用的函數
: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
1.5 Blobs
blob Blob Blobs E978 Blob 是一種二進位物件。例如,它可以用於從檔案讀取影像並透過管道傳送影像。
Blob 的行為大多類似於數字的 列表,其中每個數字都有一個 8 位元組的值,從 0 到 255。
Blob 建立
Blob 可以使用 blob-literal 建立:
:let b = 0zFF00ED015DAF
為了提高可讀性,可以在位元組之間(成對的十六進位字元)插入點號,它們不會變更值:
:let b = 0zFF00.ED01.5DAF
可以使用 readfile() 從檔案讀取 blob,例如,將 {type} 引數設定為 "B":
:let b = readfile('image.png', 'B')
Blob 索引
blob-index E979 可以透過將索引放在 Blob 後面的方括號中來存取 Blob 中的位元組。索引是以零為基礎的,因此第一個位元組的索引為零。
: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)
Blob 迭代
:for 迴圈會對 Blob 的每個位元組執行命令。迴圈變數會設定為 Blob 中的每個位元組。範例:
:for byte in 0z112233
:   call Doit(byte)
:endfor
這會使用 0x11、0x22 和 0x33 呼叫 Doit()。
Blob 串接
blob 串接
可以使用 "+" 運算符串接兩個 blob:
:let longblob = myblob + 0z4455
:let longblob = 0z4455 + myblob
可以使用 :let+= 就地將 blob 與另一個 blob 串接:
:let myblob += 0z6677
如需更多關於就地變更 blob 的資訊,請參閱下方的 blob 修改
Blob 的一部分
可以透過在方括號中指定第一個和最後一個索引 (以冒號分隔) 來取得 Blob 的一部分:
: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。沒有錯誤訊息。
如果第二個索引等於或大於 Blob 的長度,則會使用長度減一。
:echo myblob[2:8]                " result: 0z2233
Blob 修改
blob 修改
若要變更 blob 的特定位元組,請使用 :let,方法如下:
:let blob[4] = 0x44
當索引剛好超出 Blob 的末尾一個時,則會附加它。任何更高的索引都會產生錯誤。
若要變更位元組序列,可以使用 [:] 表示法:
let blob[1:3] = 0z445566
取代的位元組長度必須與提供的值完全相同。E972
若要變更 Blob 的一部分,您可以指定要修改的第一個和最後一個位元組。該值必須與該範圍內的位元組數相同
:let blob[3:5] = 0z334455
若要就地將項目新增至 Blob,您可以使用 :let+= (blob 連接)
:let blobA = 0z1122
:let blobA += 0z3344
當兩個變數參考同一個 Blob 時,就地變更其中一個 Blob 會導致參考的 Blob 也就地變更
:let blobA = 0z1122
:let blobB = blobA
:let blobB += 0z3344
:echo blobA
0z11223344
您也可以使用函式 add()remove()insert()
Blob 識別
可以比較 Blob 是否相等
if blob == 0z001122
以及是否具有相同的識別
if blob is otherblob
blob-identity E977 當變數 "aa" 是一個 Blob,而您將其指派給另一個變數 "bb" 時,兩個變數都會參考同一個 Blob。然後 "is" 運算子會傳回 true。
當使用 [:] 或 copy() 建立副本時,值會相同,但識別不同
:let blob = 0z112233
:let blob2 = blob
:echo blob == blob2
1
:echo blob is blob2
1
:let blob3 = blob[:]
:echo blob == blob3
1
:echo blob is blob3
0
Blob 的副本是使用 copy() 函式建立的。如上所述,使用 [:] 也會起作用。
1.6 關於變數的更多資訊
more-variables
如果您需要知道變數或表達式的類型,請使用 type() 函式。
'shada' 選項中包含 '!' 旗標時,以大寫字母開頭且不包含小寫字母的全域變數會儲存在 shada 檔案 shada-file 中。
'sessionoptions' 選項包含 "global" 時,以大寫字母開頭且至少包含一個小寫字母的全域變數會儲存在工作階段檔案 session-file 中。
變數名稱可以儲存在哪裡
my_var_6 不是 My_Var_6 工作階段檔案 MY_VAR_6 shada 檔案
可以使用大括號形成變數名稱,請參閱 curly-braces-names

2. 表達式語法 expression-syntax

表達式語法摘要,從最小到最大重要性排列
expr1 expr2 expr2 ? expr1 : expr1 if-then-else
expr2 expr3 expr3 || expr3 ... 邏輯 OR
expr3 expr4 expr4 && expr4 ... 邏輯 AND
expr4 expr5 expr5 == expr5 等於 expr5 != expr5 不等於 expr5 > expr5 大於 expr5 >= expr5 大於或等於 expr5 < expr5 小於 expr5 <= expr5 小於或等於 expr5 =~ expr5 正則表達式匹配 expr5 !~ expr5 正則表達式不匹配
expr5 ==? expr5 等於,忽略大小寫 expr5 ==# expr5 等於,匹配大小寫等等。如上所述,附加 ? 表示忽略大小寫,# 表示匹配大小寫
expr5 is expr5 相同 ListDictionaryBlob 實例 expr5 isnot expr5 不同 ListDictionaryBlob 實例
expr5 expr6 expr6 + expr6 ... 數字加法、列表或 blob 連接 expr6 - expr6 ... 數字減法 expr6 . expr6 ... 字串連接 expr6 .. expr6 ... 字串連接
expr6 expr7 expr7 * expr7 ... 數字乘法 expr7 / expr7 ... 數字除法 expr7 % expr7 ... 數字取模
expr7 expr8 ! expr7 邏輯 NOT
expr7 一元減號 + expr7 一元加號
expr8 expr9 expr8[expr1] 字串的位元組或 List 的項目 expr8[expr1 : expr1] 字串的子字串或 List 的子列表 expr8.name Dictionary 中的條目 expr8(expr1, ...) 使用 Funcref 變數的函式呼叫 expr8->name(expr1, ...) 方法呼叫
expr9 數字 數字常數 "字串" 字串常數,反斜線是特殊的 '字串' 字串常數,' 加倍 [expr1, ...] List {expr1: expr1, ...} Dictionary #{key: expr1, ...} Dictionary &選項 選項值 (expr1) 巢狀表達式 變數 內部變數 va{ria}ble 帶有大括號的內部變數 $VAR 環境變數 @r 暫存器 "r" 的內容 function(expr1, ...) 函式呼叫 func{ti}on(expr1, ...) 帶有大括號的函式呼叫 {args -> expr1} lambda 表達式
"..." 表示此層級中的運算可以連接。範例
&nu || &list && &shell == "csh"
同一層級內的所有表達式都會從左到右解析。
表達式巢狀結構的深度限制為 1000 層(使用 MSVC 建置時為 300 層),以避免堆疊耗盡並崩潰。 E1169
三元運算子:expr2 ? expr1 : expr1 falsy 運算子:expr2 ?? expr1
三元運算子
'?' 前面的表達式會評估為數字。如果它評估為 TRUE,則結果是 '?' 和 ':' 之間的表達式的值,否則結果是 ':' 之後的表達式的值。範例
:echo lnum == 1 ? "top" : lnum
由於第一個表達式是 "expr2",因此它不能包含另一個 ?:。其他兩個表達式可以,因此允許遞迴使用 ?:。範例
:echo lnum == 1 ? "top" : lnum == 1000 ? "last" : lnum
為了保持可讀性,建議使用 行接續
:echo lnum == 1
:\        ? "top"
:\        : lnum == 1000
:\                ? "last"
:\                : lnum
您應該始終在 ':' 前面放置一個空格,否則可能會誤認為是用於變數(例如 "a:1")中。
Falsy 運算子
這也稱為「null 聯合運算子」,但這太複雜了,因此我們僅將其稱為 falsy 運算子。
會評估 '??' 前面的表達式。如果它評估為 truthy,則會將其用作結果。否則,會評估 '??' 後面的表達式並將其用作結果。這對於具有一個可能導致零或空的表達式的預設值最有用
echo theList ?? 'list is empty'
echo GetName() ?? 'unknown'
這些相似,但不相等
expr2 ?? expr1
expr2 ? expr2 : expr1
在第二行中,"expr2" 會被評估兩次。

expr2 和 expr3 expr2 expr3

expr3 || expr3 .. 邏輯 OR expr-barbar
expr4 && expr4 .. 邏輯 AND expr-&&
"||" 和 "&&" 運算子在每一側都採用一個引數。引數會(轉換為)數字。結果為
輸入 輸出
n1 n2 n1 || n2 n1 && n2
FALSE FALSE FALSE FALSE FALSE TRUE TRUE FALSE TRUE FALSE TRUE FALSE TRUE TRUE TRUE TRUE
可以連接運算子,例如
&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" 的情況下才會評估第二個子句。

expr4 expr4

expr5 {cmp} expr5
比較兩個 expr5 表達式,如果評估為 false,則結果為 0;如果評估為 true,則結果為 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 expr-isnot expr-is# expr-isnot# expr-is? expr-isnot?
使用 'ignorecase' 匹配大小寫 忽略大小寫
等於 == ==# ==? 不等於 != !=# !=? 大於 > ># >? 大於或等於 >= >=# >=? 小於 < <# <? 小於或等於 <= <=# <=? 正則表達式匹配 =~ =~# =~? 正則表達式不匹配 !~ !~# !~? 相同實例 is is# is? 不同實例 isnot isnot# isnot?
範例:"abc" ==# "Abc" 評估為 0 "abc" ==? "Abc" 評估為 1 如果設定了 'ignorecase',則 "abc" == "Abc" 評估為 1,否則評估為 0
E691 E692 List 只能與 List 比較,且只能使用「等於」、「不等於」、「is」和「isnot」。這會遞迴比較列表的值。忽略大小寫表示比較項目值時會忽略大小寫。
E735 E736 字典只能與另一個字典比較,且只能使用 "等於"、"不等於"、"是" 和 "不是"。這會遞迴地比較字典的鍵/值。忽略大小寫表示比較項目值時忽略大小寫。
E694
函式參照只能與另一個函式參照比較,且只能使用 "等於"、"不等於"、"是" 和 "不是"。永遠不會忽略大小寫。是否有綁定引數或字典(使用 partial)很重要。字典也必須相等(或在 "是" 的情況下相同),引數也必須相等(或相同)。
要比較函式參照以查看它們是否指向相同的函式,忽略綁定的字典和引數,請使用 get() 取得函式名稱
if get(Part1, 'name') == get(Part2, 'name')
   " Part1 and Part2 refer to the same function
將 "是" 或 "不是" 用於 列表字典Blob 會檢查表達式是否指向相同的 列表字典Blob 實例。列表的副本與原始 列表 不同。當在未使用 列表字典Blob 的情況下使用 "是" 時,它等同於使用 "等於",使用 "不是" 等同於使用 "不等於"。但不同的類型表示值不同
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
在列表或字典中,不會使用此轉換。
當比較兩個字串時,會使用 strcmp() 或 stricmp() 進行。這會導致數學上的差異(比較位元組值),而不一定是當地語言的字母差異。
當使用帶有尾隨 '#' 的運算符,或者使用簡短版本且 'ignorecase' 關閉時,比較會使用 strcmp() 進行:大小寫很重要。
當使用帶有尾隨 '?' 的運算符,或者使用簡短版本且 'ignorecase' 設定時,比較會使用 stricmp() 進行:大小寫會被忽略。
'smartcase' 不會被使用。
"=~" 和 "!~" 運算符會將左側引數與右側引數進行匹配,右側引數會被當作模式使用。有關模式的定義,請參閱 pattern。此匹配總是像設定 'magic''cpoptions' 為空一樣進行,無論 'magic''cpoptions' 的實際值為何。這使得腳本具有可移植性。為了避免在 regexp 模式中將反斜線加倍,請使用單引號字串,請參閱 literal-string。由於字串被認為是單行,因此多行模式(包含 \n,反斜線-n)將不會匹配。但是,可以像匹配普通字元一樣匹配文字 NL 字元。範例:"foo\nbar" =~ "\n" 的計算結果為 1 "foo\nbar" =~ "\\n" 的計算結果為 0

expr5 和 expr6 expr5 expr6

expr6 + expr6 數字加法,列表Blob 連接 expr-+ expr6 - expr6 數字減法 expr--
expr6 . expr6 字串連接 expr-.
expr6 .. expr6 字串連接 expr-..
對於 列表,僅允許使用 "+",且兩個 expr6 都必須是列表。結果是一個新的列表,其中包含兩個連接的列表。
對於字串連接,建議使用 "..",因為 "." 具有二義性,它也用於 Dict 成員存取和浮點數。
expr7 * expr7 數字乘法 expr-star
expr7 / expr7 數字除法 expr-/
expr7 % expr7 數字模數 expr-%
對於除了 "." 和 ".." 之外的所有運算符,字串都會轉換為數字。對於位元運算符,請參閱 and()or()xor()
請注意 "+" 和 "." 之間的差異:"123" + "456" = 579 "123" . "456" = "123456"
由於 '.' 的優先順序與 '+' 和 '-' 相同,因此您需要讀取
1 . 90 + 90.0
作為
(1 . 90) + 90.0
這有效,因為字串 "190" 會自動轉換為數字 190,可以將其加到浮點數 90.0。然而
1 . 90 * 90.0
應讀取為
1 . (90 * 90.0)
因為 '.' 的優先順序低於 "*"。這不起作用,因為這嘗試將浮點數和字串連接。
當數字除以零時,結果取決於該值:0 / 0 = -0x80000000(類似於浮點數的 NaN)>0 / 0 = 0x7fffffff(類似於正無限大)<0 / 0 = -0x7fffffff(類似於負無限大)(在 Vim 7.2 之前,它總是 0x7fffffff)
當啟用 64 位元數字支援時:0 / 0 = -0x8000000000000000(類似於浮點數的 NaN)>0 / 0 = 0x7fffffffffffffff(類似於正無限大)<0 / 0 = -0x7fffffffffffffff(類似於負無限大)
當 '%' 的右側為零時,結果為 0。
這些都不適用於 函式參照
. 和 % 不適用於浮點數。 E804

expr7 expr7

! expr7 邏輯 NOT expr-!
expr7 一元負號 expr-unary--
+ expr7 一元正號 expr-unary-+
對於 '!',TRUE 變為 FALSEFALSE 變為 TRUE (一)。對於 '-',數字的符號會被更改。對於 '+',數字保持不變。注意: "++" 無效。
字串將首先轉換為數字。
這三者可以重複和混合。範例:!-1 == 0 !!8 == 1 --9 == 9

expr8 expr8

此表達式可以是 expr9,也可以是以下替代項的序列,順序不限。例如,這些都是可能的:expr8[expr1].name expr8.name[expr1] expr8(expr1, ...)[expr1].name expr8->(expr1, ...)[expr1] 計算始終從左到右進行。
expr8[expr1] 字串或 列表的項目 expr-[] E111 subscript
在舊版 Vim 腳本中:如果 expr8 是數字或字串,則結果會是一個字串,其中包含來自 expr8 的第 expr1 個單一位元組。expr8 會被當作字串使用(數字會自動轉換為字串),expr1 會被當作數字使用。這不會識別多位元組編碼,請參閱 byteidx() 以取得替代方法,或者使用 split() 將字串轉換為字元列表。範例,取得游標下的位元組
:let c = getline(".")[col(".") - 1]
索引零會提供第一個位元組。這類似於 C 中的工作方式。請注意:文字欄位數字從一開始!範例,取得游標下的位元組
:let c = getline(".")[col(".") - 1]
索引零會提供第一個位元組。請注意:文字欄位數字從一開始!
如果字串的長度小於索引,則結果會是空字串。負索引總是產生空字串(原因:向後相容性)。使用 [-1:] 取得最後一個位元組。
如果 expr8 是 列表,則會產生索引 expr1 處的項目。有關可能的索引值,請參閱 list-index。如果索引超出範圍,則會產生錯誤。範例
:let item = mylist[-1]                " get last item
通常,如果 列表索引等於或高於 列表的長度,或者比 列表的長度更負,則會產生錯誤。
expr8[expr1a : expr1b] 子字串或子列表 expr-[:] substring
如果 expr8 是字串,則結果會是從 expr1a 到包含 expr1b 的位元組或字元的子字串。expr8 會被當作字串使用,expr1a 和 expr1b 會被當作數字使用。
在舊版 Vim 腳本中,索引是位元組索引。這不會識別多位元組編碼,請參閱 byteidx() 以計算索引。如果 expr8 是數字,則會先將其轉換為字串。
索引 expr1b 處的項目包含在內,它是包含的。對於不包含的索引,請使用 slice() 函式。
如果省略 expr1a,則會使用零。如果省略 expr1b,則會使用字串長度減一。
可以使用負數從字串的末尾開始測量。-1 是最後一個字元,-2 是倒數第二個,依此類推。
如果索引超出字串的範圍,則會省略字元。如果 expr1b 小於 expr1a,則結果會是空字串。
範例
: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
切片
如果 expr8 是 列表,則結果會是一個新的 列表,其中包含索引 expr1a 和 expr1b 指示的項目。這與字串的工作方式相同,如上所述。另請參閱下面的 子列表。範例
: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
函式參照上使用 expr8[expr1] 或 expr8[expr1a : expr1b] 會產生錯誤。
請注意命名空間和變數後接冒號以產生子列表之間的混淆
mylist[n:]     " uses variable n
mylist[s:]     " uses namespace s:, error!
expr8.name 在字典中的條目 expr-entry
如果 expr8 是一個字典,並且後面跟著一個點號,那麼後面的名稱將被用作字典中的鍵。這就像:expr8[name]。
名稱必須由字母數字字符組成,就像變數名稱一樣,但它可以用數字開頭。不能使用大括號。
點號前後不能有空白字元。
範例
: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
請注意,點號也用於字串串接。為避免混淆,請始終在字串串接的點號周圍加上空格。
expr8(expr1, ...) Funcref 函式呼叫 E1085
當 expr8 是Funcref 類型的變數時,會呼叫它所指向的函式。
expr8->name([args]) 方法呼叫 method -> expr8->{lambda}([args])
E260 E276 對於也可以作為全域函式使用的方法,這與以下相同
name(expr8 [, args])
也可能存在專門針對 "expr8" 類型的方法。
這允許鏈式呼叫,將一個方法返回的值傳遞給下一個方法
mylist->filter(filterexpr)->map(mapexpr)->sort()->join()
使用 lambda 的範例
GetPercentage()->{x -> x * 100}()->printf('%d%%')
當使用 -> 時,expr7 運算符將首先被套用,因此
-1.234->string()
等同於
(-1.234)->string()
而不是
-(1.234->string())
E274
"->name(" 不得包含空白字元。"->" 前和 "(" 後面可以有空白字元,因此您可以像這樣分割程式碼行
mylist
\ ->filter(filterexpr)
\ ->map(mapexpr)
\ ->sort()
\ ->join()
當使用 lambda 形式時,} 和之間不得有空白字元

(.

expr9

數字

數字 數字常數 expr-number
0x hex-number 0o octal-number binary-number 十進位、十六進位(以 0x 或 0X 開頭)、二進位(以 0b 或 0B 開頭)和八進位(以 0、0o 或 0O 開頭)。
浮點數格式
浮點數可以寫成兩種形式
[-+]{N}.{M} [-+]{N}.{M}[eE][-+]{exp}
{N}{M} 是數字。{N}{M} 都必須存在,且只能包含數字。[-+] 表示有一個可選的正負號。{exp} 是指數,即 10 的冪次方。只接受小數點,不接受逗號。無論目前的地區設定是什麼。
範例:123.456 +0.0001 55.0 -0.123 1.234e03 1.0E-6 -3.1416e+88
這些是無效的:3. 空的 {M} 1e40 缺少 .{M}
理由:在引入浮點數之前,文字 "123.456" 被解讀為兩個數字 "123" 和 "456",兩者都被轉換為字串並串接,產生字串 "123456"。由於這被認為毫無意義,並且我們沒有發現它在 Vim 指令碼中被有意使用,因此接受了這種向後不相容性,以支持使用浮點數的正常表示法。
float-pi float-e 一些有用的值,可供複製和貼上
:let pi = 3.14159265359
:let e  = 2.71828182846
或者,如果您不想將它們寫成浮點字面值,您也可以使用函式,如下所示
:let pi = acos(-1.0)
:let e  = exp(1.0)
浮點數精度
浮點數的精度和範圍取決於 Vim 編譯時使用的函式庫中 "double" 的含義。無法在執行時更改此設定。
顯示 Float 的預設方式是使用 6 個小數位數,就像使用 printf("%g", f) 一樣。您可以在使用 printf() 函式時選擇其他格式。範例
:echo printf('%.15e', atan(1))
7.853981633974483e-01
"字串" 字串常數 expr-quote
請注意,使用的是雙引號。
字串常數接受以下特殊字符:\... 三位數八進位數字(例如,"\316")\.. 兩位數八進位數字(必須後跟非數字)\. 一位數八進位數字(必須後跟非數字)\x.. 以兩個十六進位數字指定的位元組(例如,"\x1f")\x. 以一個十六進位數字指定的位元組(必須後跟非十六進位字符)\X.. 與 \x.. 相同 \X. 與 \x. 相同 \u.... 以最多 4 個十六進位數字指定的字符,以 UTF-8 格式儲存(例如,"\u02a4")\U.... 與 \u 相同,但允許最多 8 個十六進位數字。\b 退格 <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"。
請注意,"\xff" 儲存為位元組 255,這在某些編碼中可能無效。請使用 "\u00ff" 將字符 255 正確地儲存為 UTF-8。
請注意,"\000" 和 "\x00" 會強制字串結尾。

blob-literal blob-literal E973

以 0z 或 0Z 開頭的十六進位,具有任意數量的位元組。該序列必須是偶數個十六進位字符。範例
:let b = 0zFF00ED015DAF

literal-string literal-string E115

字串 字串常數 expr-'
請注意,使用的是單引號。
此字串按原樣取得。不會刪除或有特殊含義的反斜線。唯一的例外是,兩個引號代表一個引號。
單引號字串對於模式非常有用,因此不需要將反斜線加倍。以下兩個指令是等效的
if a =~ "\\s*"
if a =~ '\s*'

interpolated-string $quote interpolated-string

$"字串" 插值字串常數 expr-$quote
$'字串' 插值字面值字串常數 expr-$'
插值字串是 字串字面值字串 的擴展,允許包含 Vim 指令碼表達式(請參閱 expr1)。任何返回值的表達式都可以用大括號括起來。該值會被轉換為字串。所有文字和表達式的結果都會串接起來以產生一個新字串。E1278
若要在字串內容中包含左大括號 '{' 或右大括號 '}',請將其加倍。對於使用反斜線的雙引號字串也有效。單個右大括號 '}' 會導致錯誤。
範例
let your_name = input("What's your name? ")
你叫什麼名字?彼得
echo
echo $"Hello, {your_name}!"
你好,彼得!
echo $"The square root of {{9}} is {sqrt(9)}"
{9} 的平方根是 3.0
字串偏移編碼
字串由多個字符組成。UTF-8 對於 ASCII 字符使用一個位元組,對於其他拉丁字符使用兩個位元組,對於其他字符使用更多位元組。
字串偏移可以計算字符或位元組。其他程式可能會使用 UTF-16 編碼(16 位元字)和 UTF-16 字的偏移。某些函式使用位元組偏移,通常用於 UTF-8 編碼。其他函式使用字符偏移,在這種情況下,編碼無關緊要。
以下是字串 "a©😊" 的不同偏移
UTF-8 偏移:[0]: 61, [1]: C2, [2]: A9, [3]: F0, [4]: 9F, [5]: 98, [6]: 8A UTF-16 偏移:[0]: 0061, [1]: 00A9, [2]: D83D, [3]: DE0A UTF-32(字符)偏移:[0]: 00000061, [1]: 000000A9, [2]: 0001F60A
您可以使用字符上的 "g8" 和 "ga" 命令來查看十進位/十六進位/八進位值。
函式 byteidx()utf16idx()charidx() 可用於在這些索引之間進行轉換。函式 strlen()strutf16len()strcharlen() 分別傳回字串中的位元組數、UTF-16 程式碼單元數和字符數。
&選項 選項值,如果可能,則為局部值 &g:選項 全域選項值 &l:選項 局部選項值
範例
echo "tabstop is " .. &tabstop
if &expandtab
此處可以使用任何選項名稱。請參閱 選項。當使用局部值且沒有緩衝區局部值或視窗局部值時,仍會使用全域值。

暫存器 expr-register @r

@r 暫存器 'r' 的內容
結果為指定名稱暫存器的內容,以單個字串表示。會在需要時插入換行符號。若要取得未命名暫存器的內容,請使用 @" 或 @@。請參閱 暫存器 以了解可用暫存器的說明。
當使用 '=' 暫存器時,您會取得表達式本身,而不是它評估的值。請使用 eval() 來評估它。
巢狀 expr-nesting E110 ------- (expr1) 巢狀表達式

環境變數 expr-env

$VAR 環境變數
任何環境變數的字串值。當未定義時,結果會是空字串。
函式 getenv()setenv() 也可以使用,並且適用於具有非字母數字名稱的環境變數。函式 environ() 可用於取得包含所有環境變數的字典。
expr-env-expand
請注意,直接使用 $VAR 和使用 expand("$VAR") 之間存在差異。直接使用只會展開目前 Vim 會期中已知的環境變數。使用 expand() 會先嘗試使用目前 Vim 會期中已知的環境變數。如果失敗,則會使用 shell 來展開變數。這可能會比較慢,但它會展開 shell 所知道的所有變數。範例
:echo $shell
:echo expand("$shell")
第一個可能不會 echo 任何東西,第二個會 echo $shell 變數(如果您的 shell 支援)。

內部變數 expr-variable

變數 內部變數 請參閱下方 internal-variables
function(expr1, ...) 函式呼叫 請參閱下方 functions

Lambda 表達式 expr-lambda lambda

{args -> expr1} Lambda 表達式 E451
Lambda 表達式會建立一個新的未命名函式,它會傳回評估 expr1 的結果。Lambda 表達式與 user-function 的不同之處在於以下幾點
1. Lambda 表達式的主體是一個 expr1,而不是一連串的 Ex 命令。2. 引數不應使用 "a:" 前綴。例如:
:let F = {arg1, arg2 -> arg1 - arg2}
:echo F(5, 2)
3
引數是可選的。範例
:let F = {-> 'error function'}
:echo F('ignored')
錯誤函式 closure
Lambda 表達式可以存取外部範圍的變數和引數。這通常稱為閉包。範例中 "i" 和 "a:arg" 在 lambda 中使用,而它們已經存在於函式範圍中。即使函式傳回後,它們仍然有效
:function Foo(arg)
:  let i = 3
:  return {x -> x + i - a:arg}
:endfunction
:let Bar = Foo(4)
:echo Bar(6)
5 請注意,變數必須在定義 lambda 之前存在於外部範圍中,這樣才能運作。另請參閱 :func-closure
可以使用以下方式檢查 Lambda 和閉包支援
if has('lambda')
將 Lambda 表達式與 sort()map()filter() 一起使用的範例
:echo map([1, 2, 3], {idx, val -> val + 1})
[2, 3, 4]
:echo sort([3,7,2,1,4], {a, b -> a - b})
[1, 2, 3, 4, 7]
Lambda 表達式也適用於工作和計時器
:let timer = timer_start(500,
                \ {-> execute("echo 'Handler called'", "")},
                \ {'repeat': 3})
已呼叫處理常式 已呼叫處理常式 已呼叫處理常式
請注意,如果閉包被它所依賴的內容引用,則可能會導致使用記憶體而沒有釋放
function Function()
   let x = 0
   let F = {-> x}
 endfunction
閉包使用函式範圍中的 "x",而同一個範圍中的 "F" 引用閉包。這種循環會導致記憶體無法釋放。建議:不要這樣做。
請注意如何使用 execute() 來執行 Ex 命令。雖然那樣很醜陋。
Lambda 表達式具有類似 '<lambda>42' 的內部名稱。如果您的 Lambda 表達式發生錯誤,您可以使用以下命令找出它是什麼
:function <lambda>42
另請參閱:numbered-function

3. 內部變數 internal-variables 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:" 開頭的變數名稱是區域於目前緩衝區的。因此,您可以有多個 "b:foo" 變數,每個緩衝區一個。當緩衝區被抹除或使用 :bdelete 刪除時,會刪除這類型的變數。
有一個預先定義的區域緩衝區變數:b:changedtick changetick b:changedtick 目前緩衝區的總更改次數。每次變更時都會遞增。在這種情況下,復原命令也是一種變更。寫入緩衝區時重設 'modified' 也會計算在內。這可用於僅當緩衝區已變更時才執行動作。範例
:if my_changedtick != b:changedtick
:        let my_changedtick = b:changedtick
:        call My_Update()
:endif
您無法變更或刪除 b:changedtick 變數。
window-variable w:var w: 以 "w:" 開頭的變數名稱是區域於目前視窗的。當視窗關閉時,會刪除它。
tabpage-variable t:var t: 以 "t:" 開頭的變數名稱是區域於目前標籤頁面的。當標籤頁面關閉時,會刪除它。
global-variable g:var g: 在函式內部,全域變數是使用 "g:" 存取的。省略此項將存取函式的區域變數。但是,如果您喜歡,"g:" 也可以在任何其他地方使用。
local-variable l:var l: 在函式內部,區域變數在不附加任何前綴的情況下存取。但是,如果您喜歡,也可以附加 "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 "script executed for the first time"
else
  let s:counter = s:counter + 1
  echo "script executed " .. s:counter .. " times now"
endif
請注意,這表示檔案類型外掛程式不會為每個緩衝區取得不同的腳本變數集。請改用區域緩衝區變數 b:var

預先定義的 VIM 變數 vim-variable v:var v:

E963
所有內建變數的字母列表和詳細資訊位於單獨的說明檔案中:vvars

4. 內建函式 vim-function functions

Vimscript 子系統(在內部稱為 "eval")提供內建函式。腳本也可以定義 user-function
請參閱 function-list 以依主題瀏覽函式。
所有內建函式的字母列表和詳細資訊位於單獨的說明檔案中:builtin-functions

5. 定義函式 user-function

可以定義新函式。這些函式可以像內建函式一樣呼叫。函式會取得引數、執行一連串 Ex 命令,並可以傳回值。
您可以在 userfunc.txt 中找到有關定義函式的大多數資訊。

6. 大括號名稱 curly-braces-names

在大多數您可以使用變數的地方,您都可以使用「大括號名稱」變數。這是一個一般變數名稱,其中一個或多個表達式以大括號 {} 包裹,如下所示
my_{adjective}_variable
當 Vim 遇到此情況時,它會評估大括號內的表達式,將其放置在表達式的位置,然後將整個內容重新解讀為變數名稱。因此,在上面的範例中,如果變數 "adjective" 設定為 "noisy",則參考將會是 "my_noisy_variable",而如果 "adjective" 設定為 "quiet",則參考將會是 "my_quiet_variable"。
這種方法的一個應用是建立一組由選項值控制的變數。例如,語句
echo my_{&background}_message
會根據 'background' 的目前值,輸出 "my_dark_message" 或 "my_light_message" 的內容。
您可以使用多個大括號對
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

7. 指令 expression-commands

:let {var-name} = {expr1} :let E18 將內部變數 {var-name} 設定為表達式 {expr1} 的結果。變數將從 {expr} 取得類型。如果 {var-name} 尚不存在,則會建立它。
:let {var-name}[{idx}] = {expr1} E689
將列表項目設定為表達式 {expr1} 的結果。{var-name} 必須參照到一個列表,並且 {idx} 必須是該列表中有效的索引。對於巢狀列表,可以重複使用索引。這不能用於將項目新增至 列表。這不能用於設定字串中的位元組。您可以這樣做:
:let var = var[0:2] .. 'X' .. var[4:]
{var-name}Blob 時,{idx} 可以是 Blob 的長度,在這種情況下,會附加一個位元組。
E711 E719 :let {var-name}[{idx1}:{idx2}] = {expr1} E708 E709 E710列表中的一系列項目設定為表達式 {expr1} 的結果,此表達式必須是一個具有正確項目數的列表。{idx1} 可以省略,改用零。{idx2} 可以省略,表示列表的結尾。當選取的項目範圍部分超過列表的結尾時,將會新增項目。
:let+= :let-= :let*= :let/= :let%= :let.= :let..= E734 :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}"。 :let {var} ..= {expr1} 類似於 ":let {var} = {var} .. {expr1}"。如果 {var} 尚未設定,且 {var}{expr1} 的類型不符合運算符,這些操作將會失敗。+= 會就地修改 列表Blob,而不是建立新的。
:let ${env-name} = {expr1} :let-environment :let-$ 將環境變數 {env-name} 設定為表達式 {expr1} 的結果。類型始終為字串。 :let ${env-name} .= {expr1}{expr1} 附加到環境變數 {env-name}。如果環境變數尚不存在,則此操作的作用類似於 "="。
:let @{reg-name} = {expr1} :let-register :let-@ 將表達式 {expr1} 的結果寫入暫存器 {reg-name}{reg-name} 必須是單個字母,並且必須是可寫入暫存器的名稱(請參閱 registers)。"@@" 可以用於未命名的暫存器,"@@/" 用於搜尋模式。如果 {expr1} 的結果以 <CR><NL> 結尾,則暫存器將會是行式,否則將會設定為字元式。這可用於清除最後的搜尋模式。
:let @/ = ""
這與搜尋空字串不同,搜尋空字串會在任何地方找到匹配。
:let @{reg-name} .= {expr1}{expr1} 附加到暫存器 {reg-name}。如果暫存器為空,則其作用類似於將其設定為 {expr1}
:let &{option-name} = {expr1} :let-option :let-& 將選項 {option-name} 設定為表達式 {expr1} 的結果。字串或數字值始終會轉換為選項的類型。對於視窗或緩衝區本機的選項,其效果與使用 :set 指令相同:本機值和全域值都會變更。範例:
:let &path = &path .. ',/usr/local/include'
:let &{option-name} .= {expr1} 對於字串選項:將 {expr1} 附加到值。不會像 :set+= 一樣插入逗號。
:let &{option-name} += {expr1} :let &{option-name} -= {expr1} 對於數字或布林選項:加或減 {expr1}
:let &l:{option-name} = {expr1} :let &l:{option-name} .= {expr1} :let &l:{option-name} += {expr1} :let &l:{option-name} -= {expr1} 與上述相同,但僅設定選項的本機值(如果有的話)。作用類似於 :setlocal
:let &g:{option-name} = {expr1} :let &g:{option-name} .= {expr1} :let &g:{option-name} += {expr1} :let &g:{option-name} -= {expr1} 與上述相同,但僅設定選項的全域值(如果有的話)。作用類似於 :setglobal
:let [{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
結果是 [0, 2]。
:let [{name1}, {name2}, ...] .= {expr1} :let [{name1}, {name2}, ...] += {expr1} :let [{name1}, {name2}, ...] -= {expr1} 與上述相同,但為每個 列表項目附加/加/減該值。
:let [{name}, ..., ; {lastname}] = {expr1} E452
類似於上述的 :let-unpack,但 列表可能比名稱多出項目。剩餘項目的列表會指派給 {lastname}。如果沒有剩餘項目,則 {lastname} 會設定為空列表。範例:
:let [a, b; rest] = ["aval", "bval", 3, 4]
:let [{name}, ..., ; {lastname}] .= {expr1} :let [{name}, ..., ; {lastname}] += {expr1} :let [{name}, ..., ; {lastname}] -= {expr1} 與上述相同,但為每個 列表項目附加/加/減該值。
:let=<< :let-heredoc E990 E991 E172 E221 E1145 :let {var-name} =<< [trim] [eval] {endmarker} text... text... {endmarker} 將內部變數 {var-name} 設定為 列表,其中包含由字串 {endmarker} 界定的文字行。
如果未指定 "eval",則文字的每一行都會用作 literal-string,但單引號不需要加倍。如果指定了 "eval",則會評估任何 {expr} 形式的 Vim 表達式,並且結果會取代該表達式,類似於使用 interpolated-string。以下範例會展開 $HOME:
let lines =<< trim eval END
  some text
  See the file {$HOME}/.vimrc
  more text
END
單行中可以有多個 Vim 表達式,但是一個表達式不能跨越多行。如果任何表達式評估失敗,則指派也會失敗。
{endmarker} 不得包含空白字元。{endmarker} 不能以小寫字元開頭。最後一行應僅以 {endmarker} 字串結尾,而沒有任何其他字元。請注意 {endmarker} 後面的空白!
如果沒有 "trim",則會保留文字行中的任何空白字元。如果在 {endmarker} 之前指定了 "trim",則會移除縮排,因此您可以執行
let text =<< trim END
   if ok
     echo 'done'
   endif
END
結果為:["if ok", " echo 'done'", "endif"] 標記必須與 "let" 對齊,並且會從所有文字行中移除第一行的縮排。具體來說:會從輸入行中移除所有與第一個非空白文字行開頭縮排完全符合的前導縮排。會從包含 {endmarker} 的行中移除與 `let` 前面的前導縮排完全符合的所有前導縮排。請注意,這裡空格和 Tab 鍵之間的差異很重要。
如果 {var-name} 尚不存在,則會建立它。後面不能接其他指令,但是可以接註解。
為避免套用行繼續,請考慮將 'C' 新增至 'cpoptions'
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
E121
:let {var-name} .. 列出變數 {var-name} 的值。可以給定多個變數名稱。此處識別的特殊名稱:E738
g:全域變數 b:本機緩衝區變數 w:本機視窗變數 t:本機標籤頁變數 s:腳本本機變數 l:本機函數變數 v:Vim 變數。
:let 列出所有變數的值。變數的類型會顯示在值之前:<nothing> 字串 # 數字 * Funcref
:unl[et][!] {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
這對於清理已使用的全域變數和腳本本機變數(腳本結束時不會刪除這些變數)特別有用。當函數結束時,會自動刪除函數本機變數。
:unl[et] ${env-name} ... :unlet-environment :unlet-$ 移除環境變數 {env-name}。可以在一個 :unlet 指令中混用 {name} 和 ${env-name}。對於不存在的變數,不會給出錯誤訊息,即使沒有 ! 也一樣。如果系統不支援刪除環境變數,則會將其設為空。
:cons :const :cons[t] {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
E995
使用 :const 指定現有變數會產生錯誤。
:let x = 1
:const x = 1  " Error!
E996
請注意,這裡不能使用環境變數、選項值和暫存器值,因為它們無法被鎖定。
:cons[t] :cons[t] {var-name} 如果沒有給定參數或只給定 {var-name},其行為與 :let 相同。
:lockv[ar][!] [depth] {name} ... :lockvar :lockv 鎖定內部變數 {name}。鎖定表示它不能再被更改(直到它被解除鎖定)。已鎖定的變數可以被刪除
:lockvar v
:let v = 'asdf'          " fails!
:unlet v          " works
E741 E940 E1122 如果您嘗試更改已鎖定的變數,會收到錯誤訊息:「E741: Value is locked: {name}」。如果您嘗試鎖定或解除鎖定內建變數,會收到錯誤訊息:「E940: Cannot lock or unlock variable {name}」。
[depth] 在鎖定 列表字典 時相關。它指定鎖定的深度:0 鎖定變數 {name},但不鎖定其值。1 鎖定 列表字典 本身,無法新增或移除項目,但仍然可以變更其值。2 也鎖定值,無法變更項目。如果某個項目是 列表字典,則無法新增或移除項目,但仍然可以變更其值。3 與 2 類似,但針對 列表 / 字典 中的 列表 / 字典,再深入一層。預設的 [depth] 是 2,因此當 {name}列表字典 時,其值無法被變更。
使用 [depth] 0 的範例
let mylist = [1, 2, 3]
lockvar 0 mylist
let mylist[0] = 77        " OK
call add(mylist, 4)        " OK
let mylist = [7, 8, 9]  " Error!
E743
對於無限深度,請使用 [!] 並省略 [depth]。但是,為了捕捉迴圈,最大深度為 100。
請注意,當兩個變數引用同一個 列表 並且您鎖定其中一個時,透過另一個變數使用時,該 列表 也會被鎖定。範例
:let l = [0, 1, 2, 3]
:let cl = l
:lockvar l
:let cl[1] = 99                " won't work!
您可能需要複製一個列表以避免這種情況。請參閱 deepcopy()
:unlo[ckvar][!] [depth] {name} ... :unlockvar :unlo 解除鎖定內部變數 {name}。執行與 :lockvar 相反的操作。
如果 {name} 不存在,則不會給出錯誤訊息。
:if {expr1} :if :end :endif :en E171 E579 E580 :en[dif] 如果 {expr1} 的計算結果為非零值,則執行指令直到下一個匹配的 :else:endif。雖然可以使用簡短形式,但建議始終使用 :endif 以避免混淆,並使自動縮排正常工作。
從 Vim 4.5 版到 5.0 版,: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 之間無法正常工作。
:else :el E581 E583 :el[se] 如果之前沒有執行,則執行指令直到下一個匹配的 :else:endif
:elseif :elsei E582 E584 :elsei[f] {expr1}:else :if 的簡寫,但沒有額外的 :endif
:wh[ile] {expr1} :while :endwhile :wh :endw E170 E585 E588 E733 :endw[hile] 重複執行 :while:endwhile 之間的指令,只要 {expr1} 的計算結果為非零值。當在迴圈內的指令中偵測到錯誤時,執行會繼續在 endwhile 之後。範例
:let lnum = 1
:while lnum <= line("$")
   :call FixLine(lnum)
   :let lnum = lnum + 1
:endwhile
注意: :append:insert 指令在 :while:for 迴圈內無法正常工作。
:for {var} in {object} :for E690 E732 :endfo[r] :endfo :endfor 對於 {object} 中的每個項目,重複執行 :for:endfor 之間的指令。{object} 可以是 列表Blob字串
變數 {var} 設定為每個項目的值。
當在迴圈內的指令中偵測到錯誤時,執行會繼續在 endfor 之後。在迴圈內更改 {object} 會影響使用的項目。如果不需要這樣,請建立副本
:for item in copy(mylist)
{object}列表 且未建立副本時,Vim 會在執行具有目前項目的指令之前,儲存對 列表 中下一個項目的參考。因此,可以移除目前項目而不會產生影響。移除任何後續項目意味著不會找到它。因此,以下範例有效(一種效率低下的清空 列表 的方法)
for item in mylist
   call remove(mylist, 0)
endfor
請注意,重新排序 列表(例如,使用 sort() 或 reverse())可能會產生意想不到的效果。
{object}Blob 時,Vim 總是會建立副本來進行迭代。與 列表 不同,修改 Blob 不會影響迭代。
{object}字串 時,每個項目都是一個包含一個字元的字串,外加任何組合字元。
:for [{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
:continue :con E586 :con[tinue] 當在 :while:for 迴圈內使用時,會跳回迴圈的開頭。
如果在迴圈內的 :try 之後,但在匹配的 :finally 之前(如果存在)使用,則會先執行 :finally 之後直到匹配的 :endtry 的指令。此過程適用於迴圈內的所有巢狀 :try。最外層的 :endtry 然後跳回迴圈的開頭。
:break :brea E587 :brea[k] 當在 :while:for 迴圈內使用時,會跳到匹配的 :endwhile:endfor 之後的指令。如果在迴圈內的 :try 之後,但在匹配的 :finally 之前(如果存在)使用,則會先執行 :finally 之後直到匹配的 :endtry 的指令。此過程適用於迴圈內的所有巢狀 :try。最外層的 :endtry 然後跳到迴圈之後的指令。
:try :try :endt :endtry E600 E601 E602 :endt[ry] 更改 :try:endtry 之間的指令的錯誤處理,包括跨 :source 指令、函式呼叫或自動指令調用的所有執行動作。
當偵測到錯誤或中斷,且後面有 :finally 指令時,執行會繼續在 :finally 之後。否則,或當之後到達 :endtry 時,會檢查下一個(動態)周圍的 :try 是否有對應的 :finally 等。然後腳本處理會終止。函式定義是否具有「abort」參數並不重要。範例
try | call Unknown() | finally | echomsg "cleanup" | endtry
echomsg "not reached"
此外,:try:endtry 內(動態)的錯誤或中斷會轉換為例外。它可以像被 :throw 指令拋出一樣被捕獲(請參閱 :catch)。在這種情況下,腳本處理不會終止。
值「Vim:Interrupt」用於中斷例外。Vim 指令中的錯誤會轉換為「Vim({command}):{errmsg}」形式的值,其他錯誤會轉換為「Vim:{errmsg}」形式的值。{command} 是完整的指令名稱,而 {errmsg} 是如果未捕獲錯誤例外時顯示的訊息,始終以錯誤編號開頭。範例
try | sleep 100 | catch /^Vim:Interrupt$/ | endtry
try | edit | catch /^Vim(edit):E\d\+/ | echo "error" | endtry
:cat :catch E603 E604 E605 :cat[ch] /{pattern}/ 當拋出符合 {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 注意: 「:catch」錯誤訊息的文字並不可靠,因為它在不同的地區設定中可能會有所不同。
:fina :finally E606 E607 :fina[lly] 當符合的 :try:finally 之間的部分離開時,就會執行直到符合的 :endtry 為止的以下命令:無論是直接執行到 :finally,或是透過 :continue:break:finish:return,或透過錯誤、中斷或例外(請參閱 :throw)。
:th :throw E608 :th[row] {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
請注意,「catch」可能需要位於單獨的一行,以便在錯誤導致剖析略過整行且看不到分隔命令的「|」時使用。
:ec :echo :ec[ho] {expr1} .. 顯示每個 {expr1},中間以空格分隔。第一個 {expr1} 從新的一行開始。另請參閱 :comment。使用「\n」開始新的一行。使用「\r」將游標移動到第一欄。使用 :echohl 命令設定的醒目提示。後面不能接註解。範例
:echo "the value of 'shell' is" &shell
:echo-redraw
稍後的重新繪製可能會再次使訊息消失。由於 Vim 大多數會延後重新繪製,直到完成一系列命令,這種情況很常發生。若要避免 :echo 之前的命令導致之後重新繪製(重新繪製通常會延後到您輸入內容),請使用 :redraw 命令強制重新繪製。範例
:new | redraw | echo "there is a new window"
:echo-self-refer
在列印巢狀容器時,echo 會使用「[...@level]」(自參考 List)或「{...@level}」(自參考 Dict)列印第二次出現的自參考容器。
:let l = []
:call add(l, l)
:let l2 = []
:call add(l2, [l2])
:echo l l2
顯示「[[...@0]] [[[...@0]]]」。顯示「[l]」會顯示「[[[...@1]]]」,因為 l 第一次出現在第二層。
:echon
:echon {expr1} .. 顯示每個 {expr1},不新增任何內容。另請參閱 :comment。使用 :echohl 命令設定的醒目提示。後面不能接註解。範例
:echon "the value of 'shell' is " &shell
請注意,使用 :echo (Vim 命令) 和 :!echo (外部 Shell 命令) 之間的不同
:!echo %                --> filename
「:!」的引數會展開,請參閱 :_%
:!echo "%"                --> filename or "filename"
與先前的範例類似。您是否會看到雙引號取決於您的 'shell'
:echo %                        --> nothing
「%」在運算式中是不合法的字元。
:echo "%"                --> %
這只會顯示「%」字元。
:echo expand("%")        --> filename
這會呼叫 expand() 函數來展開「%」。
:echoh :echohl :echoh[l] {name} 對於接下來的 :echo:echon:echomsg 命令,使用醒目提示群組 {name}。也用於 input() 提示。範例
:echohl WarningMsg | echo "Don't panic!" | echohl None
別忘了將群組設回「None」,否則所有後續的 echo 都會被醒目提示。
:echom :echomsg :echom[sg] {expr1} .. 以真實訊息的方式顯示運算式,將訊息儲存在 message-history 中。如同 :echo 命令,引數之間會放置空格。但是會顯示不可列印的字元,而不是解譯。剖析的運作方式與 :echo 略有不同,比較像是 :execute。所有運算式都會先評估並串連,然後才會顯示任何內容。如果運算式未評估為數字或字串,則會使用 string() 將其轉換為字串。使用 :echohl 命令設定的醒目提示。範例
:echomsg "It's a Zizzer Zazzer Zuzz, as you can plainly see."
請參閱 :echo-redraw,以避免畫面重新繪製時訊息消失。:echoe :echoerr :echoe[rr] {expr1} .. 以錯誤訊息的方式顯示運算式,將訊息儲存在 message-history 中。在指令碼或函數中使用時,會新增行號。如同 :echomsg 命令,引數之間會放置空格。在 try 條件式內使用時,會改為引發訊息作為錯誤例外(請參閱 try-echoerr)。範例
:echoerr "This script just failed!"
如果您只是想要醒目提示的訊息,請使用 :echohl。而若要發出嗶聲
:exe "normal \<Esc>"
:eval
:eval {expr} 評估 {expr} 並捨棄結果。範例
:eval Getlist()->Filter()->append('$')
由於未使用結果值,因此運算式應該會有副作用。在範例中,append() 呼叫會將具有文字的 List 附加到緩衝區。這與 :call 類似,但適用於任何運算式。
該命令可以縮短為 :ev:eva,但這些很難辨識,因此不應使用。
該命令後面不能接「|」和另一個命令,因為「|」會被視為運算式的一部分。
:exe :execute :exe[cute] {expr1} .. 將評估 {expr1} 所產生的字串當作 Ex 命令執行。多個引數會串連,中間以空格分隔。若要避免額外的空格,請使用「..」運算子將字串串連成一個引數。{expr1} 會當作已處理的命令使用,不辨識命令列編輯索引鍵。後面不能接註解。範例
:execute "buffer" nextbuf
:execute "normal" count .. "w"
「:execute」可用於將命令附加到不接受「|」的命令。範例
:execute '!ls' | echo "theend"
「:execute」也是避免在 Vim 指令碼中為「:normal」命令輸入控制字元的絕佳方式
:execute "normal ixxx\<Esc>"
這具有 <Esc> 字元,請參閱 expr-string
請小心正確逸出檔案名稱中的特殊字元。fnameescape() 函數可用於 Vim 命令,shellescape() 可用於 :! 命令。範例
:execute "e " .. fnameescape(filename)
:execute "!ls " .. shellescape(filename, 1)
注意: 執行的字串可以是任何命令列,但開始或結束「if」、「while」和「for」不一定有效,因為當略過命令時,「:execute」不會被評估,而 Vim 會遺失區塊開始和結束位置的追蹤。此外,「break」和「continue」不應位於「:execute」內部。此範例無效,因為「:execute」未被評估,而 Vim 看不到「while」,並會因為找到「:endwhile」而產生錯誤
:if 0
: execute 'while i > 5'
:  echo "test"
: endwhile
:endif
允許在執行的字串中完全包含「while」或「if」命令
:execute 'while i < 5 | echo i | let i = i + 1 | endwhile'
:exe-comment
「:execute」、「:echo」和「:echon」後面不能直接接註解,因為它們會將「"」視為字串的開頭。但是,您可以使用「|」後接註解。範例
:echo "foo" | "this is a comment

8. 例外處理 exception-handling

Vim 指令碼語言包含例外處理功能。本節說明如何在 Vim 指令碼中使用它。
Vim 可能會在錯誤或中斷時引發例外,請參閱 catch-errorscatch-interrupt。您也可以使用「:throw」命令明確擲出例外,請參閱 throw-catch

TRY 條件式 try-conditionals

可以捕獲例外或讓清除程式碼執行。您可以使用 try 條件式來指定 catch 子句(捕獲例外)和/或 finally 子句(執行清除)。try 條件式以 :try 命令開始,並在符合的 :endtry 命令結束。在兩者之間,您可以使用 :catch 命令來開始 catch 子句,或使用 :finally 命令來開始 finally 子句。可以有零個或多個 catch 子句,但最多只能有一個 finally 子句,而且後面不能接任何 catch 子句。catch 子句和 finally 子句之前的行稱為 try 區塊。
:try
:        ...
:        ...                                TRY BLOCK
:        ...
:catch /{pattern}/
:        ...
:        ...                                CATCH CLAUSE
:        ...
:catch /{pattern}/
:        ...
:        ...                                CATCH CLAUSE
:        ...
:finally
:        ...
:        ...                                FINALLY CLAUSE
:        ...
:endtry
try 條件式允許觀察程式碼中的例外,並採取適當的動作。可以捕獲 try 區塊中的例外。try 區塊以及 catch 子句中的例外可能會導致清除動作。當 try 區塊執行期間未擲出任何例外時,控制會轉移到 finally 子句(如果存在)。執行後,指令碼會從「:endtry」後面的行繼續。當 try 區塊執行期間發生例外時,會略過 try 區塊中剩餘的行。例外會與指定為「:catch」命令引數的模式比對。會採用第一個符合的「:catch」之後的 catch 子句,而不會執行其他 catch 子句。當到達下一個「:catch」、「:finally」或「:endtry」命令時,catch 子句會結束,無論哪一個先到。然後,會執行 finally 子句(如果存在)。當到達「:endtry」時,指令碼會像平常一樣在下一行繼續執行。當在 try 區塊中擲出不符合「:catch」命令所指定之任何模式的例外時,該例外不會被該 try 條件式捕獲,也不會執行任何 catch 子句。只會採用 finally 子句(如果存在)。例外會在執行 finally 子句期間擱置。它會在「:endtry」處恢復,以便不會執行「:endtry」之後的命令,而且可能會在其他地方捕獲例外,請參閱 try-nesting。當在執行 catch 子句期間擲出另一個例外時,不會執行該 catch 子句中剩餘的行。新的例外不會與相同 try 條件式之任何「:catch」命令中的模式比對,也不會採用其任何 catch 子句。但是,如果存在 finally 子句,則會執行該子句,並且例外會在執行期間擱置。不會執行「:endtry」之後的命令。但是,可能會在其他地方捕獲新的例外,請參閱 try-nesting。當在執行 finally 子句(如果存在)期間擲出例外時,會略過 finally 子句中剩餘的行。如果 finally 子句是因為 try 區塊或其中一個 catch 子句的例外而採用,則會捨棄原始(擱置)的例外。不會執行「:endtry」之後的命令,而且會傳播 finally 子句中的例外,並可以在其他地方捕獲,請參閱 try-nesting
當從 try 區塊或 catch 子句執行封閉整個 try 條件的 ":while" 迴圈的 ":break" 或 ":continue" 時,也會執行 finally 子句。或者,當從函式或來源腳本中的 try 條件的 try 區塊或 catch 子句執行 ":return" 或 ":finish" 時。在執行 finally 子句期間,":break"、":continue"、":return" 或 ":finish" 會暫停,並在到達 ":endtry" 時恢復。然而,當從 finally 子句拋出例外時,它會被捨棄。當在 finally 子句中遇到封閉整個 try 條件的 ":while" 迴圈的 ":break" 或 ":continue",或遇到 ":return" 或 ":finish" 時,finally 子句的其餘部分會被跳過,並且像往常一樣執行 ":break"、":continue"、":return" 或 ":finish"。如果 finally 子句是因為例外或 try 區塊或 catch 子句中較早的 ":break"、":continue"、":return" 或 ":finish" 而被採用的,則此暫掛的例外或命令會被捨棄。
範例請參閱 throw-catchtry-finally

TRY 條件的巢狀結構 try-nesting

Try 條件可以任意巢狀。也就是說,完整的 try 條件可以放入另一個 try 條件的 try 區塊、catch 子句或 finally 子句中。如果內部的 try 條件沒有捕獲在其 try 區塊中拋出的例外,或者從其 catch 子句之一或其 finally 子句拋出新的例外,則會根據上述規則檢查外部的 try 條件。如果內部的 try 條件位於外部 try 條件的 try 區塊中,則會檢查其 catch 子句,否則只會執行 finally 子句。對於巢狀結構而言,內部的 try 條件是直接包含在外部的 try 條件中,還是外部的 try 條件來源包含內部 try 條件的腳本或呼叫函式,都沒有關係。
當沒有任何作用中的 try 條件捕獲例外時,只會執行它們的 finally 子句。之後,腳本處理會終止。如果由 ":throw" 命令明確拋出未捕獲的例外,則會顯示錯誤訊息。對於由 Vim 隱式引發的未捕獲錯誤和中斷例外,則會像往常一樣顯示錯誤訊息或中斷訊息。
範例請參閱 throw-catch

檢查例外處理程式碼 except-examine

例外處理程式碼可能會變得棘手。如果您不確定會發生什麼事,請將 'verbose' 設定為 13,或在來源您的腳本檔案時使用 ":13verbose" 命令修飾符。然後,您會看到何時拋出、捨棄、捕獲或完成例外。當使用至少 14 的詳細程度層級時,也會顯示 finally 子句中暫掛的事項。此資訊也會在偵錯模式下提供(請參閱 debug-scripts)。

拋出和捕獲例外 throw-catch

您可以拋出任意數值或字串作為例外。使用 :throw 命令,並將要拋出的值作為引數傳遞
:throw 4711
:throw "string"
throw-expression
您也可以指定一個運算式引數。然後會先評估該運算式,然後拋出結果
: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" 都沒有顯示。
catch-order
例外可以由具有一個或多個 :catch 命令的 try 條件捕獲,請參閱 try-conditionals。每個 ":catch" 命令要捕獲的值可以指定為模式引數。當捕獲到符合的例外時,會執行後續的 catch 子句。範例
: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 子句。
throw-variables
如果您透過一般模式捕獲例外,您可以在變數 v:exception 中存取確切的值
:  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-nested
未被 try 條件捕獲的例外可以被周圍的 try 條件捕獲
:try
:  try
:    throw "foo"
:  catch /foobar/
:    echo "foobar"
:  finally
:    echo "inner finally"
:  endtry
:catch /foo/
:  echo "foo"
:endtry
內部的 try 條件不會捕獲例外,只會執行其 finally 子句。然後,例外會被外部的 try 條件捕獲。範例會顯示 "inner finally",然後顯示 "foo"。
throw-from-catch
您可以捕獲例外,並從 catch 子句拋出新的例外,以便在其他地方捕獲
: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"。
rethrow
Vim 腳本語言中沒有真正的重新拋出,但是您可以改為拋出 "v:exception"
:function! Bar()
:  try
:    call Foo()
:  catch /.*/
:    echo "Rethrow" v:exception
:    throw v:exception
:  endtry
:endfunction
try-echoerr
請注意,此方法不能用於「重新拋出」Vim 錯誤或中斷例外,因為無法偽造 Vim 內部例外。嘗試這樣做會導致錯誤例外。您應該拋出自己的例外,表示情況。如果您想要導致包含原始錯誤例外值的 Vim 錯誤例外,您可以使用 :echoerr 命令
:try
:  try
:    asdf
:  catch /.*/
:    echoerr v:exception
:  endtry
:catch /.*/
:  echo v:exception
:endtry
此程式碼會顯示
Vim(echoerr):Vim:E492: Not an editor command: asdf

清理程式碼 try-finally

腳本通常會變更全域設定,並在結束時還原它們。但是,如果使用者按下 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
每當函式或腳本的一部分變更全域設定時,都應該在本地使用此方法,這些設定需要在該函式或腳本部分的失敗或正常結束時還原。
break-finally
當 try 區塊或 catch 子句被 ":continue"、":break"、":return" 或 ":finish" 離開時,清理程式碼也會執行。範例
: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"。(最重要的是,這會覆蓋傳回值。)
except-from-finally
在 finally 子句中使用 ":continue"、":break"、":return"、":finish" 或 ":throw" 是可能的,但不建議這樣做,因為這會放棄 try 條件的清理動作。但是,當然,可能會從 finally 子句引發中斷和錯誤例外。範例,其中 finally 子句中的錯誤會停止中斷的正常運作
: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-errorsignore-errors

捕獲錯誤 catch-errors

如果您想要捕獲特定的錯誤,您只需將要監視的程式碼放入 try 區塊中,並為錯誤訊息新增 catch 子句。try 條件的存在會導致所有錯誤都轉換為例外。不會顯示訊息,並且不會設定 v:errmsg。若要找到 ":catch" 命令的正確模式,您必須知道錯誤例外的格式。錯誤例外具有以下格式
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-text
注意:您絕不應該捕獲錯誤訊息文字本身
:catch /No such variable/
只在英文地區設定中有效,但是當使用者透過 :language 命令選擇不同的語言時無效。但是,在註解中引用訊息文字很有幫助
:catch /^Vim(\a\+):E108:/   " No such variable

忽略錯誤 ignore-errors

您可以透過在本機捕獲錯誤來忽略特定 Vim 命令中的錯誤
:try
:  write
:catch
:endtry
但是,強烈建議您不要使用這種簡單的形式,因為它可能會捕獲超出您想要的範圍。使用 ":write" 命令時,可能會執行某些自動命令並導致與寫入無關的錯誤,例如
:au BufWritePre * unlet novar
即使是身為腳本撰寫者的您不需負責的錯誤也可能發生:您的腳本使用者可能已定義了自動指令。這樣您就會對使用者隱藏錯誤。最好使用
:try
:  write
:catch /^Vim(write):/
:endtry
只捕捉真正的寫入錯誤。因此,只捕捉您想故意忽略的錯誤。
對於不會導致執行自動指令的單一指令,您甚至可以使用「:silent!」指令來抑制錯誤轉換為例外。
:silent! nunmap k
當 try 條件式處於啟用狀態時,此方法也有效。

捕捉中斷 catch-interrupt

當有啟用的 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,腳本將會終止。
若要測試在腳本中的特定行按下 CTRL-C 時會發生什麼情況,請使用除錯模式並在該行執行 >quit>interrupt 指令。請參閱 debug-scripts

捕捉所有例外 catch-all

以下指令
: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

例外與自動指令 except-autocmd

在執行自動指令期間可以使用例外。範例
: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!」。
except-autocmd-Pre
對於某些指令,會在指令的主要動作發生之前執行自動指令。如果在自動指令序列中拋出且未捕捉到例外,則該序列和導致其執行的指令會被放棄,並且例外會傳播到指令的呼叫者。範例
: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 "*"
except-autocmd-Post
對於某些指令,會在指令的主要動作發生之後執行自動指令。如果這個主要動作失敗,且指令位於活動的 try 條件式內,則會跳過自動指令,並且會拋出一個錯誤例外,該例外可以被指令的呼叫者捕捉。範例
: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
您也可以使用「:silent!」
: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
except-autocmd-Cmd
對於某些指令,可以使用自動指令序列來取代正常動作。來自該序列的例外將會被指令的呼叫者捕捉。範例:對於「:write」指令,當發生例外時,呼叫者無法知道檔案是否已實際寫入。您需要以某種方式告知它。
: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
等等。
except-autocmd-ill
您不能將 try 條件式分散在不同事件的自動指令上。下列程式碼格式不正確
:autocmd BufWritePre  * try
:
:autocmd BufWritePost * catch
:autocmd BufWritePost *   echo v:exception
:autocmd BufWritePost * endtry
:
:write

例外階層和參數化的例外 except-hier-param

某些程式語言允許使用例外類別的階層,或將其他資訊與例外類別的物件一起傳遞。您可以在 Vim 中執行類似的操作。若要從階層中拋出例外,只需拋出以冒號分隔元件的完整類別名稱,例如,針對數學程式庫中的溢位拋出字串「EXCEPT:MATHERR:OVERFLOW」。當您想要使用例外類別傳遞其他資訊時,請將其新增在括號中,例如,針對寫入「myfile」時發生的錯誤拋出字串「EXCEPT:IO:WRITEERR(myfile)」。透過「:catch」指令中的適當模式,您可以針對階層的基本類別或衍生類別進行捕捉。括號中的其他資訊可以使用「:substitute」指令從 v:exception 中取出。範例
: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"
:
:endtry
Vim 本身引發的例外(在發生錯誤或按下 CTRL-C 時)使用扁平階層:它們都在「Vim」類別中。您無法自行拋出帶有「Vim」前置詞的例外;它們是保留給 Vim 使用的。如果知道的話,Vim 錯誤例外會以失敗的指令名稱進行參數化。請參閱 catch-errors

特殊性

except-compat
例外處理概念要求導致例外的指令序列立即中止,並將控制權轉移到 finally 子句和/或 catch 子句。
在 Vim 腳本語言中,有些情況下,腳本和函式會在發生錯誤後繼續執行:在沒有「abort」旗標的函式中,或在「:silent!」之後的指令中,控制流程會移至下一行,而在函式外部,控制流程會移至最外層的「:endwhile」或「:endif」之後的行。另一方面,錯誤應該可以作為例外被捕捉(因此,需要立即中止)。
此問題已透過將錯誤轉換為例外並僅在 try 條件式處於活動狀態時使用立即中止(如果未被「:silent!」抑制)來解決。這沒有限制,因為(錯誤)例外只能從活動的 try 條件式中捕捉。如果您想要立即終止而不捕捉錯誤,只需使用沒有 catch 子句的 try 條件式即可。(您可以透過指定 finally 子句來讓清除程式碼在終止前執行。)
當沒有活動的 try 條件式時,會使用一般的中止和繼續行為,而不是立即中止。這確保了為 Vim 6.1 和更早版本編寫的腳本的相容性。
然而,當從新腳本的活動 try 條件式內執行不使用例外處理指令的現有腳本(或呼叫其函式之一)時,您可能會變更現有腳本在發生錯誤時的控制流程。您會立即中止發生錯誤,並且可以在新腳本中捕捉錯誤。然而,如果來源腳本透過使用「:silent!」指令來抑制錯誤訊息(如果適當,則透過測試 v:errmsg 來檢查錯誤),則其執行路徑不會變更。錯誤不會轉換為例外。(請參閱 :silent。)因此,唯一剩下會發生這種情況的原因是腳本不在乎錯誤並產生錯誤訊息。您可能不希望從新腳本中使用此類程式碼。
except-syntax-err
例外處理指令中的語法錯誤永遠不會被其所屬 try 條件式的任何「:catch」指令捕捉。然而,會執行其 finally 子句。範例
: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
原始例外會被捨棄,並且會改為引發錯誤例外。
except-single-line
「:try」、「:catch」、「:finally」和「:endtry」指令可以放在同一行上,但這樣語法錯誤可能會使您難以識別「catch」行,因此您最好避免這樣做。範例
:try | unlet! foo # | catch | endtry
會針對「:unlet!」引數後的尾隨字元引發錯誤例外,但不會看到「:catch」和「:endtry」指令,因此錯誤例外會被捨棄,並且會顯示「E488: Trailing characters」訊息。
except-several-errors
當單一指令中出現多個錯誤時,第一個錯誤訊息通常是最具體的,因此會轉換為錯誤例外。範例
echo novar
會導致
E121: Undefined variable: novar
E15: Invalid expression: novar
try 條件式內錯誤例外的值為
Vim(echo):E121: Undefined variable: novar
except-syntax-error
但是,當在同一指令中的正常錯誤之後偵測到語法錯誤時,會使用語法錯誤作為拋出的例外。範例
unlet novar #
會導致
E108: No such variable: "novar"
E488: Trailing characters
try 條件式內錯誤例外的值為
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

9. 範例 eval-examples

以二進制列印
:" 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")))
scanf() 取代
sscanf
Vim 中沒有 sscanf() 函式。如果您需要從一行中提取部分內容,可以使用 matchstr() 和 substitute() 來完成。此範例示範如何從類似「foobar.txt, 123, 45」的行中取得檔案名稱、行號和欄號。
:" 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-dictionary
可以使用 :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

沙箱 eval-sandbox sandbox

'foldexpr''formatexpr''includeexpr''indentexpr''statusline''foldtext' 選項可以在沙箱中評估。這表示您可以防止這些運算式產生不良的副作用。這為從模式行設定這些選項時提供了一些安全性。當執行標籤檔案中的指令時,以及在命令列中使用 CTRL-R = 時,也會使用它。沙箱也用於 :sandbox 指令。
E48
不允許在沙箱中使用這些項目
變更緩衝區文字
定義或變更對應、自動指令、使用者指令
設定某些選項(請參閱 option-summary
設定某些 v: 變數(請參閱 v:varE794
執行 shell 指令
讀取或寫入檔案
跳至另一個緩衝區或編輯檔案
執行 Python、Perl 等指令。這不能保證 100% 安全,但應該會阻止大多數攻擊。
:san :sandbox :san[dbox] {cmd} 在沙箱中執行 {cmd}。適用於評估可能從模式行設定的選項,例如 'foldexpr'
sandbox-option
一些選項包含運算式。評估此運算式時,可能必須在沙箱中執行,以避免安全風險。但是,沙箱是受限的,因此只有在從不安全的位置設定選項時才會發生這種情況。在此情況下,不安全的位置包括
在目前目錄中來源 .nvimrc 或 .exrc
在沙箱中執行時
來自模式行的值
執行在沙箱中定義的函式
請注意,當在沙盒中儲存選項值並還原時,該選項仍會被標記為在沙盒中設定的狀態。

文字鎖定 textlock

在某些情況下,不允許更改緩衝區中的文字、跳到另一個視窗,以及其他可能會混淆或破壞 Vim 目前正在執行的操作。這主要適用於當 Vim 正在執行其他操作時發生的事情。例如,TextYankPost 自動指令無法編輯它正在複製的文字。
當文字鎖定啟用時,不允許進行以下操作
變更緩衝區文字
跳到另一個緩衝區或視窗
編輯另一個檔案
關閉視窗或退出 Vim
等等。

Vim 腳本庫 vim-script-library

Vim 捆綁了一個 Vim 腳本庫,可供執行階段和腳本作者使用。目前,它僅包含非常少的功能,但隨著時間的推移可能會增加。
dist#vim
這些函數使用自動載入的前綴 "dist#vim"。
以下函數可用
dist#vim#IsSafeExecutable(filetype, executable)
此函數接受一個檔案類型和一個可執行檔,並檢查執行給定的可執行檔是否安全。為了安全起見,使用者可能不希望 Vim 執行隨機的可執行檔,或者可能已禁止針對特定檔案類型執行此操作,透過設定 "<filetype>_exec" 變數 (plugin_exec)。
它會回傳 TRUEFALSE,以指示外掛程式是否應該執行給定的可執行檔。它接受以下引數
引數類型
檔案類型 字串 可執行檔 字串

命令列運算式高亮顯示 expr-highlight

使用者在 i_CTRL-R_=c_CTRL-\_equote= 中輸入的運算式會由內建的運算式解析器高亮顯示。它使用下表中描述的高亮群組,這些群組可能會被配色方案覆蓋。 hl-NvimInvalid
除了下面描述的 "Nvim" 前綴的高亮群組外,還有 "NvimInvalid" 前綴的高亮群組,它們具有相同的含義,但表示該 Token 包含錯誤或之前發生了錯誤。它們大多具有相同的層次結構,只是(預設情況下)會使用連結到 Error 的 NvimInvalid 來取代任何非 Nvim 前綴的群組,並且存在一些其他的中間群組。
群組 預設連結 彩色運算式
hl-NvimInternalError 無,紅/紅 解析器錯誤
hl-NvimAssignment 運算子 通用賦值 hl-NvimPlainAssignment NvimAssignment :let 中的 = hl-NvimAugmentedAssignment NvimAssignment 通用,+=/`-=`/`.=` hl-NvimAssignmentWithAddition NvimAugmentedAssignment :let+= 中的 += hl-NvimAssignmentWithSubtraction NvimAugmentedAssignment :let-= 中的 -= hl-NvimAssignmentWithConcatenation NvimAugmentedAssignment :let.= 中的 .=
hl-NvimOperator 運算子 通用運算子
hl-NvimUnaryOperator NvimOperator 通用一元運算子 hl-NvimUnaryPlus NvimUnaryOperator expr-unary-+ hl-NvimUnaryMinus NvimUnaryOperator expr-unary-- hl-NvimNot NvimUnaryOperator expr-!
hl-NvimBinaryOperator NvimOperator 通用二元運算子 hl-NvimComparison NvimBinaryOperator 任何 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-%
hl-NvimTernary NvimOperator expr1 中的 ? hl-NvimTernaryColon NvimTernary expr1 中的 :
hl-NvimParenthesis 分隔符號 通用括號 hl-NvimLambda NvimParenthesis lambda 中的 {/`}` hl-NvimNestingParenthesis NvimParenthesis expr-nesting 中的 (/`)` hl-NvimCallingParenthesis NvimParenthesis expr-function 中的 (/`)`
hl-NvimSubscript NvimParenthesis 通用下標 hl-NvimSubscriptBracket NvimSubscript expr-[] 中的 [/`]` hl-NvimSubscriptColon NvimSubscript expr-[:] 中的 : hl-NvimCurly NvimSubscript curly-braces-names 中的 {/`}`
hl-NvimContainer NvimParenthesis 通用容器 hl-NvimDict NvimContainer dict 字面值中的 {/`}` hl-NvimList NvimContainer list 字面值中的 [/`]`
hl-NvimIdentifier 識別符號 通用識別符號 hl-NvimIdentifierScope NvimIdentifier 命名空間: internal-variables: 前的字母 hl-NvimIdentifierScopeDelimiter NvimIdentifier 命名空間字母後的 : hl-NvimIdentifierName NvimIdentifier 識別符號的其餘部分 hl-NvimIdentifierKey NvimIdentifier expr-entry 後的識別符號
hl-NvimColon 分隔符號 dict 字面值中的 : hl-NvimComma 分隔符號 dictlist 字面值或 expr-function 中的 , hl-NvimArrow 分隔符號 lambda 中的 ->
hl-NvimRegister 特殊字元 expr-register hl-NvimNumber 數字 整數中非前綴的數字 expr-number hl-NvimNumberPrefix 類型 八進位數0十六進位數0x二進位數0b hl-NvimFloat NvimNumber 浮點數
hl-NvimOptionSigil 類型 expr-option 中的 & hl-NvimOptionScope NvimIdentifierScope 選項範圍 (如果有) hl-NvimOptionScopeDelimiter NvimIdentifierScopeDelimiter 選項範圍後的 : hl-NvimOptionName NvimIdentifier 選項名稱
hl-NvimEnvironmentSigil NvimOptionSigil expr-env 中的 $ hl-NvimEnvironmentName NvimIdentifier 環境變數名稱
hl-NvimString 字串 通用字串 hl-NvimStringBody NvimString 通用字串文字主體 hl-NvimStringQuote NvimString 通用字串引號 hl-NvimStringSpecial 特殊字元 通用字串非文字主體
hl-NvimSingleQuote NvimStringQuote expr-' 中的 ' hl-NvimSingleQuotedBody NvimStringBody expr-' 字串主體的文字部分 hl-NvimSingleQuotedQuote NvimStringSpecial expr-' 字串主體內的 ''
hl-NvimDoubleQuote NvimStringQuote expr-quote 中的 " hl-NvimDoubleQuotedBody NvimStringBody expr-quote 主體的文字部分 hl-NvimDoubleQuotedEscape NvimStringSpecial 有效的 expr-quote 跳脫序列 hl-NvimDoubleQuotedUnknownEscape NvimInvalidValue 無法辨識的 expr-quote 跳脫序列
主要
命令索引
快速參考