diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:09:20 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-10 20:09:20 +0000 |
commit | 029f72b1a93430b24b88eb3a72c6114d9f149737 (patch) | |
tree | 765d5c2041967f9c6fef195fe343d9234a030e90 /runtime/doc/eval.txt | |
parent | Initial commit. (diff) | |
download | vim-029f72b1a93430b24b88eb3a72c6114d9f149737.tar.xz vim-029f72b1a93430b24b88eb3a72c6114d9f149737.zip |
Adding upstream version 2:9.1.0016.upstream/2%9.1.0016
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'runtime/doc/eval.txt')
-rw-r--r-- | runtime/doc/eval.txt | 4841 |
1 files changed, 4841 insertions, 0 deletions
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt new file mode 100644 index 0000000..d52f7fe --- /dev/null +++ b/runtime/doc/eval.txt @@ -0,0 +1,4841 @@ +*eval.txt* For Vim version 9.1. Last change: 2023 Dec 09 + + + VIM REFERENCE MANUAL by Bram Moolenaar + + +Expression evaluation *expression* *expr* *E15* *eval* + *E1002* +Using expressions is introduced in chapter 41 of the user manual |usr_41.txt|. + +Note: Expression evaluation can be disabled at compile time. If this has been +done, the features in this document are not available. See |+eval| and +|no-eval-feature|. + +This file is mainly about the backwards compatible (legacy) Vim script. For +specifics of Vim9 script, which can execute much faster, supports type +checking and much more, see |vim9.txt|. Where the syntax or semantics differ +a remark is given. + +1. Variables |variables| + 1.1 Variable types + 1.2 Function references |Funcref| + 1.3 Lists |Lists| + 1.4 Dictionaries |Dictionaries| + 1.5 Blobs |Blobs| + 1.6 More about variables |more-variables| +2. Expression syntax |expression-syntax| +3. Internal variable |internal-variables| +4. Builtin Functions |functions| +5. Defining functions |user-functions| +6. Curly braces names |curly-braces-names| +7. Commands |expression-commands| +8. Exception handling |exception-handling| +9. Examples |eval-examples| +10. Vim script version |vimscript-version| +11. No +eval feature |no-eval-feature| +12. The sandbox |eval-sandbox| +13. Textlock |textlock| +14. Vim script library |vim-script-library| + +Testing support is documented in |testing.txt|. +Profiling is documented at |profiling|. + +============================================================================== +1. Variables *variables* + +1.1 Variable types ~ + *E712* *E896* *E897* *E899* *E1098* + *E1107* *E1135* *E1138* +There are ten types of variables: + + *Number* *Integer* +Number A 32 or 64 bit signed number. |expr-number| + The number of bits is available in |v:numbersize|. + Examples: -123 0x10 0177 0o177 0b1011 + +Float A floating point number. |floating-point-format| *Float* + Examples: 123.456 1.15e-6 -1.1e3 + +String A NUL terminated string of 8-bit unsigned characters (bytes). + |expr-string| Examples: "ab\txx\"--" 'x-z''a,c' + +List An ordered sequence of items, see |List| for details. + Example: [1, 2, ['a', 'b']] + +Dictionary An associative, unordered array: Each entry has a key and a + value. |Dictionary| + Examples: + {'blue': "#0000ff", 'red': "#ff0000"} + #{blue: "#0000ff", red: "#ff0000"} + +Funcref A reference to a function |Funcref|. + Example: function("strlen") + It can be bound to a dictionary and arguments, it then works + like a Partial. + Example: function("Callback", [arg], myDict) + +Special |v:false|, |v:true|, |v:none| and |v:null|. *Special* + +Job Used for a job, see |job_start()|. *Job* *Jobs* + +Channel Used for a channel, see |ch_open()|. *Channel* *Channels* + +Blob Binary Large Object. Stores any sequence of bytes. See |Blob| + for details + Example: 0zFF00ED015DAF + 0z is an empty Blob. + +The Number and String types are converted automatically, depending on how they +are used. + +Conversion from a Number to a String is by making the ASCII representation of +the Number. Examples: + Number 123 --> String "123" ~ + Number 0 --> String "0" ~ + Number -1 --> String "-1" ~ + *octal* +Conversion from a String to a Number only happens in legacy Vim script, not in +Vim9 script. It is done by converting the first digits to a number. +Hexadecimal "0xf9", Octal "017" or "0o17", and Binary "0b10" +numbers are recognized +NOTE: when using |Vim9| script or |scriptversion-4| octal with a leading "0" +is not recognized. The 0o notation requires patch 8.2.0886. +If the String doesn't start with digits, the result is zero. +Examples: + String "456" --> Number 456 ~ + String "6bar" --> Number 6 ~ + String "foo" --> Number 0 ~ + String "0xf1" --> Number 241 ~ + String "0100" --> Number 64 ~ + String "0o100" --> Number 64 ~ + String "0b101" --> Number 5 ~ + String "-8" --> Number -8 ~ + String "+8" --> Number 0 ~ + +To force conversion from String to Number, add zero to it: > + :echo "0100" + 0 +< 64 ~ + +To avoid a leading zero to cause octal conversion, or for using a different +base, use |str2nr()|. + + *TRUE* *FALSE* *Boolean* +For boolean operators Numbers are used. Zero is FALSE, non-zero is TRUE. +You can also use |v:false| and |v:true|, in Vim9 script |false| and |true|. +When TRUE is returned from a function it is the Number one, FALSE is the +number zero. + +Note that in the command: > + :if "foo" + :" NOT executed +"foo" is converted to 0, which means FALSE. If the string starts with a +non-zero number it means TRUE: > + :if "8foo" + :" executed +To test for a non-empty string, use empty(): > + :if !empty("foo") + +< *falsy* *truthy* +An expression can be used as a condition, ignoring the type and only using +whether the value is "sort of true" or "sort of false". Falsy is: + the number zero + empty string, blob, list or dictionary +Other values are truthy. Examples: + 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 + + *non-zero-arg* +Function arguments often behave slightly different from |TRUE|: If the +argument is present and it evaluates to a non-zero Number, |v:true| or a +non-empty String, then the value is considered to be TRUE. +Note that " " and "0" are also non-empty strings, thus considered to be TRUE. +A List, Dictionary or Float is not a Number or String, thus evaluate to FALSE. + + *E611* *E745* *E728* *E703* *E729* *E730* *E731* *E908* *E910* + *E913* *E974* *E975* *E976* *E1319* *E1320* *E1321* *E1322* + *E1323* *E1324* +|List|, |Dictionary|, |Funcref|, |Job|, |Channel|, |Blob|, |Class| and +|object| types are not automatically converted. + + *E805* *E806* *E808* +When mixing Number and Float the Number is converted to Float. Otherwise +there is no automatic conversion of Float. You can use str2float() for String +to Float, printf() for Float to String and float2nr() for Float to Number. + + *E362* *E891* *E892* *E893* *E894* *E907* *E911* *E914* +When expecting a Float a Number can also be used, but nothing else. + + *no-type-checking* +You will not get an error if you try to change the type of a variable. + + +1.2 Function references ~ + *Funcref* *E695* *E718* *E1192* +A Funcref variable is obtained with the |function()| function, the |funcref()| +function, (in |Vim9| script) the name of a function, or created with the +lambda expression |expr-lambda|. It can be used in an expression in the place +of a function name, before the parenthesis around the arguments, to invoke the +function it refers to. Example in |Vim9| script: > + + :var Fn = MyFunc + :echo Fn() + +Legacy script: > + :let Fn = function("MyFunc") + :echo Fn() +< *E704* *E705* *E707* +A Funcref variable must start with a capital, "s:", "w:", "t:" or "b:". You +can use "g:" but the following name must still start with a capital. You +cannot have both a Funcref variable and a function with the same name. + +A special case is defining a function and directly assigning its Funcref to a +Dictionary entry. Example: > + :function dict.init() dict + : let self.val = 0 + :endfunction + +The key of the Dictionary can start with a lower case letter. The actual +function name is not used here. Also see |numbered-function|. + +A Funcref can also be used with the |:call| command: > + :call Fn() + :call dict.init() + +The name of the referenced function can be obtained with |string()|. > + :let func = string(Fn) + +You can use |call()| to invoke a Funcref and use a list variable for the +arguments: > + :let r = call(Fn, mylist) +< + *Partial* +A Funcref optionally binds a Dictionary and/or arguments. This is also called +a Partial. This is created by passing the Dictionary and/or arguments to +function() or funcref(). When calling the function the Dictionary and/or +arguments will be passed to the function. Example: > + + let Cb = function('Callback', ['foo'], myDict) + call Cb('bar') + +This will invoke the function as if using: > + call myDict.Callback('foo', 'bar') + +This is very useful when passing a function around, e.g. in the arguments of +|ch_open()|. + +Note that binding a function to a Dictionary also happens when the function is +a member of the Dictionary: > + + let myDict.myFunction = MyFunction + call myDict.myFunction() + +Here MyFunction() will get myDict passed as "self". This happens when the +"myFunction" member is accessed. When making assigning "myFunction" to +otherDict and calling it, it will be bound to otherDict: > + + let otherDict.myFunction = myDict.myFunction + call otherDict.myFunction() + +Now "self" will be "otherDict". But when the dictionary was bound explicitly +this won't happen: > + + let myDict.myFunction = function(MyFunction, myDict) + let otherDict.myFunction = myDict.myFunction + call otherDict.myFunction() + +Here "self" will be "myDict", because it was bound explicitly. + + +1.3 Lists ~ + *list* *List* *Lists* *E686* +A List is an ordered sequence of items. An item can be of any type. Items +can be accessed by their index number. Items can be added and removed at any +position in the sequence. + + +List creation ~ + *E696* *E697* +A List is created with a comma-separated list of items in square brackets. +Examples: > + :let mylist = [1, two, 3, "four"] + :let emptylist = [] + +An item can be any expression. Using a List for an item creates a +List of Lists: > + :let nestlist = [[11, 12], [21, 22], [31, 32]] + +An extra comma after the last item is ignored. + + +List index ~ + *list-index* *E684* +An item in the List can be accessed by putting the index in square brackets +after the List. Indexes are zero-based, thus the first item has index zero. > + :let item = mylist[0] " get the first item: 1 + :let item = mylist[2] " get the third item: 3 + +When the resulting item is a list this can be repeated: > + :let item = nestlist[0][1] " get the first list, second item: 12 +< +A negative index is counted from the end. Index -1 refers to the last item in +the List, -2 to the last but one item, etc. > + :let last = mylist[-1] " get the last item: "four" + +To avoid an error for an invalid index use the |get()| function. When an item +is not available it returns zero or the default value you specify: > + :echo get(mylist, idx) + :echo get(mylist, idx, "NONE") + + +List concatenation ~ + *list-concatenation* +Two lists can be concatenated with the "+" operator: > + :let longlist = mylist + [5, 6] + :let mylist += [7, 8] + +To prepend or append an item, turn the item into a list by putting [] around +it. To change a list in-place, refer to |list-modification| below. + + +Sublist ~ + *sublist* +A part of the List can be obtained by specifying the first and last index, +separated by a colon in square brackets: > + :let shortlist = mylist[2:-1] " get List [3, "four"] + +Omitting the first index is similar to zero. Omitting the last index is +similar to -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 + +Notice that the last index is inclusive. If you prefer using an exclusive +index use the |slice()| method. + +If the first index is beyond the last item of the List or the second item is +before the first item, the result is an empty list. There is no error +message. + +If the second index is equal to or greater than the length of the list the +length minus one is used: > + :let mylist = [0, 1, 2, 3] + :echo mylist[2:8] " result: [2, 3] + +NOTE: mylist[s:e] means using the variable "s:e" as index. Watch out for +using a single letter variable before the ":". Insert a space when needed: +mylist[s : e]. + + +List identity ~ + *list-identity* +When variable "aa" is a list and you assign it to another variable "bb", both +variables refer to the same list. Thus changing the list "aa" will also +change "bb": > + :let aa = [1, 2, 3] + :let bb = aa + :call add(aa, 4) + :echo bb +< [1, 2, 3, 4] + +Making a copy of a list is done with the |copy()| function. Using [:] also +works, as explained above. This creates a shallow copy of the list: Changing +a list item in the list will also change the item in the copied list: > + :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] + +To make a completely independent list use |deepcopy()|. This also makes a +copy of the values in the list, recursively. Up to a hundred levels deep. + +The operator "is" can be used to check if two variables refer to the same +List. "isnot" does the opposite. In contrast "==" compares if two lists have +the same value. > + :let alist = [1, 2, 3] + :let blist = [1, 2, 3] + :echo alist is blist +< 0 > + :echo alist == blist +< 1 + +Note about comparing lists: Two lists are considered equal if they have the +same length and all items compare equal, as with using "==". There is one +exception: When comparing a number with a string they are considered +different. There is no automatic type conversion, as with using "==" on +variables. Example: > + echo 4 == "4" +< 1 > + echo [4] == ["4"] +< 0 + +Thus comparing Lists is more strict than comparing numbers and strings. You +can compare simple values this way too by putting them in a list: > + + :let a = 5 + :let b = "5" + :echo a == b +< 1 > + :echo [a] == [b] +< 0 + + +List unpack ~ + +To unpack the items in a list to individual variables, put the variables in +square brackets, like list items: > + :let [var1, var2] = mylist + +When the number of variables does not match the number of items in the list +this produces an error. To handle any extra items from the list append ";" +and a variable name: > + :let [var1, var2; rest] = mylist + +This works like: > + :let var1 = mylist[0] + :let var2 = mylist[1] + :let rest = mylist[2:] + +Except that there is no error if there are only two items. "rest" will be an +empty list then. + + +List modification ~ + *list-modification* +To change a specific item of a list use |:let| this way: > + :let list[4] = "four" + :let listlist[0][3] = item + +To change part of a list you can specify the first and last item to be +modified. The value must at least have the number of items in the range: > + :let list[3:5] = [3, 4, 5] + +Adding and removing items from a list is done with functions. Here are a few +examples: > + :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' + +Changing the order of items in a list: > + :call sort(list) " sort a list alphabetically + :call reverse(list) " reverse the order of items + :call uniq(sort(list)) " sort and remove duplicates + + +For loop ~ + +The |:for| loop executes commands for each item in a List, String or Blob. +A variable is set to each item in sequence. Example with a List: > + :for item in mylist + : call Doit(item) + :endfor + +This works like: > + :let index = 0 + :while index < len(mylist) + : let item = mylist[index] + : :call Doit(item) + : let index = index + 1 + :endwhile + +If all you want to do is modify each item in the list then the |map()| +function will be a simpler method than a for loop. + +Just like the |:let| command, |:for| also accepts a list of variables. This +requires the argument to be a List of Lists. > + :for [lnum, col] in [[1, 3], [2, 8], [3, 0]] + : call Doit(lnum, col) + :endfor + +This works like a |:let| command is done for each list item. Again, the types +must remain the same to avoid an error. + +It is also possible to put remaining items in a List variable: > + :for [i, j; rest] in listlist + : call Doit(i, j) + : if !empty(rest) + : echo "remainder: " .. string(rest) + : endif + :endfor + +For a Blob one byte at a time is used. + +For a String one character, including any composing characters, is used as a +String. Example: > + for c in text + echo 'This character is ' .. c + endfor + + +List functions ~ + *E714* +Functions that are useful with a List: > + :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 + +Don't forget that a combination of features can make things simple. For +example, to add up all the numbers in a list: > + :exe 'let sum = ' .. join(nrlist, '+') + + +1.4 Dictionaries ~ + *dict* *Dict* *Dictionaries* *Dictionary* +A Dictionary is an associative array: Each entry has a key and a value. The +entry can be located with the key. The entries are stored without a specific +ordering. + + +Dictionary creation ~ + *E720* *E721* *E722* *E723* +A Dictionary is created with a comma-separated list of entries in curly +braces. Each entry has a key and a value, separated by a colon. Each key can +only appear once. Examples: > + :let mydict = {1: 'one', 2: 'two', 3: 'three'} + :let emptydict = {} +< *E713* *E716* *E717* +A key is always a String. You can use a Number, it will be converted to a +String automatically. Thus the String '4' and the number 4 will find the same +entry. Note that the String '04' and the Number 04 are different, since the +Number will be converted to the String '4', leading zeros are dropped. The +empty string can also be used as a key. + +In |Vim9| script a literal key can be used if it consists only of alphanumeric +characters, underscore and dash, see |vim9-literal-dict|. + *literal-Dict* *#{}* +To avoid having to put quotes around every key the #{} form can be used in +legacy script. This does require the key to consist only of ASCII letters, +digits, '-' and '_'. Example: > + :let mydict = #{zero: 0, one_key: 1, two-key: 2, 333: 3} +Note that 333 here is the string "333". Empty keys are not possible with #{}. +In |Vim9| script the #{} form cannot be used because it can be confused with +the start of a comment. + +A value can be any expression. Using a Dictionary for a value creates a +nested Dictionary: > + :let nestdict = {1: {11: 'a', 12: 'b'}, 2: {21: 'c'}} + +An extra comma after the last entry is ignored. + + +Accessing entries ~ + +The normal way to access an entry is by putting the key in square brackets: > + :let val = mydict["one"] + :let mydict["four"] = 4 + +You can add new entries to an existing Dictionary this way, unlike Lists. + +For keys that consist entirely of letters, digits and underscore the following +form can be used |expr-entry|: > + :let val = mydict.one + :let mydict.four = 4 + +Since an entry can be any type, also a List and a Dictionary, the indexing and +key lookup can be repeated: > + :echo dict.key[idx].key + + +Dictionary to List conversion ~ + +You may want to loop over the entries in a dictionary. For this you need to +turn the Dictionary into a List and pass it to |:for|. + +Most often you want to loop over the keys, using the |keys()| function: > + :for key in keys(mydict) + : echo key .. ': ' .. mydict[key] + :endfor + +The List of keys is unsorted. You may want to sort them first: > + :for key in sort(keys(mydict)) + +To loop over the values use the |values()| function: > + :for v in values(mydict) + : echo "value: " .. v + :endfor + +If you want both the key and the value use the |items()| function. It returns +a List in which each item is a List with two items, the key and the value: > + :for [key, value] in items(mydict) + : echo key .. ': ' .. value + :endfor + + +Dictionary identity ~ + *dict-identity* +Just like Lists you need to use |copy()| and |deepcopy()| to make a copy of a +Dictionary. Otherwise, assignment results in referring to the same +Dictionary: > + :let onedict = {'a': 1, 'b': 2} + :let adict = onedict + :let adict['a'] = 11 + :echo onedict['a'] + 11 + +Two Dictionaries compare equal if all the key-value pairs compare equal. For +more info see |list-identity|. + + +Dictionary modification ~ + *dict-modification* +To change an already existing entry of a Dictionary, or to add a new entry, +use |:let| this way: > + :let dict[4] = "four" + :let dict['one'] = item + +Removing an entry from a Dictionary is done with |remove()| or |:unlet|. +Three ways to remove the entry with key "aaa" from dict: > + :let i = remove(dict, 'aaa') + :unlet dict.aaa + :unlet dict['aaa'] + +Merging a Dictionary with another is done with |extend()|: > + :call extend(adict, bdict) +This extends adict with all entries from bdict. Duplicate keys cause entries +in adict to be overwritten. An optional third argument can change this. +Note that the order of entries in a Dictionary is irrelevant, thus don't +expect ":echo adict" to show the items from bdict after the older entries in +adict. + +Weeding out entries from a Dictionary can be done with |filter()|: > + :call filter(dict, 'v:val =~ "x"') +This removes all entries from "dict" with a value not matching 'x'. +This can also be used to remove all entries: > + call filter(dict, 0) + +In some situations it is not allowed to remove or add entries to a Dictionary. +Especially when iterating over all the entries. You will get *E1313* or +another error in that case. + + +Dictionary function ~ + *Dictionary-function* *self* *E725* *E862* +When a function is defined with the "dict" attribute it can be used in a +special way with a dictionary. Example: > + :function Mylen() dict + : return len(self.data) + :endfunction + :let mydict = {'data': [0, 1, 2, 3], 'len': function("Mylen")} + :echo mydict.len() + +This is like a method in object oriented programming. The entry in the +Dictionary is a |Funcref|. The local variable "self" refers to the dictionary +the function was invoked from. When using |Vim9| script you can use classes +and objects, see `:class`. + +It is also possible to add a function without the "dict" attribute as a +Funcref to a Dictionary, but the "self" variable is not available then. + + *numbered-function* *anonymous-function* +To avoid the extra name for the function it can be defined and directly +assigned to a Dictionary in this way: > + :let mydict = {'data': [0, 1, 2, 3]} + :function mydict.len() + : return len(self.data) + :endfunction + :echo mydict.len() + +The function will then get a number and the value of dict.len is a |Funcref| +that references this function. The function can only be used through a +|Funcref|. It will automatically be deleted when there is no |Funcref| +remaining that refers to it. + +It is not necessary to use the "dict" attribute for a numbered function. + +If you get an error for a numbered function, you can find out what it is with +a trick. Assuming the function is 42, the command is: > + :function g:42 + + +Functions for Dictionaries ~ + *E715* +Functions that can be used with a Dictionary: > + :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* +A Blob is a binary object. It can be used to read an image from a file and +send it over a channel, for example. + +A Blob mostly behaves like a |List| of numbers, where each number has the +value of an 8-bit byte, from 0 to 255. + + +Blob creation ~ + +A Blob can be created with a |blob-literal|: > + :let b = 0zFF00ED015DAF +Dots can be inserted between bytes (pair of hex characters) for readability, +they don't change the value: > + :let b = 0zFF00.ED01.5DAF + +A blob can be read from a file with |readfile()| passing the {type} argument +set to "B", for example: > + :let b = readfile('image.png', 'B') + +A blob can be read from a channel with the |ch_readblob()| function. + + +Blob index ~ + *blob-index* *E979* +A byte in the Blob can be accessed by putting the index in square brackets +after the Blob. Indexes are zero-based, thus the first byte has index zero. > + :let myblob = 0z00112233 + :let byte = myblob[0] " get the first byte: 0x00 + :let byte = myblob[2] " get the third byte: 0x22 + +A negative index is counted from the end. Index -1 refers to the last byte in +the Blob, -2 to the last but one byte, etc. > + :let last = myblob[-1] " get the last byte: 0x33 + +To avoid an error for an invalid index use the |get()| function. When an item +is not available it returns -1 or the default value you specify: > + :echo get(myblob, idx) + :echo get(myblob, idx, 999) + + +Blob iteration ~ + +The |:for| loop executes commands for each byte of a Blob. The loop variable is +set to each byte in the Blob. Example: > + :for byte in 0z112233 + : call Doit(byte) + :endfor +This calls Doit() with 0x11, 0x22 and 0x33. + + +Blob concatenation ~ + +Two blobs can be concatenated with the "+" operator: > + :let longblob = myblob + 0z4455 + :let myblob += 0z6677 + +To change a blob in-place see |blob-modification| below. + + +Part of a blob ~ + +A part of the Blob can be obtained by specifying the first and last index, +separated by a colon in square brackets: > + :let myblob = 0z00112233 + :let shortblob = myblob[1:2] " get 0z1122 + :let shortblob = myblob[2:-1] " get 0z2233 + +Omitting the first index is similar to zero. Omitting the last index is +similar to -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 + +If the first index is beyond the last byte of the Blob or the second index is +before the first index, the result is an empty Blob. There is no error +message. + +If the second index is equal to or greater than the length of the list the +length minus one is used: > + :echo myblob[2:8] " result: 0z2233 + + +Blob modification ~ + *blob-modification* *E1182* *E1184* +To change a specific byte of a blob use |:let| this way: > + :let blob[4] = 0x44 + +When the index is just one beyond the end of the Blob, it is appended. Any +higher index is an error. + +To change a sequence of bytes the [:] notation can be used: > + let blob[1:3] = 0z445566 +The length of the replaced bytes must be exactly the same as the value +provided. *E972* + +To change part of a blob you can specify the first and last byte to be +modified. The value must have the same number of bytes in the range: > + :let blob[3:5] = 0z334455 + +You can also use the functions |add()|, |remove()| and |insert()|. + + +Blob identity ~ + +Blobs can be compared for equality: > + if blob == 0z001122 +And for equal identity: > + if blob is otherblob +< *blob-identity* *E977* +When variable "aa" is a Blob and you assign it to another variable "bb", both +variables refer to the same Blob. Then the "is" operator returns true. + +When making a copy using [:] or |copy()| the values are the same, but the +identity is different: > + :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 + +Making a copy of a Blob is done with the |copy()| function. Using [:] also +works, as explained above. + + +1.6 More about variables ~ + *more-variables* +If you need to know the type of a variable or expression, use the |type()| +function. + +When the '!' flag is included in the 'viminfo' option, global variables that +start with an uppercase letter, and don't contain a lowercase letter, are +stored in the viminfo file |viminfo-file|. + +When the 'sessionoptions' option contains "global", global variables that +start with an uppercase letter and contain at least one lowercase letter are +stored in the session file |session-file|. + +variable name can be stored where ~ +my_var_6 not +My_Var_6 session file +MY_VAR_6 viminfo file + + +In legacy script it is possible to form a variable name with curly braces, see +|curly-braces-names|. + +============================================================================== +2. Expression syntax *expression-syntax* + *E1143* +Expression syntax summary, from least to most significant: + +|expr1| expr2 + expr2 ? expr1 : expr1 if-then-else + +|expr2| expr3 + expr3 || expr3 ... logical OR + +|expr3| expr4 + expr4 && expr4 ... logical AND + +|expr4| expr5 + expr5 == expr5 equal + expr5 != expr5 not equal + expr5 > expr5 greater than + expr5 >= expr5 greater than or equal + expr5 < expr5 smaller than + expr5 <= expr5 smaller than or equal + expr5 =~ expr5 regexp matches + expr5 !~ expr5 regexp doesn't match + + expr5 ==? expr5 equal, ignoring case + expr5 ==# expr5 equal, match case + etc. As above, append ? for ignoring case, # for + matching case + + expr5 is expr5 same |List|, |Dictionary| or |Blob| instance + expr5 isnot expr5 different |List|, |Dictionary| or |Blob| + instance + +|expr5| expr6 + expr6 << expr6 bitwise left shift + expr6 >> expr6 bitwise right shift + +|expr6| expr7 + expr7 + expr7 ... number addition, list or blob concatenation + expr7 - expr7 ... number subtraction + expr7 . expr7 ... string concatenation + expr7 .. expr7 ... string concatenation + +|expr7| expr8 + expr8 * expr8 ... number multiplication + expr8 / expr8 ... number division + expr8 % expr8 ... number modulo + +|expr8| expr9 + <type>expr9 type check and conversion (|Vim9| only) + +|expr9| expr10 + ! expr9 logical NOT + - expr9 unary minus + + expr9 unary plus + +|expr10| expr11 + expr10[expr1] byte of a String or item of a |List| + expr10[expr1 : expr1] substring of a String or sublist of a |List| + expr10.name entry in a |Dictionary| + expr10(expr1, ...) function call with |Funcref| variable + expr10->name(expr1, ...) |method| call + +|expr11| number number constant + "string" string constant, backslash is special + 'string' string constant, ' is doubled + [expr1, ...] |List| + {expr1: expr1, ...} |Dictionary| + #{key: expr1, ...} legacy |Dictionary| + &option option value + (expr1) nested expression + variable internal variable + va{ria}ble internal variable with curly braces + $VAR environment variable + @r contents of register 'r' + function(expr1, ...) function call + func{ti}on(expr1, ...) function call with curly braces + {args -> expr1} legacy lambda expression + (args) => expr1 Vim9 lambda expression + + +"..." indicates that the operations in this level can be concatenated. +Example: > + &nu || &list && &shell == "csh" + +All expressions within one level are parsed from left to right. + +Expression nesting is limited to 1000 levels deep (300 when build with MSVC) +to avoid running out of stack and crashing. *E1169* + + +expr1 *expr1* *ternary* *falsy-operator* *??* *E109* +----- + +The ternary operator: expr2 ? expr1 : expr1 +The falsy operator: expr2 ?? expr1 + +Ternary operator ~ + +In legacy script the expression before the '?' is evaluated to a number. If +it evaluates to |TRUE|, the result is the value of the expression between the +'?' and ':', otherwise the result is the value of the expression after the +':'. + +In |Vim9| script the first expression must evaluate to a boolean, see +|vim9-boolean|. + +Example: > + :echo lnum == 1 ? "top" : lnum + +Since the first expression is an "expr2", it cannot contain another ?:. The +other two expressions can, thus allow for recursive use of ?:. +Example: > + :echo lnum == 1 ? "top" : lnum == 1000 ? "last" : lnum + +To keep this readable, using |line-continuation| is suggested: > + :echo lnum == 1 + :\ ? "top" + :\ : lnum == 1000 + :\ ? "last" + :\ : lnum + +You should always put a space before the ':', otherwise it can be mistaken for +use in a variable such as "a:1". + +Falsy operator ~ + +This is also known as the "null coalescing operator", but that's too +complicated, thus we just call it the falsy operator. + +The expression before the '??' is evaluated. If it evaluates to +|truthy|, this is used as the result. Otherwise the expression after the '??' +is evaluated and used as the result. This is most useful to have a default +value for an expression that may result in zero or empty: > + echo theList ?? 'list is empty' + echo GetName() ?? 'unknown' + +These are similar, but not equal: > + expr2 ?? expr1 + expr2 ? expr2 : expr1 +In the second line "expr2" is evaluated twice. And in |Vim9| script the type +of expr2 before "?" must be a boolean. + + +expr2 and expr3 *expr2* *expr3* +--------------- + +expr3 || expr3 .. logical OR *expr-barbar* +expr4 && expr4 .. logical AND *expr-&&* + +The "||" and "&&" operators take one argument on each side. + +In legacy script the arguments are (converted to) Numbers. + +In |Vim9| script the values must be boolean, see |vim9-boolean|. Use "!!" to +convert any type to a boolean. + +The result is: + input output ~ +n1 n2 n1 || n2 n1 && n2 ~ +|FALSE| |FALSE| |FALSE| |FALSE| +|FALSE| |TRUE| |TRUE| |FALSE| +|TRUE| |FALSE| |TRUE| |FALSE| +|TRUE| |TRUE| |TRUE| |TRUE| + +The operators can be concatenated, for example: > + + &nu || &list && &shell == "csh" + +Note that "&&" takes precedence over "||", so this has the meaning of: > + + &nu || (&list && &shell == "csh") + +Once the result is known, the expression "short-circuits", that is, further +arguments are not evaluated. This is like what happens in C. For example: > + + let a = 1 + echo a || b + +This is valid even if there is no variable called "b" because "a" is |TRUE|, +so the result must be |TRUE|. Similarly below: > + + echo exists("b") && b == "yes" + +This is valid whether "b" has been defined or not. The second clause will +only be evaluated if "b" has been defined. + + +expr4 *expr4* *E1153* +----- + +expr5 {cmp} expr5 + +Compare two expr5 expressions. In legacy script the result is a 0 if it +evaluates to false, or 1 if it evaluates to true. In |Vim9| script the result +is |true| or |false|. + + *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?* *E1072* + use 'ignorecase' match case ignore case ~ +equal == ==# ==? +not equal != !=# !=? +greater than > ># >? +greater than or equal >= >=# >=? +smaller than < <# <? +smaller than or equal <= <=# <=? +regexp matches =~ =~# =~? +regexp doesn't match !~ !~# !~? +same instance is is# is? +different instance isnot isnot# isnot? + +Examples: +"abc" ==# "Abc" evaluates to 0 +"abc" ==? "Abc" evaluates to 1 +"abc" == "Abc" evaluates to 1 if 'ignorecase' is set, 0 otherwise +NOTE: In |Vim9| script 'ignorecase' is not used. + + *E691* *E692* +A |List| can only be compared with a |List| and only "equal", "not equal", +"is" and "isnot" can be used. This compares the values of the list, +recursively. Ignoring case means case is ignored when comparing item values. + + *E735* *E736* +A |Dictionary| can only be compared with a |Dictionary| and only "equal", "not +equal", "is" and "isnot" can be used. This compares the key/values of the +|Dictionary| recursively. Ignoring case means case is ignored when comparing +item values. + + *E694* +A |Funcref| can only be compared with a |Funcref| and only "equal", "not +equal", "is" and "isnot" can be used. Case is never ignored. Whether +arguments or a Dictionary are bound (with a partial) matters. The +Dictionaries must also be equal (or the same, in case of "is") and the +arguments must be equal (or the same). + +To compare Funcrefs to see if they refer to the same function, ignoring bound +Dictionary and arguments, use |get()| to get the function name: > + if get(Part1, 'name') == get(Part2, 'name') + " Part1 and Part2 refer to the same function +< *E1037* +Using "is" or "isnot" with a |List|, |Dictionary| or |Blob| checks whether +the expressions are referring to the same |List|, |Dictionary| or |Blob| +instance. A copy of a |List| is different from the original |List|. When +using "is" without a |List|, |Dictionary| or |Blob|, it is equivalent to +using "equal", using "isnot" equivalent to using "not equal". Except that +a different type means the values are different: > + echo 4 == '4' + 1 + echo 4 is '4' + 0 + echo 0 is [] + 0 +"is#"/"isnot#" and "is?"/"isnot?" can be used to match and ignore case. +In |Vim9| script this doesn't work, two strings are never identical. + +In legacy script, when comparing a String with a Number, the String is +converted to a Number, and the comparison is done on Numbers. This means +that: > + echo 0 == 'x' + 1 +because 'x' converted to a Number is zero. However: > + echo [0] == ['x'] + 0 +Inside a List or Dictionary this conversion is not used. + +In |Vim9| script the types must match. + +When comparing two Strings, this is done with strcmp() or stricmp(). This +results in the mathematical difference (comparing byte values), not +necessarily the alphabetical difference in the local language. + +When using the operators with a trailing '#', or the short version and +'ignorecase' is off, the comparing is done with strcmp(): case matters. + +When using the operators with a trailing '?', or the short version and +'ignorecase' is set, the comparing is done with stricmp(): case is ignored. + +'smartcase' is not used. + +The "=~" and "!~" operators match the lefthand argument with the righthand +argument, which is used as a pattern. See |pattern| for what a pattern is. +This matching is always done like 'magic' was set and 'cpoptions' is empty, no +matter what the actual value of 'magic' or 'cpoptions' is. This makes scripts +portable. To avoid backslashes in the regexp pattern to be doubled, use a +single-quote string, see |literal-string|. +Since a string is considered to be a single line, a multi-line pattern +(containing \n, backslash-n) will not match. However, a literal NL character +can be matched like an ordinary character. Examples: + "foo\nbar" =~ "\n" evaluates to 1 + "foo\nbar" =~ "\\n" evaluates to 0 + + +expr5 *expr5* *bitwise-shift* +----- +expr6 << expr6 bitwise left shift *expr-<<* +expr6 >> expr6 bitwise right shift *expr->>* + *E1282* *E1283* +The "<<" and ">>" operators can be used to perform bitwise left or right shift +of the left operand by the number of bits specified by the right operand. The +operands are used as positive numbers. When shifting right with ">>" the +topmost bit (sometimes called the sign bit) is cleared. If the right operand +(shift amount) is more than the maximum number of bits in a number +(|v:numbersize|) the result is zero. + + +expr6 and expr7 *expr6* *expr7* *E1036* *E1051* +--------------- +expr7 + expr7 Number addition, |List| or |Blob| concatenation *expr-+* +expr7 - expr7 Number subtraction *expr--* +expr7 . expr7 String concatenation *expr-.* +expr7 .. expr7 String concatenation *expr-..* + +For |Lists| only "+" is possible and then both expr7 must be a list. The +result is a new list with the two lists Concatenated. + +For String concatenation ".." is preferred, since "." is ambiguous, it is also +used for |Dict| member access and floating point numbers. +In |Vim9| script and when |vimscript-version| is 2 or higher, using "." is not +allowed. + +In |Vim9| script the arguments of ".." are converted to String for simple +types: Number, Float, Special and Bool. For other types |string()| should be +used. + +expr8 * expr8 Number multiplication *expr-star* +expr8 / expr8 Number division *expr-/* +expr8 % expr8 Number modulo *expr-%* + +In legacy script, for all operators except "." and "..", Strings are converted +to Numbers. + +For bitwise operators see |and()|, |or()| and |xor()|. + +Note the difference between "+" and ".." in legacy script: + "123" + "456" = 579 + "123" .. "456" = "123456" + +Since '..' has the same precedence as '+' and '-', you need to read: > + 1 .. 90 + 90.0 +As: > + (1 .. 90) + 90.0 +That works in legacy script, since the String "190" is automatically converted +to the Number 190, which can be added to the Float 90.0. However: > + 1 .. 90 * 90.0 +Should be read as: > + 1 .. (90 * 90.0) +Since '..' has lower precedence than '*'. This does NOT work, since this +attempts to concatenate a Float and a String. + +When dividing a Number by zero the result depends on the value: + 0 / 0 = -0x80000000 (like NaN for Float) + >0 / 0 = 0x7fffffff (like positive infinity) + <0 / 0 = -0x7fffffff (like negative infinity) + (before Vim 7.2 it was always 0x7fffffff) +In |Vim9| script dividing a number by zero is an error. *E1154* + +When 64-bit Number support is enabled: + 0 / 0 = -0x8000000000000000 (like NaN for Float) + >0 / 0 = 0x7fffffffffffffff (like positive infinity) + <0 / 0 = -0x7fffffffffffffff (like negative infinity) + +When the righthand side of '%' is zero, the result is 0. + +None of these work for |Funcref|s. + +".", ".." and "%" do not work for Float. *E804* *E1035* + + +expr8 *expr8* +----- +<type>expr9 + +This is only available in |Vim9| script, see |type-casting|. + + +expr9 *expr9* +----- +! expr9 logical NOT *expr-!* +- expr9 unary minus *expr-unary--* ++ expr9 unary plus *expr-unary-+* + +For '!' |TRUE| becomes |FALSE|, |FALSE| becomes |TRUE| (one). +For '-' the sign of the number is changed. +For '+' the number is unchanged. Note: "++" has no effect. + +In legacy script a String will be converted to a Number first. Note that if +the string does not start with a digit you likely don't get what you expect. + +In |Vim9| script an error is given when "-" or "+" is used and the type is not +a number. + +In |Vim9| script "!" can be used for any type and the result is always a +boolean. Use "!!" to convert any type to a boolean, according to whether the +value is |falsy|. + +These three can be repeated and mixed. Examples: + !-1 == 0 + !!8 == 1 + --9 == 9 + + +expr10 *expr10* +------ +This expression is either |expr11| or a sequence of the alternatives below, +in any order. E.g., these are all possible: + expr10[expr1].name + expr10.name[expr1] + expr10(expr1, ...)[expr1].name + expr10->(expr1, ...)[expr1] +Evaluation is always from left to right. + +expr10[expr1] item of String or |List| *expr-[]* *E111* + *E909* *subscript* *E1062* +In legacy Vim script: +If expr10 is a Number or String this results in a String that contains the +expr1'th single byte from expr10. expr10 is used as a String (a number is +automatically converted to a String), expr1 as a Number. This doesn't +recognize multibyte encodings, see `byteidx()` for an alternative, or use +`split()` to turn the string into a list of characters. Example, to get the +byte under the cursor: > + :let c = getline(".")[col(".") - 1] + +In |Vim9| script: *E1147* *E1148* +If expr10 is a String this results in a String that contains the expr1'th +single character (including any composing characters) from expr10. To use byte +indexes use |strpart()|. + +Index zero gives the first byte or character. Careful: text column numbers +start with one! + +If the length of the String is less than the index, the result is an empty +String. A negative index always results in an empty string (reason: backward +compatibility). Use [-1:] to get the last byte or character. +In Vim9 script a negative index is used like with a list: count from the end. + +If expr10 is a |List| then it results the item at index expr1. See |list-index| +for possible index values. If the index is out of range this results in an +error. Example: > + :let item = mylist[-1] " get last item + +Generally, if a |List| index is equal to or higher than the length of the +|List|, or more negative than the length of the |List|, this results in an +error. + + +expr10[expr1a : expr1b] substring or |sublist| *expr-[:]* *substring* + +If expr10 is a String this results in the substring with the bytes or +characters from expr1a to and including expr1b. expr10 is used as a String, +expr1a and expr1b are used as a Number. + +In legacy Vim script the indexes are byte indexes. This doesn't recognize +multibyte encodings, see |byteidx()| for computing the indexes. If expr10 is +a Number it is first converted to a String. + +In Vim9 script the indexes are character indexes and include composing +characters. To use byte indexes use |strpart()|. To use character indexes +without including composing characters use |strcharpart()|. + +The item at index expr1b is included, it is inclusive. For an exclusive index +use the |slice()| function. + +If expr1a is omitted zero is used. If expr1b is omitted the length of the +string minus one is used. + +A negative number can be used to measure from the end of the string. -1 is +the last character, -2 the last but one, etc. + +If an index goes out of range for the string characters are omitted. If +expr1b is smaller than expr1a the result is an empty string. + +Examples: > + :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 +< + *slice* +If expr10 is a |List| this results in a new |List| with the items indicated by +the indexes expr1a and expr1b. This works like with a String, as explained +just above. Also see |sublist| below. Examples: > + :let l = mylist[:3] " first four items + :let l = mylist[4:4] " List with one item + :let l = mylist[:] " shallow copy of a List + +If expr10 is a |Blob| this results in a new |Blob| with the bytes in the +indexes expr1a and expr1b, inclusive. Examples: > + :let b = 0zDEADBEEF + :let bs = b[1:2] " 0zADBE + :let bs = b[:] " copy of 0zDEADBEEF + +Using expr10[expr1] or expr10[expr1a : expr1b] on a |Funcref| results in an +error. + +Watch out for confusion between a namespace and a variable followed by a colon +for a sublist: > + mylist[n:] " uses variable n + mylist[s:] " uses namespace s:, error! + + +expr10.name entry in a |Dictionary| *expr-entry* + *E1203* *E1229* +If expr10 is a |Dictionary| and it is followed by a dot, then the following +name will be used as a key in the |Dictionary|. This is just like: +expr10[name]. + +The name must consist of alphanumeric characters, just like a variable name, +but it may start with a number. Curly braces cannot be used. + +There must not be white space before or after the dot. + +Examples: > + :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 + +Note that the dot is also used for String concatenation. To avoid confusion +always put spaces around the dot for String concatenation. + + +expr10(expr1, ...) |Funcref| function call *E1085* + +When expr10 is a |Funcref| type variable, invoke the function it refers to. + + +expr10->name([args]) method call *method* *->* +expr10->{lambda}([args]) + *E260* *E276* *E1265* +For methods that are also available as global functions this is the same as: > + name(expr10 [, args]) +There can also be methods specifically for the type of "expr10". + +This allows for chaining, passing the value that one method returns to the +next method: > + mylist->filter(filterexpr)->map(mapexpr)->sort()->join() +< +Example of using a lambda: > + GetPercentage()->{x -> x * 100}()->printf('%d%%') +< +When using -> the |expr9| operators will be applied first, thus: > + -1.234->string() +Is equivalent to: > + (-1.234)->string() +And NOT: > + -(1.234->string()) + +What comes after "->" can be a name, a simple expression (not containing any +parenthesis), or any expression in parentheses: > + base->name(args) + base->some.name(args) + base->alist[idx](args) + base->(getFuncRef())(args) +Note that in the last call the base is passed to the function resulting from +"(getFuncRef())", inserted before "args". *E1275* + + *E274* +"->name(" must not contain white space. There can be white space before the +"->" and after the "(", thus you can split the lines like this: > + mylist + \ ->filter(filterexpr) + \ ->map(mapexpr) + \ ->sort() + \ ->join() + +When using the lambda form there must be no white space between the } and the +(. + + + *expr11* +number +------ +number number constant *expr-number* + + *0x* *hex-number* *0o* *octal-number* *binary-number* +Decimal, Hexadecimal (starting with 0x or 0X), Binary (starting with 0b or 0B) +and Octal (starting with 0, 0o or 0O). + +Assuming 64 bit numbers are used (see |v:numbersize|) an unsigned number is +truncated to 0x7fffffffffffffff or 9223372036854775807. You can use -1 to get +0xffffffffffffffff. + + *floating-point-format* +Floating point numbers can be written in two forms: + + [-+]{N}.{M} + [-+]{N}.{M}[eE][-+]{exp} + +{N} and {M} are numbers. Both {N} and {M} must be present and can only +contain digits, except that in |Vim9| script in {N} single quotes between +digits are ignored. +[-+] means there is an optional plus or minus sign. +{exp} is the exponent, power of 10. +Only a decimal point is accepted, not a comma. No matter what the current +locale is. + +Examples: + 123.456 + +0.0001 + 55.0 + -0.123 + 1.234e03 + 1.0E-6 + -3.1416e+88 + +These are INVALID: + 3. empty {M} + 1e40 missing .{M} + +Rationale: +Before floating point was introduced, the text "123.456" was interpreted as +the two numbers "123" and "456", both converted to a string and concatenated, +resulting in the string "123456". Since this was considered pointless, and we +could not find it intentionally being used in Vim scripts, this backwards +incompatibility was accepted in favor of being able to use the normal notation +for floating point numbers. + + *float-pi* *float-e* +A few useful values to copy&paste: > + :let pi = 3.14159265359 + :let e = 2.71828182846 +Or, if you don't want to write them in as floating-point literals, you can +also use functions, like the following: > + :let pi = acos(-1.0) + :let e = exp(1.0) +< + *floating-point-precision* +The precision and range of floating points numbers depends on what "double" +means in the library Vim was compiled with. There is no way to change this at +runtime. + +The default for displaying a |Float| is to use 6 decimal places, like using +printf("%g", f). You can select something else when using the |printf()| +function. Example: > + :echo printf('%.15e', atan(1)) +< 7.853981633974483e-01 + + + +string *string* *String* *expr-string* *E114* +------ +"string" string constant *expr-quote* + +Note that double quotes are used. + +A string constant accepts these special characters: +\... three-digit octal number (e.g., "\316") +\.. two-digit octal number (must be followed by non-digit) +\. one-digit octal number (must be followed by non-digit) +\x.. byte specified with two hex numbers (e.g., "\x1f") +\x. byte specified with one hex number (must be followed by non-hex char) +\X.. same as \x.. +\X. same as \x. +\u.... character specified with up to 4 hex numbers, stored according to the + current value of 'encoding' (e.g., "\u02a4") +\U.... same as \u but allows up to 8 hex numbers. +\b backspace <BS> +\e escape <Esc> +\f formfeed 0x0C +\n newline <NL> +\r return <CR> +\t tab <Tab> +\\ backslash +\" double quote +\<xxx> Special key named "xxx". e.g. "\<C-W>" for CTRL-W. This is for use + in mappings, the 0x80 byte is escaped. + To use the double quote character it must be escaped: "<M-\">". + Don't use <Char-xxxx> to get a UTF-8 character, use \uxxxx as + mentioned above. +\<*xxx> Like \<xxx> but prepends a modifier instead of including it in the + character. E.g. "\<C-w>" is one character 0x17 while "\<*C-w>" is four + bytes: 3 for the CTRL modifier and then character "W". + +Note that "\xff" is stored as the byte 255, which may be invalid in some +encodings. Use "\u00ff" to store character 255 according to the current value +of 'encoding'. + +Note that "\000" and "\x00" force the end of the string. + + +blob-literal *blob-literal* *E973* +------------ + +Hexadecimal starting with 0z or 0Z, with an arbitrary number of bytes. +The sequence must be an even number of hex characters. Example: > + :let b = 0zFF00ED015DAF + + +literal-string *literal-string* *E115* +--------------- +'string' string constant *expr-'* + +Note that single quotes are used. + +This string is taken as it is. No backslashes are removed or have a special +meaning. The only exception is that two quotes stand for one quote. + +Single quoted strings are useful for patterns, so that backslashes do not need +to be doubled. These two commands are equivalent: > + if a =~ "\\s*" + if a =~ '\s*' + + +interpolated-string *$quote* *interpolated-string* +-------------------- +$"string" interpolated string constant *expr-$quote* +$'string' interpolated literal string constant *expr-$'* + +Interpolated strings are an extension of the |string| and |literal-string|, +allowing the inclusion of Vim script expressions (see |expr1|). Any +expression returning a value can be enclosed between curly braces. The value +is converted to a string. All the text and results of the expressions +are concatenated to make a new string. + *E1278* *E1279* +To include an opening brace '{' or closing brace '}' in the string content +double it. For double quoted strings using a backslash also works. A single +closing brace '}' will result in an error. + +Examples: > + let your_name = input("What's your name? ") +< What's your name? Peter ~ +> + echo + echo $"Hello, {your_name}!" +< Hello, Peter! ~ +> + echo $"The square root of {{9}} is {sqrt(9)}" +< The square root of {9} is 3.0 ~ + + *string-offset-encoding* +A string consists of multiple characters. How the characters are stored +depends on 'encoding'. Most common is UTF-8, which uses one byte for ASCII +characters, two bytes for other latin characters and more bytes for other +characters. + +A string offset can count characters or bytes. Other programs may use +UTF-16 encoding (16-bit words) and an offset of UTF-16 words. Some functions +use byte offsets, usually for UTF-8 encoding. Other functions use character +offsets, in which case the encoding doesn't matter. + +The different offsets for the string "a©😊" are below: + + UTF-8 offsets: + [0]: 61, [1]: C2, [2]: A9, [3]: F0, [4]: 9F, [5]: 98, [6]: 8A + UTF-16 offsets: + [0]: 0061, [1]: 00A9, [2]: D83D, [3]: DE0A + UTF-32 (character) offsets: + [0]: 00000061, [1]: 000000A9, [2]: 0001F60A + +You can use the "g8" and "ga" commands on a character to see the +decimal/hex/octal values. + +The functions |byteidx()|, |utf16idx()| and |charidx()| can be used to convert +between these indices. The functions |strlen()|, |strutf16len()| and +|strcharlen()| return the number of bytes, UTF-16 code units and characters in +a string respectively. + +option *expr-option* *E112* *E113* +------ +&option option value, local value if possible +&g:option global option value +&l:option local option value + +Examples: > + echo "tabstop is " .. &tabstop + if &insertmode + +Any option name can be used here. See |options|. When using the local value +and there is no buffer-local or window-local value, the global value is used +anyway. + + +register *expr-register* *@r* +-------- +@r contents of register 'r' + +The result is the contents of the named register, as a single string. +Newlines are inserted where required. To get the contents of the unnamed +register use @" or @@. See |registers| for an explanation of the available +registers. + +When using the '=' register you get the expression itself, not what it +evaluates to. Use |eval()| to evaluate it. + + +nesting *expr-nesting* *E110* +------- +(expr1) nested expression + + +environment variable *expr-env* +-------------------- +$VAR environment variable + +The String value of any environment variable. When it is not defined, the +result is an empty string. + +The functions `getenv()` and `setenv()` can also be used and work for +environment variables with non-alphanumeric names. +The function `environ()` can be used to get a Dict with all environment +variables. + + + *expr-env-expand* +Note that there is a difference between using $VAR directly and using +expand("$VAR"). Using it directly will only expand environment variables that +are known inside the current Vim session. Using expand() will first try using +the environment variables known inside the current Vim session. If that +fails, a shell will be used to expand the variable. This can be slow, but it +does expand all variables that the shell knows about. Example: > + :echo $shell + :echo expand("$shell") +The first one probably doesn't echo anything, the second echoes the $shell +variable (if your shell supports it). + + +internal variable *expr-variable* *E1015* *E1089* +----------------- +variable internal variable +See below |internal-variables|. + + +function call *expr-function* *E116* *E118* *E119* *E120* +------------- +function(expr1, ...) function call +See below |functions|. + + +lambda expression *expr-lambda* *lambda* +----------------- +{args -> expr1} legacy lambda expression *E451* +(args) => expr1 |Vim9| lambda expression + +A lambda expression creates a new unnamed function which returns the result of +evaluating |expr1|. Lambda expressions differ from |user-functions| in +the following ways: + +1. The body of the lambda expression is an |expr1| and not a sequence of |Ex| + commands. +2. The prefix "a:" should not be used for arguments. E.g.: > + :let F = {arg1, arg2 -> arg1 - arg2} + :echo F(5, 2) +< 3 + +The arguments are optional. Example: > + :let F = {-> 'error function'} + :echo F('ignored') +< error function + +The |Vim9| lambda does not only use a different syntax, it also adds type +checking and can be split over multiple lines, see |vim9-lambda|. + + *closure* +Lambda expressions can access outer scope variables and arguments. This is +often called a closure. Example where "i" and "a:arg" are used in a lambda +while they already exist in the function scope. They remain valid even after +the function returns: > + :function Foo(arg) + : let i = 3 + : return {x -> x + i - a:arg} + :endfunction + :let Bar = Foo(4) + :echo Bar(6) +< 5 + +Note that the variables must exist in the outer scope before the lambda is +defined for this to work. See also |:func-closure|. + +Lambda and closure support can be checked with: > + if has('lambda') + +Examples for using a lambda expression with |sort()|, |map()| and |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] + +The lambda expression is also useful for Channel, Job and timer: > + :let timer = timer_start(500, + \ {-> execute("echo 'Handler called'", "")}, + \ {'repeat': 3}) +< Handler called + Handler called + Handler called + +Note that it is possible to cause memory to be used and not freed if the +closure is referenced by the context it depends on: > + function Function() + let x = 0 + let F = {-> x} + endfunction +The closure uses "x" from the function scope, and "F" in that same scope +refers to the closure. This cycle results in the memory not being freed. +Recommendation: don't do this. + +Notice how execute() is used to execute an Ex command. That's ugly though. +In Vim9 script you can use a command block, see |inline-function|. + +Although you can use the loop variable of a `for` command, it must still exist +when the closure is called, otherwise you get an error. *E1302* + +Lambda expressions have internal names like '<lambda>42'. If you get an error +for a lambda expression, you can find what it is with the following command: > + :function <lambda>42 +See also: |numbered-function| + +============================================================================== +3. Internal variable *internal-variables* *E461* *E1001* + +An internal variable name can be made up of letters, digits and '_'. But it +cannot start with a digit. In legacy script it is also possible to use curly +braces, see |curly-braces-names|. + +In legacy script an internal variable is created with the ":let" command +|:let|. An internal variable is explicitly destroyed with the ":unlet" +command |:unlet|. +Using a name that is not an internal variable or refers to a variable that has +been destroyed results in an error. + +In |Vim9| script `:let` is not used and variables work differently, see |:var|. + + *variable-scope* +There are several name spaces for variables. Which one is to be used is +specified by what is prepended: + + (nothing) In a function: local to the function; + in a legacy script: global; + in a |Vim9| script: local to the script +|buffer-variable| b: Local to the current buffer. +|window-variable| w: Local to the current window. +|tabpage-variable| t: Local to the current tab page. +|global-variable| g: Global. +|local-variable| l: Local to a function (only in a legacy function) +|script-variable| s: Local to a |:source|'ed Vim script. +|function-argument| a: Function argument (only in a legacy function). +|vim-variable| v: Global, predefined by Vim. + +The scope name by itself can be used as a |Dictionary|. For example, to +delete all script-local variables: > + :for k in keys(s:) + : unlet s:[k] + :endfor + +Note: in Vim9 script variables can also be local to a block of commands, see +|vim9-scopes|. + *buffer-variable* *b:var* *b:* +A variable name that is preceded with "b:" is local to the current buffer. +Thus you can have several "b:foo" variables, one for each buffer. +This kind of variable is deleted when the buffer is wiped out or deleted with +|:bdelete|. + +One local buffer variable is predefined: + *b:changedtick* *changetick* +b:changedtick The total number of changes to the current buffer. It is + incremented for each change. An undo command is also a change + in this case. Resetting 'modified' when writing the buffer is + also counted. + This can be used to perform an action only when the buffer has + changed. Example: > + :if my_changedtick != b:changedtick + : let my_changedtick = b:changedtick + : call My_Update() + :endif +< You cannot change or delete the b:changedtick variable. + If you need more information about the change see + |listener_add()|. + + *window-variable* *w:var* *w:* +A variable name that is preceded with "w:" is local to the current window. It +is deleted when the window is closed. + + *tabpage-variable* *t:var* *t:* +A variable name that is preceded with "t:" is local to the current tab page, +It is deleted when the tab page is closed. {not available when compiled +without the |+windows| feature} + + *global-variable* *g:var* *g:* +Inside functions and in |Vim9| script global variables are accessed with "g:". +Omitting this will access a variable local to a function or script. "g:" +can also be used in any other place if you like. + + *local-variable* *l:var* *l:* +Inside functions local variables are accessed without prepending anything. +But you can also prepend "l:" if you like. However, without prepending "l:" +you may run into reserved variable names. For example "count". By itself it +refers to "v:count". Using "l:count" you can have a local variable with the +same name. + + *script-variable* *s:var* +In a legacy Vim script variables starting with "s:" can be used. They cannot +be accessed from outside of the scripts, thus are local to the script. +In |Vim9| script the "s:" prefix can be omitted, variables are script-local by +default. + +They can be used in: +- commands executed while the script is sourced +- functions defined in the script +- autocommands defined in the script +- functions and autocommands defined in functions and autocommands which were + defined in the script (recursively) +- user defined commands defined in the script +Thus not in: +- other scripts sourced from this one +- mappings +- menus +- etc. + +Script variables can be used to avoid conflicts with global variable names. +Take this example: > + + let s:counter = 0 + function MyCounter() + let s:counter = s:counter + 1 + echo s:counter + endfunction + command Tick call MyCounter() + +You can now invoke "Tick" from any script, and the "s:counter" variable in +that script will not be changed, only the "s:counter" in the script where +"Tick" was defined is used. + +Another example that does the same: > + + let s:counter = 0 + command Tick let s:counter = s:counter + 1 | echo s:counter + +When calling a function and invoking a user-defined command, the context for +script variables is set to the script where the function or command was +defined. + +The script variables are also available when a function is defined inside a +function that is defined in a script. Example: > + + 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 + +This defines the MyCounter() function either for counting up or counting down +when calling StartCounting(). It doesn't matter from where StartCounting() is +called, the s:counter variable will be accessible in MyCounter(). + +When the same script is sourced again it will use the same script variables. +They will remain valid as long as Vim is running. This can be used to +maintain a counter: > + + 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 + +Note that this means that filetype plugins don't get a different set of script +variables for each buffer. Use local buffer variables instead |b:var|. + + +PREDEFINED VIM VARIABLES *vim-variable* *v:var* *v:* + *E963* *E1063* +Some variables can be set by the user, but the type cannot be changed. + + *v:argv* *argv-variable* +v:argv The command line arguments Vim was invoked with. This is a + list of strings. The first item is the Vim command. + See |v:progpath| for the command with full path. + + *v:beval_col* *beval_col-variable* +v:beval_col The number of the column, over which the mouse pointer is. + This is the byte index in the |v:beval_lnum| line. + Only valid while evaluating the 'balloonexpr' option. + + *v:beval_bufnr* *beval_bufnr-variable* +v:beval_bufnr The number of the buffer, over which the mouse pointer is. Only + valid while evaluating the 'balloonexpr' option. + + *v:beval_lnum* *beval_lnum-variable* +v:beval_lnum The number of the line, over which the mouse pointer is. Only + valid while evaluating the 'balloonexpr' option. + + *v:beval_text* *beval_text-variable* +v:beval_text The text under or after the mouse pointer. Usually a word as + it is useful for debugging a C program. 'iskeyword' applies, + but a dot and "->" before the position is included. When on a + ']' the text before it is used, including the matching '[' and + word before it. When on a Visual area within one line the + highlighted text is used. Also see |<cexpr>|. + Only valid while evaluating the 'balloonexpr' option. + + *v:beval_winnr* *beval_winnr-variable* +v:beval_winnr The number of the window, over which the mouse pointer is. Only + valid while evaluating the 'balloonexpr' option. The first + window has number zero (unlike most other places where a + window gets a number). + + *v:beval_winid* *beval_winid-variable* +v:beval_winid The |window-ID| of the window, over which the mouse pointer + is. Otherwise like v:beval_winnr. + + *v:char* *char-variable* +v:char Argument for evaluating 'formatexpr' and used for the typed + character when using <expr> in an abbreviation |:map-<expr>|. + It is also used by the |InsertCharPre| and |InsertEnter| events. + + *v:charconvert_from* *charconvert_from-variable* +v:charconvert_from + The name of the character encoding of a file to be converted. + Only valid while evaluating the 'charconvert' option. + + *v:charconvert_to* *charconvert_to-variable* +v:charconvert_to + The name of the character encoding of a file after conversion. + Only valid while evaluating the 'charconvert' option. + + *v:cmdarg* *cmdarg-variable* +v:cmdarg This variable is used for two purposes: + 1. The extra arguments given to a file read/write command. + Currently these are "++enc=" and "++ff=". This variable is + set before an autocommand event for a file read/write + command is triggered. There is a leading space to make it + possible to append this variable directly after the + read/write command. Note: The "+cmd" argument isn't + included here, because it will be executed anyway. + 2. When printing a PostScript file with ":hardcopy" this is + the argument for the ":hardcopy" command. This can be used + in 'printexpr'. + + *v:cmdbang* *cmdbang-variable* +v:cmdbang Set like v:cmdarg for a file read/write command. When a "!" + was used the value is 1, otherwise it is 0. Note that this + can only be used in autocommands. For user commands |<bang>| + can be used. + *v:collate* *collate-variable* +v:collate The current locale setting for collation order of the runtime + environment. This allows Vim scripts to be aware of the + current locale encoding. Technical: it's the value of + LC_COLLATE. When not using a locale the value is "C". + This variable can not be set directly, use the |:language| + command. + See |multi-lang|. + + *v:colornames* +v:colornames A dictionary that maps color names to hex color strings. These + color names can be used with the |highlight-guifg|, + |highlight-guibg|, and |highlight-guisp| parameters. Updating + an entry in v:colornames has no immediate effect on the syntax + highlighting. The highlight commands (probably in a + colorscheme script) need to be re-evaluated in order to use + the updated color values. For example: > + + :let v:colornames['fuscia'] = '#cf3ab4' + :let v:colornames['mauve'] = '#915f6d' + :highlight Normal guifg=fuscia guibg=mauve +< + This cannot be used to override the |cterm-colors| but it can + be used to override other colors. For example, the X11 colors + defined in the `colors/lists/default.vim` (previously defined + in |rgb.txt|). When defining new color names in a plugin, the + recommended practice is to set a color entry only when it does + not already exist. For example: > + + :call extend(v:colornames, { + \ 'fuscia': '#cf3ab4', + \ 'mauve': '#915f6d, + \ }, 'keep') +< + Using |extend()| with the 'keep' option updates each color only + if it did not exist in |v:colornames|. Doing so allows the + user to choose the precise color value for a common name + by setting it in their |.vimrc|. + + It is possible to remove entries from this dictionary but + doing so is NOT recommended, because it is disruptive to + other scripts. It is also unlikely to achieve the desired + result because the |:colorscheme| and |:highlight| commands will + both automatically load all `colors/lists/default.vim` color + scripts. + + *v:completed_item* *completed_item-variable* +v:completed_item + |Dictionary| containing the |complete-items| for the most + recently completed word after |CompleteDone|. The + |Dictionary| is empty if the completion failed. + Note: Plugins can modify the value to emulate the builtin + |CompleteDone| event behavior. + + *v:count* *count-variable* +v:count The count given for the last Normal mode command. Can be used + to get the count before a mapping. Read-only. Example: > + :map _x :<C-U>echo "the count is " .. v:count<CR> +< Note: The <C-U> is required to remove the line range that you + get when typing ':' after a count. + When there are two counts, as in "3d2w", they are multiplied, + just like what happens in the command, "d6w" for the example. + Also used for evaluating the 'formatexpr' option. + "count" also works, for backwards compatibility, unless + |scriptversion| is 3 or higher. + + *v:count1* *count1-variable* +v:count1 Just like "v:count", but defaults to one when no count is + used. + + *v:ctype* *ctype-variable* +v:ctype The current locale setting for characters of the runtime + environment. This allows Vim scripts to be aware of the + current locale encoding. Technical: it's the value of + LC_CTYPE. When not using a locale the value is "C". + This variable can not be set directly, use the |:language| + command. + See |multi-lang|. + + *v:dying* *dying-variable* +v:dying Normally zero. When a deadly signal is caught it's set to + one. When multiple signals are caught the number increases. + Can be used in an autocommand to check if Vim didn't + terminate normally. {only works on Unix} + Example: > + :au VimLeave * if v:dying | echo "\nAAAAaaaarrrggghhhh!!!\n" | endif +< Note: if another deadly signal is caught when v:dying is one, + VimLeave autocommands will not be executed. + + *v:exiting* *exiting-variable* +v:exiting Vim exit code. Normally zero, non-zero when something went + wrong. The value is v:null before invoking the |VimLeavePre| + and |VimLeave| autocmds. See |:q|, |:x| and |:cquit|. + Example: > + :au VimLeave * echo "Exit value is " .. v:exiting +< + *v:echospace* *echospace-variable* +v:echospace Number of screen cells that can be used for an `:echo` message + in the last screen line before causing the |hit-enter-prompt|. + Depends on 'showcmd', 'ruler' and 'columns'. You need to + check 'cmdheight' for whether there are full-width lines + available above the last line. + + *v:errmsg* *errmsg-variable* +v:errmsg Last given error message. It's allowed to set this variable. + Example: > + :let v:errmsg = "" + :silent! next + :if v:errmsg != "" + : ... handle error +< "errmsg" also works, for backwards compatibility, unless + |scriptversion| is 3 or higher. + + *v:errors* *errors-variable* *assert-return* +v:errors Errors found by assert functions, such as |assert_true()|. + This is a list of strings. + The assert functions append an item when an assert fails. + The return value indicates this: a one is returned if an item + was added to v:errors, otherwise zero is returned. + To remove old results make it empty: > + :let v:errors = [] +< If v:errors is set to anything but a list it is made an empty + list by the assert function. + + *v:event* *event-variable* +v:event Dictionary containing information about the current + |autocommand|. See the specific event for what it puts in + this dictionary. + The dictionary is emptied when the |autocommand| finishes, + please refer to |dict-identity| for how to get an independent + copy of it. Use |deepcopy()| if you want to keep the + information after the event triggers. Example: > + au TextYankPost * let g:foo = deepcopy(v:event) +< + *v:exception* *exception-variable* +v:exception The value of the exception most recently caught and not + finished. See also |v:throwpoint| and |throw-variables|. + Example: > + :try + : throw "oops" + :catch /.*/ + : echo "caught " .. v:exception + :endtry +< Output: "caught oops". + + *v:false* *false-variable* +v:false A Number with value zero. Used to put "false" in JSON. See + |json_encode()|. + When used as a string this evaluates to "v:false". > + echo v:false +< v:false ~ + That is so that eval() can parse the string back to the same + value. Read-only. + In |Vim9| script "false" can be used which has a boolean type. + + *v:fcs_reason* *fcs_reason-variable* +v:fcs_reason The reason why the |FileChangedShell| event was triggered. + Can be used in an autocommand to decide what to do and/or what + to set v:fcs_choice to. Possible values: + deleted file no longer exists + conflict file contents, mode or timestamp was + changed and buffer is modified + changed file contents has changed + mode mode of file changed + time only file timestamp changed + + *v:fcs_choice* *fcs_choice-variable* +v:fcs_choice What should happen after a |FileChangedShell| event was + triggered. Can be used in an autocommand to tell Vim what to + do with the affected buffer: + reload Reload the buffer (does not work if + the file was deleted). + edit Reload the buffer and detect the + values for options such as + 'fileformat', 'fileencoding', 'binary' + (does not work if the file was + deleted). + ask Ask the user what to do, as if there + was no autocommand. Except that when + only the timestamp changed nothing + will happen. + <empty> Nothing, the autocommand should do + everything that needs to be done. + The default is empty. If another (invalid) value is used then + Vim behaves like it is empty, there is no warning message. + + *v:fname* *fname-variable* +v:fname When evaluating 'includeexpr': the file name that was + detected. Empty otherwise. + + *v:fname_in* *fname_in-variable* +v:fname_in The name of the input file. Valid while evaluating: + option used for ~ + 'charconvert' file to be converted + 'diffexpr' original file + 'patchexpr' original file + 'printexpr' file to be printed + And set to the swap file name for |SwapExists|. + + *v:fname_out* *fname_out-variable* +v:fname_out The name of the output file. Only valid while + evaluating: + option used for ~ + 'charconvert' resulting converted file (*) + 'diffexpr' output of diff + 'patchexpr' resulting patched file + (*) When doing conversion for a write command (e.g., ":w + file") it will be equal to v:fname_in. When doing conversion + for a read command (e.g., ":e file") it will be a temporary + file and different from v:fname_in. + + *v:fname_new* *fname_new-variable* +v:fname_new The name of the new version of the file. Only valid while + evaluating 'diffexpr'. + + *v:fname_diff* *fname_diff-variable* +v:fname_diff The name of the diff (patch) file. Only valid while + evaluating 'patchexpr'. + + *v:folddashes* *folddashes-variable* +v:folddashes Used for 'foldtext': dashes representing foldlevel of a closed + fold. + Read-only in the |sandbox|. |fold-foldtext| + + *v:foldlevel* *foldlevel-variable* +v:foldlevel Used for 'foldtext': foldlevel of closed fold. + Read-only in the |sandbox|. |fold-foldtext| + + *v:foldend* *foldend-variable* +v:foldend Used for 'foldtext': last line of closed fold. + Read-only in the |sandbox|. |fold-foldtext| + + *v:foldstart* *foldstart-variable* +v:foldstart Used for 'foldtext': first line of closed fold. + Read-only in the |sandbox|. |fold-foldtext| + + *v:hlsearch* *hlsearch-variable* +v:hlsearch Variable that indicates whether search highlighting is on. + Setting it makes sense only if 'hlsearch' is enabled which + requires |+extra_search|. Setting this variable to zero acts + like the |:nohlsearch| command, setting it to one acts like > + let &hlsearch = &hlsearch +< Note that the value is restored when returning from a + function. |function-search-undo|. + + *v:insertmode* *insertmode-variable* +v:insertmode Used for the |InsertEnter| and |InsertChange| autocommand + events. Values: + i Insert mode + r Replace mode + v Virtual Replace mode + + *v:key* *key-variable* +v:key Key of the current item of a |Dictionary|. Only valid while + evaluating the expression used with |map()| and |filter()|. + Read-only. + + *v:lang* *lang-variable* +v:lang The current locale setting for messages of the runtime + environment. This allows Vim scripts to be aware of the + current language. Technical: it's the value of LC_MESSAGES. + The value is system dependent. + This variable can not be set directly, use the |:language| + command. + It can be different from |v:ctype| when messages are desired + in a different language than what is used for character + encoding. See |multi-lang|. + + *v:lc_time* *lc_time-variable* +v:lc_time The current locale setting for time messages of the runtime + environment. This allows Vim scripts to be aware of the + current language. Technical: it's the value of LC_TIME. + This variable can not be set directly, use the |:language| + command. See |multi-lang|. + + *v:lnum* *lnum-variable* +v:lnum Line number for the 'foldexpr' |fold-expr|, 'formatexpr' and + 'indentexpr' expressions, tab page number for 'guitablabel' + and 'guitabtooltip'. Only valid while one of these + expressions is being evaluated. Read-only when in the + |sandbox|. + + *v:maxcol* *maxcol-variable* +v:maxcol Maximum line length. Depending on where it is used it can be + screen columns, characters or bytes. The value currently is + 2147483647 on all systems. + + *v:mouse_win* *mouse_win-variable* +v:mouse_win Window number for a mouse click obtained with |getchar()|. + First window has number 1, like with |winnr()|. The value is + zero when there was no mouse button click. + + *v:mouse_winid* *mouse_winid-variable* +v:mouse_winid Window ID for a mouse click obtained with |getchar()|. + The value is zero when there was no mouse button click. + + *v:mouse_lnum* *mouse_lnum-variable* +v:mouse_lnum Line number for a mouse click obtained with |getchar()|. + This is the text line number, not the screen line number. The + value is zero when there was no mouse button click. + + *v:mouse_col* *mouse_col-variable* +v:mouse_col Column number for a mouse click obtained with |getchar()|. + This is the screen column number, like with |virtcol()|. The + value is zero when there was no mouse button click. + + *v:none* *none-variable* *None* +v:none An empty String. Used to put an empty item in JSON. See + |json_encode()|. + This can also be used as a function argument to use the + default value, see |none-function_argument|. + When used as a number this evaluates to zero. + When used as a string this evaluates to "v:none". > + echo v:none +< v:none ~ + That is so that eval() can parse the string back to the same + value. Read-only. + Note that using `== v:none` and `!= v:none` will often give + an error. Instead, use `is v:none` and `isnot v:none` . + + *v:null* *null-variable* +v:null An empty String. Used to put "null" in JSON. See + |json_encode()|. + When used as a number this evaluates to zero. + When used as a string this evaluates to "v:null". > + echo v:null +< v:null ~ + That is so that eval() can parse the string back to the same + value. Read-only. + In |Vim9| script `null` can be used without "v:". + In some places `v:null` and `null` can be used for a List, + Dict, Job, etc. that is not set. That is slightly different + than an empty List, Dict, etc. + + *v:numbermax* *numbermax-variable* +v:numbermax Maximum value of a number. + + *v:numbermin* *numbermin-variable* +v:numbermin Minimum value of a number (negative). + + *v:numbersize* *numbersize-variable* +v:numbersize Number of bits in a Number. This is normally 64, but on some + systems it may be 32. + + *v:oldfiles* *oldfiles-variable* +v:oldfiles List of file names that is loaded from the |viminfo| file on + startup. These are the files that Vim remembers marks for. + The length of the List is limited by the ' argument of the + 'viminfo' option (default is 100). + When the |viminfo| file is not used the List is empty. + Also see |:oldfiles| and |c_#<|. + The List can be modified, but this has no effect on what is + stored in the |viminfo| file later. If you use values other + than String this will cause trouble. + {only when compiled with the |+viminfo| feature} + + *v:option_new* +v:option_new New value of the option. Valid while executing an |OptionSet| + autocommand. + *v:option_old* +v:option_old Old value of the option. Valid while executing an |OptionSet| + autocommand. Depending on the command used for setting and the + kind of option this is either the local old value or the + global old value. + *v:option_oldlocal* +v:option_oldlocal + Old local value of the option. Valid while executing an + |OptionSet| autocommand. + *v:option_oldglobal* +v:option_oldglobal + Old global value of the option. Valid while executing an + |OptionSet| autocommand. + *v:option_type* +v:option_type Scope of the set command. Valid while executing an + |OptionSet| autocommand. Can be either "global" or "local" + *v:option_command* +v:option_command + Command used to set the option. Valid while executing an + |OptionSet| autocommand. + value option was set via ~ + "setlocal" |:setlocal| or ":let l:xxx" + "setglobal" |:setglobal| or ":let g:xxx" + "set" |:set| or |:let| + "modeline" |modeline| + *v:operator* *operator-variable* +v:operator The last operator given in Normal mode. This is a single + character except for commands starting with <g> or <z>, + in which case it is two characters. Best used alongside + |v:prevcount| and |v:register|. Useful if you want to cancel + Operator-pending mode and then use the operator, e.g.: > + :omap O <Esc>:call MyMotion(v:operator)<CR> +< The value remains set until another operator is entered, thus + don't expect it to be empty. + v:operator is not set for |:delete|, |:yank| or other Ex + commands. + Read-only. + + *v:prevcount* *prevcount-variable* +v:prevcount The count given for the last but one Normal mode command. + This is the v:count value of the previous command. Useful if + you want to cancel Visual or Operator-pending mode and then + use the count, e.g.: > + :vmap % <Esc>:call MyFilter(v:prevcount)<CR> +< Read-only. + + *v:profiling* *profiling-variable* +v:profiling Normally zero. Set to one after using ":profile start". + See |profiling|. + + *v:progname* *progname-variable* +v:progname Contains the name (with path removed) with which Vim was + invoked. Allows you to do special initialisations for |view|, + |evim| etc., or any other name you might symlink to Vim. + Read-only. + + *v:progpath* *progpath-variable* +v:progpath Contains the command with which Vim was invoked, in a form + that when passed to the shell will run the same Vim executable + as the current one (if $PATH remains unchanged). + Useful if you want to message a Vim server using a + |--remote-expr|. + To get the full path use: > + echo exepath(v:progpath) +< If the command has a relative path it will be expanded to the + full path, so that it still works after `:cd`. Thus starting + "./vim" results in "/home/user/path/to/vim/src/vim". + On Linux and other systems it will always be the full path. + On Mac it may just be "vim" and using exepath() as mentioned + above should be used to get the full path. + On MS-Windows the executable may be called "vim.exe", but the + ".exe" is not added to v:progpath. + Read-only. + + *v:python3_version* *python3-version-variable* +v:python3_version + Version of Python 3 that Vim was built against. When + Python is loaded dynamically (|python-dynamic|), this version + should exactly match the Python library up to the minor + version (e.g. 3.10.2 and 3.10.3 are compatible as the minor + version is "10", whereas 3.9.4 and 3.10.3 are not compatible). + When |python-stable-abi| is used, this will be the minimum Python + version that you can use instead. (e.g. if v:python3_version + indicates 3.9, you can use 3.9, 3.10, or anything above). + + This number is encoded as a hex number following Python ABI + versioning conventions. Do the following to have a + human-readable full version in hex: > + echo printf("%08X", v:python3_version) +< You can obtain only the minor version by doing: > + echo and(v:python3_version>>16,0xff) +< Read-only. + + *v:register* *register-variable* +v:register The name of the register in effect for the current normal mode + command (regardless of whether that command actually used a + register). Or for the currently executing normal mode mapping + (use this in custom commands that take a register). + If none is supplied it is the default register '"', unless + 'clipboard' contains "unnamed" or "unnamedplus", then it is + '*' or '+'. + Also see |getreg()| and |setreg()| + + *v:scrollstart* *scrollstart-variable* +v:scrollstart String describing the script or function that caused the + screen to scroll up. It's only set when it is empty, thus the + first reason is remembered. It is set to "Unknown" for a + typed command. + This can be used to find out why your script causes the + hit-enter prompt. + + *v:servername* *servername-variable* +v:servername The resulting registered |client-server-name| if any. + Read-only. + + +v:searchforward *v:searchforward* *searchforward-variable* + Search direction: 1 after a forward search, 0 after a + backward search. It is reset to forward when directly setting + the last search pattern, see |quote/|. + Note that the value is restored when returning from a + function. |function-search-undo|. + Read-write. + + *v:shell_error* *shell_error-variable* +v:shell_error Result of the last shell command. When non-zero, the last + shell command had an error. When zero, there was no problem. + This only works when the shell returns the error code to Vim. + The value -1 is often used when the command could not be + executed. Read-only. + Example: > + :!mv foo bar + :if v:shell_error + : echo 'could not rename "foo" to "bar"!' + :endif +< "shell_error" also works, for backwards compatibility, unless + |scriptversion| is 3 or higher. + + *v:sizeofint* *sizeofint-variable* +v:sizeofint Number of bytes in an int. Depends on how Vim was compiled. + This is only useful for deciding whether a test will give the + expected result. + + *v:sizeoflong* *sizeoflong-variable* +v:sizeoflong Number of bytes in a long. Depends on how Vim was compiled. + This is only useful for deciding whether a test will give the + expected result. + + *v:sizeofpointer* *sizeofpointer-variable* +v:sizeofpointer Number of bytes in a pointer. Depends on how Vim was compiled. + This is only useful for deciding whether a test will give the + expected result. + + *v:statusmsg* *statusmsg-variable* +v:statusmsg Last given status message. It's allowed to set this variable. + + *v:swapname* *swapname-variable* +v:swapname Only valid when executing |SwapExists| autocommands: Name of + the swap file found. Read-only. + + *v:swapchoice* *swapchoice-variable* +v:swapchoice |SwapExists| autocommands can set this to the selected choice + for handling an existing swap file: + 'o' Open read-only + 'e' Edit anyway + 'r' Recover + 'd' Delete swapfile + 'q' Quit + 'a' Abort + The value should be a single-character string. An empty value + results in the user being asked, as would happen when there is + no SwapExists autocommand. The default is empty. + + *v:swapcommand* *swapcommand-variable* +v:swapcommand Normal mode command to be executed after a file has been + opened. Can be used for a |SwapExists| autocommand to have + another Vim open the file and jump to the right place. For + example, when jumping to a tag the value is ":tag tagname\r". + For ":edit +cmd file" the value is ":cmd\r". + + *v:t_TYPE* *v:t_bool* *t_bool-variable* +v:t_bool Value of |Boolean| type. Read-only. See: |type()| + *v:t_channel* *t_channel-variable* +v:t_channel Value of |Channel| type. Read-only. See: |type()| + *v:t_dict* *t_dict-variable* +v:t_dict Value of |Dictionary| type. Read-only. See: |type()| + *v:t_float* *t_float-variable* +v:t_float Value of |Float| type. Read-only. See: |type()| + *v:t_func* *t_func-variable* +v:t_func Value of |Funcref| type. Read-only. See: |type()| + *v:t_job* *t_job-variable* +v:t_job Value of |Job| type. Read-only. See: |type()| + *v:t_list* *t_list-variable* +v:t_list Value of |List| type. Read-only. See: |type()| + *v:t_none* *t_none-variable* +v:t_none Value of |None| type. Read-only. See: |type()| + *v:t_number* *t_number-variable* +v:t_number Value of |Number| type. Read-only. See: |type()| + *v:t_string* *t_string-variable* +v:t_string Value of |String| type. Read-only. See: |type()| + *v:t_blob* *t_blob-variable* +v:t_blob Value of |Blob| type. Read-only. See: |type()| + *v:t_class* *t_class-variable* +v:t_class Value of |class| type. Read-only. See: |type()| + *v:t_object* *t_object-variable* +v:t_object Value of |object| type. Read-only. See: |type()| + *v:t_typealias* *t_typealias-variable* +v:t_typealias Value of |typealias| type. Read-only. See: |type()| + + *v:termresponse* *termresponse-variable* +v:termresponse The escape sequence returned by the terminal for the |t_RV| + termcap entry. It is set when Vim receives an escape sequence + that starts with ESC [ or CSI, then '>' or '?' and ends in a + 'c', with only digits and ';' in between. + When this option is set, the TermResponse autocommand event is + fired, so that you can react to the response from the + terminal. You can use |terminalprops()| to see what Vim + figured out about the terminal. + The response from a new xterm is: "<Esc>[> Pp ; Pv ; Pc c". Pp + is the terminal type: 0 for vt100 and 1 for vt220. Pv is the + patch level (since this was introduced in patch 95, it's + always 95 or higher). Pc is always zero. + If Pv is 141 or higher then Vim will try to request terminal + codes. This only works with xterm |xterm-codes|. + {only when compiled with |+termresponse| feature} + + *v:termblinkresp* +v:termblinkresp The escape sequence returned by the terminal for the |t_RC| + termcap entry. This is used to find out whether the terminal + cursor is blinking. This is used by |term_getcursor()|. + + *v:termstyleresp* +v:termstyleresp The escape sequence returned by the terminal for the |t_RS| + termcap entry. This is used to find out what the shape of the + cursor is. This is used by |term_getcursor()|. + + *v:termrbgresp* +v:termrbgresp The escape sequence returned by the terminal for the |t_RB| + termcap entry. This is used to find out what the terminal + background color is, see 'background'. + + *v:termrfgresp* +v:termrfgresp The escape sequence returned by the terminal for the |t_RF| + termcap entry. This is used to find out what the terminal + foreground color is. + + *v:termu7resp* +v:termu7resp The escape sequence returned by the terminal for the |t_u7| + termcap entry. This is used to find out what the terminal + does with ambiguous width characters, see 'ambiwidth'. + + *v:testing* *testing-variable* +v:testing Must be set before using `test_garbagecollect_now()`. + Also, when set certain error messages won't be shown for 2 + seconds. (e.g. "'dictionary' option is empty") + + *v:this_session* *this_session-variable* +v:this_session Full filename of the last loaded or saved session file. See + |:mksession|. It is allowed to set this variable. When no + session file has been saved, this variable is empty. + "this_session" also works, for backwards compatibility, unless + |scriptversion| is 3 or higher + + *v:throwpoint* *throwpoint-variable* +v:throwpoint The point where the exception most recently caught and not + finished was thrown. Not set when commands are typed. See + also |v:exception| and |throw-variables|. + Example: > + :try + : throw "oops" + :catch /.*/ + : echo "Exception from" v:throwpoint + :endtry +< Output: "Exception from test.vim, line 2" + + *v:true* *true-variable* +v:true A Number with value one. Used to put "true" in JSON. See + |json_encode()|. + When used as a string this evaluates to "v:true". > + echo v:true +< v:true ~ + That is so that eval() can parse the string back to the same + value. Read-only. + In |Vim9| script "true" can be used which has a boolean type. + *v:val* *val-variable* +v:val Value of the current item of a |List| or |Dictionary|. Only + valid while evaluating the expression used with |map()| and + |filter()|. Read-only. + + *v:version* *version-variable* +v:version Version number of Vim: Major version number times 100 plus + minor version number. Version 5.0 is 500. Version 5.1 + is 501. Read-only. "version" also works, for backwards + compatibility, unless |scriptversion| is 3 or higher. + Use |has()| to check if a certain patch was included, e.g.: > + if has("patch-7.4.123") +< Note that patch numbers are specific to the version, thus both + version 5.0 and 5.1 may have a patch 123, but these are + completely different. + + *v:versionlong* *versionlong-variable* +v:versionlong Like v:version, but also including the patchlevel in the last + four digits. Version 8.1 with patch 123 has value 8010123. + This can be used like this: > + if v:versionlong >= 8010123 +< However, if there are gaps in the list of patches included + this will not work well. This can happen if a recent patch + was included into an older version, e.g. for a security fix. + Use the has() function to make sure the patch is actually + included. + + *v:vim_did_enter* *vim_did_enter-variable* +v:vim_did_enter Zero until most of startup is done. It is set to one just + before |VimEnter| autocommands are triggered. + + *v:warningmsg* *warningmsg-variable* +v:warningmsg Last given warning message. It's allowed to set this variable. + + *v:windowid* *windowid-variable* +v:windowid When any X11 based GUI is running or when running in a + terminal and Vim connects to the X server (|-X|) this will be + set to the window ID. + When an MS-Windows GUI is running this will be set to the + window handle. + Otherwise the value is zero. + Note: for windows inside Vim use |winnr()| or |win_getid()|, + see |window-ID|. + +============================================================================== +4. Builtin Functions *functions* + +See |function-list| for a list grouped by what the function is used for. + +The alphabetic list of all builtin functions and details are in a separate +help file: |builtin-functions|. + +============================================================================== +5. Defining functions *user-functions* + +New functions can be defined. These can be called just like builtin +functions. The function takes arguments, executes a sequence of Ex commands +and can return a value. + +You can find most information about defining functions in |userfunc.txt|. +For Vim9 functions, which execute much faster, support type checking and more, +see |vim9.txt|. + +============================================================================== +6. Curly braces names *curly-braces-names* + +In most places where you can use a variable, you can use a "curly braces name" +variable. This is a regular variable name with one or more expressions +wrapped in braces {} like this: > + my_{adjective}_variable + +This only works in legacy Vim script, not in |Vim9| script. + +When Vim encounters this, it evaluates the expression inside the braces, puts +that in place of the expression, and re-interprets the whole as a variable +name. So in the above example, if the variable "adjective" was set to +"noisy", then the reference would be to "my_noisy_variable", whereas if +"adjective" was set to "quiet", then it would be to "my_quiet_variable". + +One application for this is to create a set of variables governed by an option +value. For example, the statement > + echo my_{&background}_message + +would output the contents of "my_dark_message" or "my_light_message" depending +on the current value of 'background'. + +You can use multiple brace pairs: > + echo my_{adverb}_{adjective}_message +..or even nest them: > + echo my_{ad{end_of_word}}_message +where "end_of_word" is either "verb" or "jective". + +However, the expression inside the braces must evaluate to a valid single +variable name, e.g. this is invalid: > + :let foo='a + b' + :echo c{foo}d +.. since the result of expansion is "ca + bd", which is not a variable name. + + *curly-braces-function-names* +You can call and define functions by an evaluated name in a similar way. +Example: > + :let func_end='whizz' + :call my_func_{func_end}(parameter) + +This would call the function "my_func_whizz(parameter)". + +This does NOT work: > + :let i = 3 + :let @{i} = '' " error + :echo @{i} " error + +============================================================================== +7. Commands *expression-commands* + +Note: in |Vim9| script `:let` is not used. `:var` is used for variable +declarations and assignments do not use a command. |vim9-declaration| + +:let {var-name} = {expr1} *:let* *E18* + Set internal variable {var-name} to the result of the + expression {expr1}. The variable will get the type + from the {expr}. If {var-name} didn't exist yet, it + is created. + +:let {var-name}[{idx}] = {expr1} *E689* *E1141* + Set a list item to the result of the expression + {expr1}. {var-name} must refer to a list and {idx} + must be a valid index in that list. For nested list + the index can be repeated. + This cannot be used to add an item to a |List|. + This cannot be used to set a byte in a String. You + can do that like this: > + :let var = var[0:2] .. 'X' .. var[4:] +< When {var-name} is a |Blob| then {idx} can be the + length of the blob, in which case one byte is + appended. + + *E711* *E719* *E1165* *E1166* *E1183* +:let {var-name}[{idx1}:{idx2}] = {expr1} *E708* *E709* *E710* + Set a sequence of items in a |List| to the result of + the expression {expr1}, which must be a list with the + correct number of items. + {idx1} can be omitted, zero is used instead. + {idx2} can be omitted, meaning the end of the list. + When the selected range of items is partly past the + end of the list, items will be added. + + *:let+=* *:let-=* *:letstar=* *:let/=* *:let%=* + *:let.=* *:let..=* *E734* *E985* *E1019* +:let {var} += {expr1} Like ":let {var} = {var} + {expr1}". +:let {var} -= {expr1} Like ":let {var} = {var} - {expr1}". +:let {var} *= {expr1} Like ":let {var} = {var} * {expr1}". +:let {var} /= {expr1} Like ":let {var} = {var} / {expr1}". +:let {var} %= {expr1} Like ":let {var} = {var} % {expr1}". +:let {var} .= {expr1} Like ":let {var} = {var} . {expr1}". +:let {var} ..= {expr1} Like ":let {var} = {var} .. {expr1}". + These fail if {var} was not set yet and when the type + of {var} and {expr1} don't fit the operator. + `.=` is not supported with Vim script version 2 and + later, see |vimscript-version|. + + +:let ${env-name} = {expr1} *:let-environment* *:let-$* + Set environment variable {env-name} to the result of + the expression {expr1}. The type is always String. + + On some systems making an environment variable empty + causes it to be deleted. Many systems do not make a + difference between an environment variable that is not + set and an environment variable that is empty. + +:let ${env-name} .= {expr1} + Append {expr1} to the environment variable {env-name}. + If the environment variable didn't exist yet this + works like "=". + +:let @{reg-name} = {expr1} *:let-register* *:let-@* + Write the result of the expression {expr1} in register + {reg-name}. {reg-name} must be a single letter, and + must be the name of a writable register (see + |registers|). "@@" can be used for the unnamed + register, "@/" for the search pattern. + If the result of {expr1} ends in a <CR> or <NL>, the + register will be linewise, otherwise it will be set to + characterwise. + This can be used to clear the last search pattern: > + :let @/ = "" +< This is different from searching for an empty string, + that would match everywhere. + +:let @{reg-name} .= {expr1} + Append {expr1} to register {reg-name}. If the + register was empty it's like setting it to {expr1}. + +:let &{option-name} = {expr1} *:let-option* *:let-&* + Set option {option-name} to the result of the + expression {expr1}. A String or Number value is + always converted to the type of the option. + For an option local to a window or buffer the effect + is just like using the |:set| command: both the local + value and the global value are changed. + Example: > + :let &path = &path .. ',/usr/local/include' +< This also works for terminal codes in the form t_xx. + But only for alphanumerical names. Example: > + :let &t_k1 = "\<Esc>[234;" +< When the code does not exist yet it will be created as + a terminal key code, there is no error. + +:let &{option-name} .= {expr1} + For a string option: Append {expr1} to the value. + Does not insert a comma like |:set+=|. + +:let &{option-name} += {expr1} +:let &{option-name} -= {expr1} + For a number or boolean option: Add or subtract + {expr1}. + +:let &l:{option-name} = {expr1} +:let &l:{option-name} .= {expr1} +:let &l:{option-name} += {expr1} +:let &l:{option-name} -= {expr1} + Like above, but only set the local value of an option + (if there is one). Works like |:setlocal|. + +:let &g:{option-name} = {expr1} +:let &g:{option-name} .= {expr1} +:let &g:{option-name} += {expr1} +:let &g:{option-name} -= {expr1} + Like above, but only set the global value of an option + (if there is one). Works like |:setglobal|. + *E1093* +:let [{name1}, {name2}, ...] = {expr1} *:let-unpack* *E687* *E688* + {expr1} must evaluate to a |List|. The first item in + the list is assigned to {name1}, the second item to + {name2}, etc. + The number of names must match the number of items in + the |List|. + Each name can be one of the items of the ":let" + command as mentioned above. + Example: > + :let [s, item] = GetItem(s) +< Detail: {expr1} is evaluated first, then the + assignments are done in sequence. This matters if + {name2} depends on {name1}. Example: > + :let x = [0, 1] + :let i = 0 + :let [i, x[i]] = [1, 2] + :echo x +< The result is [0, 2]. + +:let [{name1}, {name2}, ...] .= {expr1} +:let [{name1}, {name2}, ...] += {expr1} +:let [{name1}, {name2}, ...] -= {expr1} + Like above, but append/add/subtract the value for each + |List| item. + +:let [{name}, ..., ; {lastname}] = {expr1} *E452* + Like |:let-unpack| above, but the |List| may have more + items than there are names. A list of the remaining + items is assigned to {lastname}. If there are no + remaining items {lastname} is set to an empty list. + Example: > + :let [a, b; rest] = ["aval", "bval", 3, 4] +< +:let [{name}, ..., ; {lastname}] .= {expr1} +:let [{name}, ..., ; {lastname}] += {expr1} +:let [{name}, ..., ; {lastname}] -= {expr1} + Like above, but append/add/subtract the value for each + |List| item. + + *:let=<<* *:let-heredoc* + *E990* *E991* *E172* *E221* *E1145* +:let {var-name} =<< [trim] [eval] {endmarker} +text... +text... +{endmarker} + Set internal variable {var-name} to a |List| + containing the lines of text bounded by the string + {endmarker}. + + If "eval" is not specified, then each line of text is + used as a |literal-string|, except that single quotes + does not need to be doubled. + If "eval" is specified, then any Vim expression in the + form {expr} is evaluated and the result replaces the + expression, like with |interpolated-string|. + Example where $HOME is expanded: > + let lines =<< trim eval END + some text + See the file {$HOME}/.vimrc + more text + END +< There can be multiple Vim expressions in a single line + but an expression cannot span multiple lines. If any + expression evaluation fails, then the assignment fails. + + {endmarker} must not contain white space. + {endmarker} cannot start with a lower case character. + The last line should end only with the {endmarker} + string without any other character. Watch out for + white space after {endmarker}! + + Without "trim" any white space characters in the lines + of text are preserved. If "trim" is specified before + {endmarker}, then indentation is stripped so you can + do: > + let text =<< trim END + if ok + echo 'done' + endif + END +< Results in: ["if ok", " echo 'done'", "endif"] + The marker must line up with "let" and the indentation + of the first line is removed from all the text lines. + Specifically: all the leading indentation exactly + matching the leading indentation of the first + non-empty text line is stripped from the input lines. + All leading indentation exactly matching the leading + indentation before `let` is stripped from the line + containing {endmarker}. Note that the difference + between space and tab matters here. + + If {var-name} didn't exist yet, it is created. + Cannot be followed by another command, but can be + followed by a comment. + + To avoid line continuation to be applied, consider + adding 'C' to 'cpoptions': > + set cpo+=C + let var =<< END + \ leading backslash + END + set cpo-=C +< + Examples: > + 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} .. List the value of variable {var-name}. Multiple + variable names may be given. Special names recognized + here: *E738* + g: global variables + b: local buffer variables + w: local window variables + t: local tab page variables + s: script-local variables + l: local function variables + v: Vim variables. + This does not work in Vim9 script. |vim9-declaration| + +:let List the values of all variables. The type of the + variable is indicated before the value: + <nothing> String + # Number + * Funcref + This does not work in Vim9 script. |vim9-declaration| + +:unl[et][!] {name} ... *:unlet* *:unl* *E108* *E795* *E1081* + Remove the internal variable {name}. Several variable + names can be given, they are all removed. The name + may also be a |List| or |Dictionary| item. + With [!] no error message is given for non-existing + variables. + One or more items from a |List| can be removed: > + :unlet list[3] " remove fourth item + :unlet list[3:] " remove fourth item to last +< One item from a |Dictionary| can be removed at a time: > + :unlet dict['two'] + :unlet dict.two +< This is especially useful to clean up used global + variables and script-local variables (these are not + deleted when the script ends). Function-local + variables are automatically deleted when the function + ends. + In |Vim9| script variables declared in a function or + script cannot be removed. + +:unl[et] ${env-name} ... *:unlet-environment* *:unlet-$* + Remove environment variable {env-name}. + Can mix {name} and ${env-name} in one :unlet command. + No error message is given for a non-existing + variable, also without !. + If the system does not support deleting an environment + variable, it is made empty. + + *:cons* *:const* *E1018* +:cons[t] {var-name} = {expr1} +:cons[t] [{name1}, {name2}, ...] = {expr1} +:cons[t] [{name}, ..., ; {lastname}] = {expr1} +:cons[t] {var-name} =<< [trim] {marker} +text... +text... +{marker} + Similar to |:let|, but additionally lock the variable + after setting the value. This is the same as locking + the variable with |:lockvar| just after |:let|, thus: > + :const x = 1 +< is equivalent to: > + :let x = 1 + :lockvar! x +< NOTE: in Vim9 script `:const` works differently, see + |vim9-const| + This is useful if you want to make sure the variable + is not modified. If the value is a List or Dictionary + literal then the items also cannot be changed: > + const ll = [1, 2, 3] + let ll[1] = 5 " Error! +< Nested references are not locked: > + let lvar = ['a'] + const lconst = [0, lvar] + let lconst[0] = 2 " Error! + let lconst[1][0] = 'b' " OK +< *E995* + |:const| does not allow to for changing a variable: > + :let x = 1 + :const x = 2 " Error! +< *E996* + Note that environment variables, option values and + register values cannot be used here, since they cannot + be locked. + +:cons[t] +:cons[t] {var-name} + If no argument is given or only {var-name} is given, + the behavior is the same as |:let|. + +:lockv[ar][!] [depth] {name} ... *:lockvar* *:lockv* + Lock the internal variable {name}. Locking means that + it can no longer be changed (until it is unlocked). + A locked variable can be deleted: > + :lockvar v + :let v = 'asdf' " fails! + :unlet v " works +< *E741* *E940* *E1118* *E1119* *E1120* *E1121* *E1122* + If you try to change a locked variable you get an + error message: "E741: Value is locked: {name}". + If you try to lock or unlock a built-in variable you + get an error message: "E940: Cannot lock or unlock + variable {name}". + + [depth] is relevant when locking a |List| or + |Dictionary|. It specifies how deep the locking goes: + 0 Lock the variable {name} but not its + value. + 1 Lock the |List| or |Dictionary| itself, + cannot add or remove items, but can + still change their values. + 2 Also lock the values, cannot change + the items. If an item is a |List| or + |Dictionary|, cannot add or remove + items, but can still change the + values. + 3 Like 2 but for the |List| / + |Dictionary| in the |List| / + |Dictionary|, one level deeper. + The default [depth] is 2, thus when {name} is a |List| + or |Dictionary| the values cannot be changed. + + Example with [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* + For unlimited depth use [!] and omit [depth]. + However, there is a maximum depth of 100 to catch + loops. + + Note that when two variables refer to the same |List| + and you lock one of them, the |List| will also be + locked when used through the other variable. + Example: > + :let l = [0, 1, 2, 3] + :let cl = l + :lockvar l + :let cl[1] = 99 " won't work! +< You may want to make a copy of a list to avoid this. + See |deepcopy()|. + + *E1391* *E1392* + Locking and unlocking object and class variables is + currently NOT supported. + + +:unlo[ckvar][!] [depth] {name} ... *:unlockvar* *:unlo* *E1246* + Unlock the internal variable {name}. Does the + opposite of |:lockvar|. + + If {name} does not exist: + - In |Vim9| script an error is given. + - In legacy script this is silently ignored. + +:if {expr1} *:if* *:end* *:endif* *:en* *E171* *E579* *E580* +:en[dif] Execute the commands until the next matching `:else` + or `:endif` if {expr1} evaluates to non-zero. + Although the short forms work, it is recommended to + always use `:endif` to avoid confusion and to make + auto-indenting work properly. + + From Vim version 4.5 until 5.0, every Ex command in + between the `:if` and `:endif` is ignored. These two + commands were just to allow for future expansions in a + backward compatible way. Nesting was allowed. Note + that any `:else` or `:elseif` was ignored, the `else` + part was not executed either. + + You can use this to remain compatible with older + versions: > + :if version >= 500 + : version-5-specific-commands + :endif +< The commands still need to be parsed to find the + `endif`. Sometimes an older Vim has a problem with a + new command. For example, `:silent` is recognized as + a `:substitute` command. In that case `:execute` can + avoid problems: > + :if version >= 600 + : execute "silent 1,$delete" + :endif +< + In |Vim9| script `:endif` cannot be shortened, to + improve script readability. + NOTE: The `:append` and `:insert` commands don't work + properly in between `:if` and `:endif`. + + *:else* *:el* *E581* *E583* +:el[se] Execute the commands until the next matching `:else` + or `:endif` if they previously were not being + executed. + In |Vim9| script `:else` cannot be shortened, to + improve script readability. + + *:elseif* *:elsei* *E582* *E584* +:elsei[f] {expr1} Short for `:else` `:if`, with the addition that there + is no extra `:endif`. + In |Vim9| script `:elseif` cannot be shortened, to + improve script readability. + +:wh[ile] {expr1} *:while* *:endwhile* *:wh* *:endw* + *E170* *E585* *E588* *E733* +:endw[hile] Repeat the commands between `:while` and `:endwhile`, + as long as {expr1} evaluates to non-zero. + When an error is detected from a command inside the + loop, execution continues after the `endwhile`. + Example: > + :let lnum = 1 + :while lnum <= line("$") + :call FixLine(lnum) + :let lnum = lnum + 1 + :endwhile +< + In |Vim9| script `:while` and `:endwhile` cannot be + shortened, to improve script readability. + NOTE: The `:append` and `:insert` commands don't work + properly inside a `:while` and `:for` loop. + +:for {var} in {object} *:for* *E690* *E732* +:endfo[r] *:endfo* *:endfor* + Repeat the commands between `:for` and `:endfor` for + each item in {object}. {object} can be a |List|, + a |Blob| or a |String|. *E1177* + + Variable {var} is set to the value of each item. + In |Vim9| script the loop variable must not have been + declared yet, unless when it is a + global/window/tab/buffer variable. + + When an error is detected for a command inside the + loop, execution continues after the `endfor`. + Changing {object} inside the loop affects what items + are used. Make a copy if this is unwanted: > + :for item in copy(mylist) +< + When {object} is a |List| and not making a copy, in + legacy script Vim stores a reference to the next item + in the |List| before executing the commands with the + current item. Thus the current item can be removed + without effect. Removing any later item means it will + not be found. Thus the following example works (an + inefficient way to make a |List| empty): > + for item in mylist + call remove(mylist, 0) + endfor +< Note that reordering the |List| (e.g., with sort() or + reverse()) may have unexpected effects. + In |Vim9| script the index is used. If an item before + the current one is deleted the next item will be + skipped. + + When {object} is a |Blob|, Vim always makes a copy to + iterate over. Unlike with |List|, modifying the + |Blob| does not affect the iteration. + + When {object} is a |String| each item is a string with + one character, plus any combining characters. + + In |Vim9| script `:endfor` cannot be shortened, to + improve script readability. + +:for [{var1}, {var2}, ...] in {listlist} +:endfo[r] *E1140* + Like `:for` above, but each item in {listlist} must be + a list, of which each item is assigned to {var1}, + {var2}, etc. Example: > + :for [lnum, col] in [[1, 3], [2, 5], [3, 8]] + :echo getline(lnum)[col] + :endfor +< + *:continue* *:con* *E586* +:con[tinue] When used inside a `:while` or `:for` loop, jumps back + to the start of the loop. + If it is used after a `:try` inside the loop but + before the matching `:finally` (if present), the + commands following the `:finally` up to the matching + `:endtry` are executed first. This process applies to + all nested `:try`s inside the loop. The outermost + `:endtry` then jumps back to the start of the loop. + + In |Vim9| script `:cont` is the shortest form, to + improve script readability. + *:break* *:brea* *E587* +:brea[k] When used inside a `:while` or `:for` loop, skips to + the command after the matching `:endwhile` or + `:endfor`. + If it is used after a `:try` inside the loop but + before the matching `:finally` (if present), the + commands following the `:finally` up to the matching + `:endtry` are executed first. This process applies to + all nested `:try`s inside the loop. The outermost + `:endtry` then jumps to the command after the loop. + + In |Vim9| script `:break` cannot be shortened, to + improve script readability. + +:try *:try* *:endt* *:endtry* + *E600* *E601* *E602* *E1032* +:endt[ry] Change the error handling for the commands between + `:try` and `:endtry` including everything being + executed across `:source` commands, function calls, + or autocommand invocations. + + When an error or interrupt is detected and there is + a `:finally` command following, execution continues + after the `:finally`. Otherwise, or when the + `:endtry` is reached thereafter, the next + (dynamically) surrounding `:try` is checked for + a corresponding `:finally` etc. Then the script + processing is terminated. Whether a function + definition has an "abort" argument does not matter. + Example: > + try | call Unknown() | finally | echomsg "cleanup" | endtry + echomsg "not reached" +< + Moreover, an error or interrupt (dynamically) inside + `:try` and `:endtry` is converted to an exception. It + can be caught as if it were thrown by a `:throw` + command (see `:catch`). In this case, the script + processing is not terminated. + + The value "Vim:Interrupt" is used for an interrupt + exception. An error in a Vim command is converted + to a value of the form "Vim({command}):{errmsg}", + other errors are converted to a value of the form + "Vim:{errmsg}". {command} is the full command name, + and {errmsg} is the message that is displayed if the + error exception is not caught, always beginning with + the error number. + Examples: > + try | sleep 100 | catch /^Vim:Interrupt$/ | endtry + try | edit | catch /^Vim(edit):E\d\+/ | echo "error" | endtry +< + In |Vim9| script `:endtry` cannot be shortened, to + improve script readability. + + *:cat* *:catch* + *E603* *E604* *E605* *E654* *E1033* +:cat[ch] /{pattern}/ The following commands until the next `:catch`, + `:finally`, or `:endtry` that belongs to the same + `:try` as the `:catch` are executed when an exception + matching {pattern} is being thrown and has not yet + been caught by a previous `:catch`. Otherwise, these + commands are skipped. + When {pattern} is omitted all errors are caught. + Examples: > + :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 /.*/ +< + Another character can be used instead of / around the + {pattern}, so long as it does not have a special + meaning (e.g., '|' or '"') and doesn't occur inside + {pattern}. *E1067* + Information about the exception is available in + |v:exception|. Also see |throw-variables|. + NOTE: It is not reliable to ":catch" the TEXT of + an error message because it may vary in different + locales. + In |Vim9| script `:catch` cannot be shortened, to + improve script readability. + + *:fina* *:finally* *E606* *E607* +:fina[lly] The following commands until the matching `:endtry` + are executed whenever the part between the matching + `:try` and the `:finally` is left: either by falling + through to the `:finally` or by a `:continue`, + `:break`, `:finish`, or `:return`, or by an error or + interrupt or exception (see `:throw`). + + In |Vim9| script `:finally` cannot be shortened, to + improve script readability and avoid confusion with + `:final`. + + *:th* *:throw* *E608* *E1129* +:th[row] {expr1} The {expr1} is evaluated and thrown as an exception. + If the ":throw" is used after a `:try` but before the + first corresponding `:catch`, commands are skipped + until the first `:catch` matching {expr1} is reached. + If there is no such `:catch` or if the ":throw" is + used after a `:catch` but before the `:finally`, the + commands following the `:finally` (if present) up to + the matching `:endtry` are executed. If the `:throw` + is after the `:finally`, commands up to the `:endtry` + are skipped. At the ":endtry", this process applies + again for the next dynamically surrounding `:try` + (which may be found in a calling function or sourcing + script), until a matching `:catch` has been found. + If the exception is not caught, the command processing + is terminated. + Example: > + :try | throw "oops" | catch /^oo/ | echo "caught" | endtry +< Note that "catch" may need to be on a separate line + for when an error causes the parsing to skip the whole + line and not see the "|" that separates the commands. + + In |Vim9| script `:throw` cannot be shortened, to + improve script readability. + + *:ec* *:echo* +:ec[ho] {expr1} .. Echoes each {expr1}, with a space in between. The + first {expr1} starts on a new line. + Also see |:comment|. + Use "\n" to start a new line. Use "\r" to move the + cursor to the first column. + Uses the highlighting set by the `:echohl` command. + Cannot be followed by a comment. + Example: > + :echo "the value of 'shell' is" &shell +< *:echo-redraw* + A later redraw may make the message disappear again. + And since Vim mostly postpones redrawing until it's + finished with a sequence of commands this happens + quite often. To avoid that a command from before the + `:echo` causes a redraw afterwards (redraws are often + postponed until you type something), force a redraw + with the `:redraw` command. Example: > + :new | redraw | echo "there is a new window" +< + *:echon* +:echon {expr1} .. Echoes each {expr1}, without anything added. Also see + |:comment|. + Uses the highlighting set by the `:echohl` command. + Cannot be followed by a comment. + Example: > + :echon "the value of 'shell' is " &shell +< + Note the difference between using `:echo`, which is a + Vim command, and `:!echo`, which is an external shell + command: > + :!echo % --> filename +< The arguments of ":!" are expanded, see |:_%|. > + :!echo "%" --> filename or "filename" +< Like the previous example. Whether you see the double + quotes or not depends on your 'shell'. > + :echo % --> nothing +< The '%' is an illegal character in an expression. > + :echo "%" --> % +< This just echoes the '%' character. > + :echo expand("%") --> filename +< This calls the expand() function to expand the '%'. + + *:echoh* *:echohl* +:echoh[l] {name} Use the highlight group {name} for the following + `:echo`, `:echon` and `:echomsg` commands. Also used + for the `input()` prompt. Example: > + :echohl WarningMsg | echo "Don't panic!" | echohl None +< Don't forget to set the group back to "None", + otherwise all following echo's will be highlighted. + + *:echom* *:echomsg* +:echom[sg] {expr1} .. Echo the expression(s) as a true message, saving the + message in the |message-history|. + Spaces are placed between the arguments as with the + `:echo` command. But unprintable characters are + displayed, not interpreted. + The parsing works slightly different from `:echo`, + more like `:execute`. All the expressions are first + evaluated and concatenated before echoing anything. + If expressions does not evaluate to a Number or + String, string() is used to turn it into a string. + Uses the highlighting set by the `:echohl` command. + Example: > + :echomsg "It's a Zizzer Zazzer Zuzz, as you can plainly see." +< See |:echo-redraw| to avoid the message disappearing + when the screen is redrawn. + + *:echow* *:echowin* *:echowindow* +:[N]echow[indow] {expr1} .. + Like |:echomsg| but when the messages popup window is + available the message is displayed there. This means + it will show for three seconds and avoid a + |hit-enter| prompt. If you want to hide it before + that, press Esc in Normal mode (when it would + otherwise beep). If it disappears too soon you can + use `:messages` to see the text. + When [N] is given then the window will show up for + this number of seconds. The last `:echowindow` with a + count matters, it is used once only. + The message window is available when Vim was compiled + with the +timer and the +popupwin features. + + *:echoe* *:echoerr* +:echoe[rr] {expr1} .. Echo the expression(s) as an error message, saving the + message in the |message-history|. When used in a + script or function the line number will be added. + Spaces are placed between the arguments as with the + `:echomsg` command. When used inside a try conditional, + the message is raised as an error exception instead + (see |try-echoerr|). + Example: > + :echoerr "This script just failed!" +< If you just want a highlighted message use `:echohl`. + And to get a beep: > + :exe "normal \<Esc>" + +:echoc[onsole] {expr1} .. *:echoc* *:echoconsole* + Intended for testing: works like `:echomsg` but when + running in the GUI and started from a terminal write + the text to stdout. + + *:eval* +:eval {expr} Evaluate {expr} and discard the result. Example: > + :eval Getlist()->Filter()->append('$') + +< The expression is supposed to have a side effect, + since the resulting value is not used. In the example + the `append()` call appends the List with text to the + buffer. This is similar to `:call` but works with any + expression. + In |Vim9| script an expression without an effect will + result in error *E1207* . This should help noticing + mistakes. + + The command can be shortened to `:ev` or `:eva`, but + these are hard to recognize and therefore not to be + used. + + The command cannot be followed by "|" and another + command, since "|" is seen as part of the expression. + + + *:exe* *:execute* +:exe[cute] {expr1} .. Executes the string that results from the evaluation + of {expr1} as an Ex command. + Multiple arguments are concatenated, with a space in + between. To avoid the extra space use the ".." + operator to concatenate strings into one argument. + {expr1} is used as the processed command, command line + editing keys are not recognized. + Cannot be followed by a comment. + Examples: > + :execute "buffer" nextbuf + :execute "normal" count .. "w" +< + ":execute" can be used to append a command to commands + that don't accept a '|'. Example: > + :execute '!ls' | echo "theend" + +< ":execute" is also a nice way to avoid having to type + control characters in a Vim script for a ":normal" + command: > + :execute "normal ixxx\<Esc>" +< This has an <Esc> character, see |expr-string|. + + Be careful to correctly escape special characters in + file names. The |fnameescape()| function can be used + for Vim commands, |shellescape()| for |:!| commands. + Examples: > + :execute "e " .. fnameescape(filename) + :execute "!ls " .. shellescape(filename, 1) +< + Note: The executed string may be any command-line, but + starting or ending "if", "while" and "for" does not + always work, because when commands are skipped the + ":execute" is not evaluated and Vim loses track of + where blocks start and end. Also "break" and + "continue" should not be inside ":execute". + This example does not work, because the ":execute" is + not evaluated and Vim does not see the "while", and + gives an error for finding an ":endwhile": > + :if 0 + : execute 'while i > 5' + : echo "test" + : endwhile + :endif +< + It is allowed to have a "while" or "if" command + completely in the executed string: > + :execute 'while i < 5 | echo i | let i = i + 1 | endwhile' +< + + *:exe-comment* + ":execute", ":echo" and ":echon" cannot be followed by + a comment directly, because they see the '"' as the + start of a string. But, you can use '|' followed by a + comment. Example: > + :echo "foo" | "this is a comment + +============================================================================== +8. Exception handling *exception-handling* + +The Vim script language comprises an exception handling feature. This section +explains how it can be used in a Vim script. + +Exceptions may be raised by Vim on an error or on interrupt, see +|catch-errors| and |catch-interrupt|. You can also explicitly throw an +exception by using the ":throw" command, see |throw-catch|. + + +TRY CONDITIONALS *try-conditionals* + +Exceptions can be caught or can cause cleanup code to be executed. You can +use a try conditional to specify catch clauses (that catch exceptions) and/or +a finally clause (to be executed for cleanup). + A try conditional begins with a |:try| command and ends at the matching +|:endtry| command. In between, you can use a |:catch| command to start +a catch clause, or a |:finally| command to start a finally clause. There may +be none or multiple catch clauses, but there is at most one finally clause, +which must not be followed by any catch clauses. The lines before the catch +clauses and the finally clause is called a try block. > + + :try + : ... + : ... TRY BLOCK + : ... + :catch /{pattern}/ + : ... + : ... CATCH CLAUSE + : ... + :catch /{pattern}/ + : ... + : ... CATCH CLAUSE + : ... + :finally + : ... + : ... FINALLY CLAUSE + : ... + :endtry + +The try conditional allows to watch code for exceptions and to take the +appropriate actions. Exceptions from the try block may be caught. Exceptions +from the try block and also the catch clauses may cause cleanup actions. + When no exception is thrown during execution of the try block, the control +is transferred to the finally clause, if present. After its execution, the +script continues with the line following the ":endtry". + When an exception occurs during execution of the try block, the remaining +lines in the try block are skipped. The exception is matched against the +patterns specified as arguments to the ":catch" commands. The catch clause +after the first matching ":catch" is taken, other catch clauses are not +executed. The catch clause ends when the next ":catch", ":finally", or +":endtry" command is reached - whatever is first. Then, the finally clause +(if present) is executed. When the ":endtry" is reached, the script execution +continues in the following line as usual. + When an exception that does not match any of the patterns specified by the +":catch" commands is thrown in the try block, the exception is not caught by +that try conditional and none of the catch clauses is executed. Only the +finally clause, if present, is taken. The exception pends during execution of +the finally clause. It is resumed at the ":endtry", so that commands after +the ":endtry" are not executed and the exception might be caught elsewhere, +see |try-nesting|. + When during execution of a catch clause another exception is thrown, the +remaining lines in that catch clause are not executed. The new exception is +not matched against the patterns in any of the ":catch" commands of the same +try conditional and none of its catch clauses is taken. If there is, however, +a finally clause, it is executed, and the exception pends during its +execution. The commands following the ":endtry" are not executed. The new +exception might, however, be caught elsewhere, see |try-nesting|. + When during execution of the finally clause (if present) an exception is +thrown, the remaining lines in the finally clause are skipped. If the finally +clause has been taken because of an exception from the try block or one of the +catch clauses, the original (pending) exception is discarded. The commands +following the ":endtry" are not executed, and the exception from the finally +clause is propagated and can be caught elsewhere, see |try-nesting|. + +The finally clause is also executed, when a ":break" or ":continue" for +a ":while" loop enclosing the complete try conditional is executed from the +try block or a catch clause. Or when a ":return" or ":finish" is executed +from the try block or a catch clause of a try conditional in a function or +sourced script, respectively. The ":break", ":continue", ":return", or +":finish" pends during execution of the finally clause and is resumed when the +":endtry" is reached. It is, however, discarded when an exception is thrown +from the finally clause. + When a ":break" or ":continue" for a ":while" loop enclosing the complete +try conditional or when a ":return" or ":finish" is encountered in the finally +clause, the rest of the finally clause is skipped, and the ":break", +":continue", ":return" or ":finish" is executed as usual. If the finally +clause has been taken because of an exception or an earlier ":break", +":continue", ":return", or ":finish" from the try block or a catch clause, +this pending exception or command is discarded. + +For examples see |throw-catch| and |try-finally|. + + +NESTING OF TRY CONDITIONALS *try-nesting* + +Try conditionals can be nested arbitrarily. That is, a complete try +conditional can be put into the try block, a catch clause, or the finally +clause of another try conditional. If the inner try conditional does not +catch an exception thrown in its try block or throws a new exception from one +of its catch clauses or its finally clause, the outer try conditional is +checked according to the rules above. If the inner try conditional is in the +try block of the outer try conditional, its catch clauses are checked, but +otherwise only the finally clause is executed. It does not matter for +nesting, whether the inner try conditional is directly contained in the outer +one, or whether the outer one sources a script or calls a function containing +the inner try conditional. + +When none of the active try conditionals catches an exception, just their +finally clauses are executed. Thereafter, the script processing terminates. +An error message is displayed in case of an uncaught exception explicitly +thrown by a ":throw" command. For uncaught error and interrupt exceptions +implicitly raised by Vim, the error message(s) or interrupt message are shown +as usual. + +For examples see |throw-catch|. + + +EXAMINING EXCEPTION HANDLING CODE *except-examine* + +Exception handling code can get tricky. If you are in doubt what happens, set +'verbose' to 13 or use the ":13verbose" command modifier when sourcing your +script file. Then you see when an exception is thrown, discarded, caught, or +finished. When using a verbosity level of at least 14, things pending in +a finally clause are also shown. This information is also given in debug mode +(see |debug-scripts|). + + +THROWING AND CATCHING EXCEPTIONS *throw-catch* + +You can throw any number or string as an exception. Use the |:throw| command +and pass the value to be thrown as argument: > + :throw 4711 + :throw "string" +< *throw-expression* +You can also specify an expression argument. The expression is then evaluated +first, and the result is thrown: > + :throw 4705 + strlen("string") + :throw strpart("strings", 0, 6) + +An exception might be thrown during evaluation of the argument of the ":throw" +command. Unless it is caught there, the expression evaluation is abandoned. +The ":throw" command then does not throw a new exception. + Example: > + + :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() + +This throws "arrgh", and "in Bar" is not displayed since Bar() is not +executed. > + :throw Foo("foo") + Bar() +however displays "in Bar" and throws 4711. + +Any other command that takes an expression as argument might also be +abandoned by an (uncaught) exception during the expression evaluation. The +exception is then propagated to the caller of the command. + Example: > + + :if Foo("arrgh") + : echo "then" + :else + : echo "else" + :endif + +Here neither of "then" or "else" is displayed. + + *catch-order* +Exceptions can be caught by a try conditional with one or more |:catch| +commands, see |try-conditionals|. The values to be caught by each ":catch" +command can be specified as a pattern argument. The subsequent catch clause +gets executed when a matching exception is caught. + Example: > + + :function! Foo(value) + : try + : throw a:value + : catch /^\d\+$/ + : echo "Number thrown" + : catch /.*/ + : echo "String thrown" + : endtry + :endfunction + : + :call Foo(0x1267) + :call Foo('string') + +The first call to Foo() displays "Number thrown", the second "String thrown". +An exception is matched against the ":catch" commands in the order they are +specified. Only the first match counts. So you should place the more +specific ":catch" first. The following order does not make sense: > + + : catch /.*/ + : echo "String thrown" + : catch /^\d\+$/ + : echo "Number thrown" + +The first ":catch" here matches always, so that the second catch clause is +never taken. + + *throw-variables* +If you catch an exception by a general pattern, you may access the exact value +in the variable |v:exception|: > + + : catch /^\d\+$/ + : echo "Number thrown. Value is" v:exception + +You may also be interested where an exception was thrown. This is stored in +|v:throwpoint|. Note that "v:exception" and "v:throwpoint" are valid for the +exception most recently caught as long it is not finished. + Example: > + + :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() + +This displays > + + Nothing caught + Caught "4711" in function Foo, line 4 + Caught "oops" in function Foo, line 10 + Nothing caught + +A practical example: The following command ":LineNumber" displays the line +number in the script or function where it has been used: > + + :function! LineNumber() + : return substitute(v:throwpoint, '.*\D\(\d\+\).*', '\1', "") + :endfunction + :command! LineNumber try | throw "" | catch | echo LineNumber() | endtry +< + *try-nested* +An exception that is not caught by a try conditional can be caught by +a surrounding try conditional: > + + :try + : try + : throw "foo" + : catch /foobar/ + : echo "foobar" + : finally + : echo "inner finally" + : endtry + :catch /foo/ + : echo "foo" + :endtry + +The inner try conditional does not catch the exception, just its finally +clause is executed. The exception is then caught by the outer try +conditional. The example displays "inner finally" and then "foo". + + *throw-from-catch* +You can catch an exception and throw a new one to be caught elsewhere from the +catch clause: > + + :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 + +This displays "Caught foo, throw bar" and then "Caught bar". + + *rethrow* +There is no real rethrow in the Vim script language, but you may throw +"v:exception" instead: > + + :function! Bar() + : try + : call Foo() + : catch /.*/ + : echo "Rethrow" v:exception + : throw v:exception + : endtry + :endfunction +< *try-echoerr* +Note that this method cannot be used to "rethrow" Vim error or interrupt +exceptions, because it is not possible to fake Vim internal exceptions. +Trying so causes an error exception. You should throw your own exception +denoting the situation. If you want to cause a Vim error exception containing +the original error exception value, you can use the |:echoerr| command: > + + :try + : try + : asdf + : catch /.*/ + : echoerr v:exception + : endtry + :catch /.*/ + : echo v:exception + :endtry + +This code displays + + Vim(echoerr):Vim:E492: Not an editor command: asdf ~ + + +CLEANUP CODE *try-finally* + +Scripts often change global settings and restore them at their end. If the +user however interrupts the script by pressing CTRL-C, the settings remain in +an inconsistent state. The same may happen to you in the development phase of +a script when an error occurs or you explicitly throw an exception without +catching it. You can solve these problems by using a try conditional with +a finally clause for restoring the settings. Its execution is guaranteed on +normal control flow, on error, on an explicit ":throw", and on interrupt. +(Note that errors and interrupts from inside the try conditional are converted +to exceptions. When not caught, they terminate the script after the finally +clause has been executed.) +Example: > + + :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 + +This method should be used locally whenever a function or part of a script +changes global settings which need to be restored on failure or normal exit of +that function or script part. + + *break-finally* +Cleanup code works also when the try block or a catch clause is left by +a ":continue", ":break", ":return", or ":finish". + Example: > + + :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" + +This displays "first", "cleanup", "second", "cleanup", and "end". > + + :function! Foo() + : try + : return 4711 + : finally + : echo "cleanup\n" + : endtry + : echo "Foo still active" + :endfunction + : + :echo Foo() "returned by Foo" + +This displays "cleanup" and "4711 returned by Foo". You don't need to add an +extra ":return" in the finally clause. (Above all, this would override the +return value.) + + *except-from-finally* +Using either of ":continue", ":break", ":return", ":finish", or ":throw" in +a finally clause is possible, but not recommended since it abandons the +cleanup actions for the try conditional. But, of course, interrupt and error +exceptions might get raised from a finally clause. + Example where an error in the finally clause stops an interrupt from +working correctly: > + + :try + : try + : echo "Press CTRL-C for interrupt" + : while 1 + : endwhile + : finally + : unlet novar + : endtry + :catch /novar/ + :endtry + :echo "Script still running" + :sleep 1 + +If you need to put commands that could fail into a finally clause, you should +think about catching or ignoring the errors in these commands, see +|catch-errors| and |ignore-errors|. + + +CATCHING ERRORS *catch-errors* + +If you want to catch specific errors, you just have to put the code to be +watched in a try block and add a catch clause for the error message. The +presence of the try conditional causes all errors to be converted to an +exception. No message is displayed and |v:errmsg| is not set then. To find +the right pattern for the ":catch" command, you have to know how the format of +the error exception is. + Error exceptions have the following format: > + + Vim({cmdname}):{errmsg} +or > + Vim:{errmsg} + +{cmdname} is the name of the command that failed; the second form is used when +the command name is not known. {errmsg} is the error message usually produced +when the error occurs outside try conditionals. It always begins with +a capital "E", followed by a two or three-digit error number, a colon, and +a space. + +Examples: + +The command > + :unlet novar +normally produces the error message > + E108: No such variable: "novar" +which is converted inside try conditionals to an exception > + Vim(unlet):E108: No such variable: "novar" + +The command > + :dwim +normally produces the error message > + E492: Not an editor command: dwim +which is converted inside try conditionals to an exception > + Vim:E492: Not an editor command: dwim + +You can catch all ":unlet" errors by a > + :catch /^Vim(unlet):/ +or all errors for misspelled command names by a > + :catch /^Vim:E492:/ + +Some error messages may be produced by different commands: > + :function nofunc +and > + :delfunction nofunc +both produce the error message > + E128: Function name must start with a capital: nofunc +which is converted inside try conditionals to an exception > + Vim(function):E128: Function name must start with a capital: nofunc +or > + Vim(delfunction):E128: Function name must start with a capital: nofunc +respectively. You can catch the error by its number independently on the +command that caused it if you use the following pattern: > + :catch /^Vim(\a\+):E128:/ + +Some commands like > + :let x = novar +produce multiple error messages, here: > + E121: Undefined variable: novar + E15: Invalid expression: novar +Only the first is used for the exception value, since it is the most specific +one (see |except-several-errors|). So you can catch it by > + :catch /^Vim(\a\+):E121:/ + +You can catch all errors related to the name "nofunc" by > + :catch /\<nofunc\>/ + +You can catch all Vim errors in the ":write" and ":read" commands by > + :catch /^Vim(\(write\|read\)):E\d\+:/ + +You can catch all Vim errors by the pattern > + :catch /^Vim\((\a\+)\)\=:E\d\+:/ +< + *catch-text* +NOTE: You should never catch the error message text itself: > + :catch /No such variable/ +only works in the English locale, but not when the user has selected +a different language by the |:language| command. It is however helpful to +cite the message text in a comment: > + :catch /^Vim(\a\+):E108:/ " No such variable + + +IGNORING ERRORS *ignore-errors* + +You can ignore errors in a specific Vim command by catching them locally: > + + :try + : write + :catch + :endtry + +But you are strongly recommended NOT to use this simple form, since it could +catch more than you want. With the ":write" command, some autocommands could +be executed and cause errors not related to writing, for instance: > + + :au BufWritePre * unlet novar + +There could even be such errors you are not responsible for as a script +writer: a user of your script might have defined such autocommands. You would +then hide the error from the user. + It is much better to use > + + :try + : write + :catch /^Vim(write):/ + :endtry + +which only catches real write errors. So catch only what you'd like to ignore +intentionally. + +For a single command that does not cause execution of autocommands, you could +even suppress the conversion of errors to exceptions by the ":silent!" +command: > + :silent! nunmap k +This works also when a try conditional is active. + + +CATCHING INTERRUPTS *catch-interrupt* + +When there are active try conditionals, an interrupt (CTRL-C) is converted to +the exception "Vim:Interrupt". You can catch it like every exception. The +script is not terminated, then. + Example: > + + :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 + +You can interrupt a task here by pressing CTRL-C; the script then asks for +a new command. If you press CTRL-C at the prompt, the script is terminated. + +For testing what happens when CTRL-C would be pressed on a specific line in +your script, use the debug mode and execute the |>quit| or |>interrupt| +command on that line. See |debug-scripts|. + + +CATCHING ALL *catch-all* + +The commands > + + :catch /.*/ + :catch // + :catch + +catch everything, error exceptions, interrupt exceptions and exceptions +explicitly thrown by the |:throw| command. This is useful at the top level of +a script in order to catch unexpected things. + Example: > + + :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 + +Note: Catching all might catch more things than you want. Thus, you are +strongly encouraged to catch only for problems that you can really handle by +specifying a pattern argument to the ":catch". + Example: Catching all could make it nearly impossible to interrupt a script +by pressing CTRL-C: > + + :while 1 + : try + : sleep 1 + : catch + : endtry + :endwhile + + +EXCEPTIONS AND AUTOCOMMANDS *except-autocmd* + +Exceptions may be used during execution of autocommands. Example: > + + :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 + +This displays "Oops!" and "Arrgh!". + + *except-autocmd-Pre* +For some commands, autocommands get executed before the main action of the +command takes place. If an exception is thrown and not caught in the sequence +of autocommands, the sequence and the command that caused its execution are +abandoned and the exception is propagated to the caller of the command. + Example: > + + :autocmd BufWritePre * throw "FAIL" + :autocmd BufWritePre * echo "Should not be displayed" + : + :try + : write + :catch + : echo "Caught:" v:exception "from" v:throwpoint + :endtry + +Here, the ":write" command does not write the file currently being edited (as +you can see by checking 'modified'), since the exception from the BufWritePre +autocommand abandons the ":write". The exception is then caught and the +script displays: > + + Caught: FAIL from BufWrite Auto commands for "*" +< + *except-autocmd-Post* +For some commands, autocommands get executed after the main action of the +command has taken place. If this main action fails and the command is inside +an active try conditional, the autocommands are skipped and an error exception +is thrown that can be caught by the caller of the command. + Example: > + + :autocmd BufWritePost * echo "File successfully written!" + : + :try + : write /i/m/p/o/s/s/i/b/l/e + :catch + : echo v:exception + :endtry + +This just displays: > + + Vim(write):E212: Can't open file for writing (/i/m/p/o/s/s/i/b/l/e) + +If you really need to execute the autocommands even when the main action +fails, trigger the event from the catch clause. + Example: > + + :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 +< +You can also use ":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 + +This displays "after fail". + +If the main action of the command does not fail, exceptions from the +autocommands will be catchable by the caller of the command: > + + :autocmd BufWritePost * throw ":-(" + :autocmd BufWritePost * echo "Should not be displayed" + : + :try + : write + :catch + : echo v:exception + :endtry +< + *except-autocmd-Cmd* +For some commands, the normal action can be replaced by a sequence of +autocommands. Exceptions from that sequence will be catchable by the caller +of the command. + Example: For the ":write" command, the caller cannot know whether the file +had actually been written when the exception occurred. You need to tell it in +some way. > + + :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 + +When this script is sourced several times after making changes, it displays +first > + File successfully written! +then > + Error on writing (file contents not changed) +then > + Error after writing +etc. + + *except-autocmd-ill* +You cannot spread a try conditional over autocommands for different events. +The following code is ill-formed: > + + :autocmd BufWritePre * try + : + :autocmd BufWritePost * catch + :autocmd BufWritePost * echo v:exception + :autocmd BufWritePost * endtry + : + :write + + +EXCEPTION HIERARCHIES AND PARAMETERIZED EXCEPTIONS *except-hier-param* + +Some programming languages allow to use hierarchies of exception classes or to +pass additional information with the object of an exception class. You can do +similar things in Vim. + In order to throw an exception from a hierarchy, just throw the complete +class name with the components separated by a colon, for instance throw the +string "EXCEPT:MATHERR:OVERFLOW" for an overflow in a mathematical library. + When you want to pass additional information with your exception class, add +it in parentheses, for instance throw the string "EXCEPT:IO:WRITEERR(myfile)" +for an error when writing "myfile". + With the appropriate patterns in the ":catch" command, you can catch for +base classes or derived classes of your hierarchy. Additional information in +parentheses can be cut out from |v:exception| with the ":substitute" command. + Example: > + + :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 + +The exceptions raised by Vim itself (on error or when pressing CTRL-C) use +a flat hierarchy: they are all in the "Vim" class. You cannot throw yourself +exceptions with the "Vim" prefix; they are reserved for Vim. + Vim error exceptions are parameterized with the name of the command that +failed, if known. See |catch-errors|. + + +PECULIARITIES + *except-compat* +The exception handling concept requires that the command sequence causing the +exception is aborted immediately and control is transferred to finally clauses +and/or a catch clause. + +In the Vim script language there are cases where scripts and functions +continue after an error: in functions without the "abort" flag or in a command +after ":silent!", control flow goes to the following line, and outside +functions, control flow goes to the line following the outermost ":endwhile" +or ":endif". On the other hand, errors should be catchable as exceptions +(thus, requiring the immediate abortion). + +This problem has been solved by converting errors to exceptions and using +immediate abortion (if not suppressed by ":silent!") only when a try +conditional is active. This is no restriction since an (error) exception can +be caught only from an active try conditional. If you want an immediate +termination without catching the error, just use a try conditional without +catch clause. (You can cause cleanup code being executed before termination +by specifying a finally clause.) + +When no try conditional is active, the usual abortion and continuation +behavior is used instead of immediate abortion. This ensures compatibility of +scripts written for Vim 6.1 and earlier. + +However, when sourcing an existing script that does not use exception handling +commands (or when calling one of its functions) from inside an active try +conditional of a new script, you might change the control flow of the existing +script on error. You get the immediate abortion on error and can catch the +error in the new script. If however the sourced script suppresses error +messages by using the ":silent!" command (checking for errors by testing +|v:errmsg| if appropriate), its execution path is not changed. The error is +not converted to an exception. (See |:silent|.) So the only remaining cause +where this happens is for scripts that don't care about errors and produce +error messages. You probably won't want to use such code from your new +scripts. + + *except-syntax-err* +Syntax errors in the exception handling commands are never caught by any of +the ":catch" commands of the try conditional they belong to. Its finally +clauses, however, is executed. + Example: > + + :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 + +This displays: > + inner finally + outer catch-all caught "Vim(catch):E54: Unmatched \(" + outer finally +The original exception is discarded and an error exception is raised, instead. + + *except-single-line* +The ":try", ":catch", ":finally", and ":endtry" commands can be put on +a single line, but then syntax errors may make it difficult to recognize the +"catch" line, thus you better avoid this. + Example: > + :try | unlet! foo # | catch | endtry +raises an error exception for the trailing characters after the ":unlet!" +argument, but does not see the ":catch" and ":endtry" commands, so that the +error exception is discarded and the "E488: Trailing characters" message gets +displayed. + + *except-several-errors* +When several errors appear in a single command, the first error message is +usually the most specific one and therefore converted to the error exception. + Example: > + echo novar +causes > + E121: Undefined variable: novar + E15: Invalid expression: novar +The value of the error exception inside try conditionals is: > + Vim(echo):E121: Undefined variable: novar +< *except-syntax-error* +But when a syntax error is detected after a normal error in the same command, +the syntax error is used for the exception being thrown. + Example: > + unlet novar # +causes > + E108: No such variable: "novar" + E488: Trailing characters +The value of the error exception inside try conditionals is: > + Vim(unlet):E488: Trailing characters +This is done because the syntax error might change the execution path in a way +not intended by the user. Example: > + try + try | unlet novar # | catch | echo v:exception | endtry + catch /.*/ + echo "outer catch:" v:exception + endtry +This displays "outer catch: Vim(unlet):E488: Trailing characters", and then +a "E600: Missing :endtry" error message is given, see |except-single-line|. + +============================================================================== +9. Examples *eval-examples* + +Printing in Binary ~ +> + :" 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 + +Example of its use: > + :echo Nr2Bin(32) +result: "100000" > + :echo String2Bin("32") +result: "110011-110010" + + +Sorting lines ~ + +This example sorts lines with a specific compare function. > + + :func SortBuffer() + : let lines = getline(1, '$') + : call sort(lines, function("Strcmp")) + : call setline(1, lines) + :endfunction + +As a one-liner: > + :call setline(1, sort(getline(1, '$'), function("Strcmp"))) + + +scanf() replacement ~ + *sscanf* +There is no sscanf() function in Vim. If you need to extract parts from a +line, you can use matchstr() and substitute() to do it. This example shows +how to get the file name, line number and column number out of a line like +"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', '') + +The input is in the variable "line", the results in the variables "file", +"lnum" and "col". (idea from Michael Geddes) + + +getting the scriptnames in a Dictionary ~ + *scriptnames-dictionary* +The `:scriptnames` command can be used to get a list of all script files that +have been sourced. There is also the `getscriptinfo()` function, but the +information returned is not exactly the same. In case you need to manipulate +the list, this code can be used as a base: > + + # Create or update scripts dictionary, indexed by SNR, and return it. + def Scripts(scripts: dict<string> = {}): dict<string> + for info in getscriptinfo() + if scripts->has_key(info.sid) + continue + endif + scripts[info.sid] = info.name + endfor + return scripts + enddef + +============================================================================== +10. Vim script versions *vimscript-version* *vimscript-versions* + *scriptversion* +Over time many features have been added to Vim script. This includes Ex +commands, functions, variable types, etc. Each individual feature can be +checked with the |has()| and |exists()| functions. + +Sometimes old syntax of functionality gets in the way of making Vim better. +When support is taken away this will break older Vim scripts. To make this +explicit the |:scriptversion| command can be used. When a Vim script is not +compatible with older versions of Vim this will give an explicit error, +instead of failing in mysterious ways. + +When using a legacy function, defined with `:function`, in |Vim9| script then +scriptversion 4 is used. + + *scriptversion-1* > + :scriptversion 1 +< This is the original Vim script, same as not using a |:scriptversion| + command. Can be used to go back to old syntax for a range of lines. + Test for support with: > + has('vimscript-1') + +< *scriptversion-2* > + :scriptversion 2 +< String concatenation with "." is not supported, use ".." instead. + This avoids the ambiguity using "." for Dict member access and + floating point numbers. Now ".5" means the number 0.5. + + *scriptversion-3* > + :scriptversion 3 +< All |vim-variable|s must be prefixed by "v:". E.g. "version" doesn't + work as |v:version| anymore, it can be used as a normal variable. + Same for some obvious names as "count" and others. + + Test for support with: > + has('vimscript-3') +< + *scriptversion-4* > + :scriptversion 4 +< Numbers with a leading zero are not recognized as octal. "0o" or "0O" + is still recognized as octal. With the + previous version you get: > + echo 017 " displays 15 (octal) + echo 0o17 " displays 15 (octal) + echo 018 " displays 18 (decimal) +< with script version 4: > + echo 017 " displays 17 (decimal) + echo 0o17 " displays 15 (octal) + echo 018 " displays 18 (decimal) +< Also, it is possible to use single quotes inside numbers to make them + easier to read: > + echo 1'000'000 +< The quotes must be surrounded by digits. + + Test for support with: > + has('vimscript-4') + +============================================================================== +11. No +eval feature *no-eval-feature* + +When the |+eval| feature was disabled at compile time, none of the expression +evaluation commands are available. To prevent this from causing Vim scripts +to generate all kinds of errors, the ":if" and ":endif" commands are still +recognized, though the argument of the ":if" and everything between the ":if" +and the matching ":endif" is ignored. Nesting of ":if" blocks is allowed, but +only if the commands are at the start of the line. The ":else" command is not +recognized. + +Example of how to avoid executing commands when the |+eval| feature is +missing: > + + :if 1 + : echo "Expression evaluation is compiled in" + :else + : echo "You will _never_ see this message" + :endif + +To execute a command only when the |+eval| feature is disabled can be done in +two ways. The simplest is to exit the script (or Vim) prematurely: > + if 1 + echo "commands executed with +eval" + finish + endif + args " command executed without +eval + +If you do not want to abort loading the script you can use a trick, as this +example shows: > + + silent! while 0 + set history=111 + silent! endwhile + +When the |+eval| feature is available the command is skipped because of the +"while 0". Without the |+eval| feature the "while 0" is an error, which is +silently ignored, and the command is executed. + +============================================================================== +12. The sandbox *eval-sandbox* *sandbox* + +The 'foldexpr', 'formatexpr', 'includeexpr', 'indentexpr', 'statusline' and +'foldtext' options may be evaluated in a sandbox. This means that you are +protected from these expressions having nasty side effects. This gives some +safety for when these options are set from a modeline. It is also used when +the command from a tags file is executed and for CTRL-R = in the command line. +The sandbox is also used for the |:sandbox| command. + *E48* +These items are not allowed in the sandbox: + - changing the buffer text + - defining or changing mapping, autocommands, user commands + - setting certain options (see |option-summary|) + - setting certain v: variables (see |v:var|) *E794* + - executing a shell command + - reading or writing a file + - jumping to another buffer or editing a file + - executing Python, Perl, etc. commands +This is not guaranteed 100% secure, but it should block most attacks. + + *:san* *:sandbox* +:san[dbox] {cmd} Execute {cmd} in the sandbox. Useful to evaluate an + option that may have been set from a modeline, e.g. + 'foldexpr'. + + *sandbox-option* +A few options contain an expression. When this expression is evaluated it may +have to be done in the sandbox to avoid a security risk. But the sandbox is +restrictive, thus this only happens when the option was set from an insecure +location. Insecure in this context are: +- sourcing a .vimrc or .exrc in the current directory +- while executing in the sandbox +- value coming from a modeline +- executing a function that was defined in the sandbox + +Note that when in the sandbox and saving an option value and restoring it, the +option will still be marked as it was set in the sandbox. + +============================================================================== +13. Textlock *textlock* + +In a few situations it is not allowed to change the text in the buffer, jump +to another window and some other things that might confuse or break what Vim +is currently doing. This mostly applies to things that happen when Vim is +actually doing something else. For example, evaluating the 'balloonexpr' may +happen any moment the mouse cursor is resting at some position. + +This is not allowed when the textlock is active: + - changing the buffer text + - jumping to another buffer or window + - editing another file + - closing a window or quitting Vim + - etc. + +============================================================================== +14. Vim script library *vim-script-library* + +Vim comes bundled with a Vim script library, that can be used by runtime, +script authors. Currently, it only includes very few functions, but it may +grow over time. + +The functions are available as |Vim9-script| as well as using legacy Vim +script (to be used for non Vim 9.0 versions and Neovim). + + *dist#vim* *dist#vim9* +The functions make use of the autoloaded prefix "dist#vim" (for legacy Vim +script and Neovim) and "dist#vim9" for Vim9 script. + +The following functions are available: + +dist#vim#IsSafeExecutable(filetype, executable) ~ +dist#vim9#IsSafeExecutable(filetype:string, executable:string): bool ~ + +This function takes a filetype and an executable and checks whether it is safe +to execute the given executable. For security reasons users may not want to +have Vim execute random executables or may have forbidden to do so for +specific filetypes by setting the "<filetype>_exec" variable (|plugin_exec|). + +It returns |true| or |false| to indicate whether the plugin should run the given +executable. It takes the following arguments: + + argument type ~ + + filetype string + executable string + + + vim:tw=78:ts=8:noet:ft=help:norl: |