Mercurial > vim
diff runtime/doc/eval.txt @ 32670:695b50472e85
Fix line endings issue
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Mon, 26 Jun 2023 13:13:12 +0200 |
parents | 448aef880252 |
children | c517845bd10e |
line wrap: on
line diff
--- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -1,4782 +1,4782 @@ -*eval.txt* For Vim version 9.0. Last change: 2023 Jun 01 - - - 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| - -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 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: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: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()|. - - -: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. - - - vim:tw=78:ts=8:noet:ft=help:norl: +*eval.txt* For Vim version 9.0. Last change: 2023 Jun 01 + + + 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| + +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 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: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: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()|. + + +: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. + + + vim:tw=78:ts=8:noet:ft=help:norl: