codekingpro/portable-devtools
114k
1*vim9.txt* For Vim version 9.2. Last change: 2026 Feb 142 3 4 VIM REFERENCE MANUAL by Bram Moolenaar5 6 7Vim9 script commands and expressions. *Vim9* *vim9*8 9Most expression help is in |eval.txt|. This file is about the new syntax and10features in Vim9 script.11 12 13 141. What is Vim9 script? |Vim9-script|152. Differences |vim9-differences|163. New style functions |fast-functions|174. Types |vim9-types|185. Generic functions |generic-functions|196. Namespace, Import and Export |vim9script|207. Classes and interfaces |vim9-classes|218. Rationale |vim9-rationale|22 23 24------------------------------------------------------------------------------25 26 NOTE: In this vim9.txt help file, the Vim9 script code blocks beginning27 with `vim9script` (and individual lines starting with `vim9cmd`) are28 Vim9 script syntax highlighted. Also, they are sourceable, meaning29 you can run them to see what they output. To source them, use30 `:'<,'>source` (see |:source-range|), which is done by visually31 selecting the line(s) with |V| and typing `:so`. For example, try it32 on the following Vim9 script: >vim933 34 vim9script35 echowindow "Welcome to Vim9 script!"36<37 There are also code examples that should not be sourced - they38 explain concepts that don't require a sourceable example. Such code39 blocks appear in generic code syntax highlighting, like this: >40 41 def ThisFunction() # script-local42 def g:ThatFunction() # global43 export def Function() # for import and import autoload44 45==============================================================================46 471. What is Vim9 script? *Vim9-script*48 49Vim script has been growing over time, while preserving backwards50compatibility. That means bad choices from the past often can't be changed51and compatibility with Vi restricts possible solutions. Execution is quite52slow, each line is parsed every time it is executed.53 54The main goal of Vim9 script is to drastically improve performance. This is55accomplished by compiling commands into instructions that can be efficiently56executed. An increase in execution speed of 10 to 100 times can be expected.57 58A secondary goal is to avoid Vim-specific constructs and get closer to59commonly used programming languages, such as JavaScript, TypeScript and Java.60 61The performance improvements can only be achieved by not being 100% backwards62compatible. For example, making function arguments available in the "a:"63dictionary adds quite a lot of overhead. In a Vim9 function this dictionary64is not available. Other differences are more subtle, such as how errors are65handled.66 67Vim9 script syntax, semantics, and behavior apply in:68- a function defined with the `:def` command69- a script file where the first command is `vim9script`70- an autocommand defined in the context of the above71- a command prefixed with the `vim9cmd` command modifier72 73When using `:function` in a Vim9 script file the legacy syntax is used, with74the highest |scriptversion|. However, this can be confusing and is therefore75discouraged.76 77Vim9 script and legacy Vim script can be mixed. There is no requirement to78rewrite old scripts, they keep working as before. You may want to use a few79`:def` functions for code that needs to be fast.80 81:vim9[cmd] {cmd} *:vim9* *:vim9cmd*82 Evaluate and execute {cmd} using Vim9 script syntax,83 semantics, and behavior. Useful when typing a command,84 in a `:function`, or a legacy Vim script.85 86 The following short example shows how a legacy Vim script87 command and a :vim9cmd (so Vim9 script context) may appear88 similar, though may differ not just syntactically, but also89 semantically and behaviorally. >vim90 91 call popup_notification('entrée'[5:]92 \ ->str2list()->string(), #{time: 7000})93 vim9cmd popup_notification('entrée'[5 :]94 ->str2list()->string(), {time: 7000})95<96 Notes: 1) The reason for the different output is Vim9 script97 uses character indexing whereas legacy Vim script98 uses byte indexing - see |vim9-string-index|.99 2) Syntax is different too. In Vim9 script:100 - The space in "[5 :]" is mandatory (see101 |vim9-white-space|).102 - Line continuation with "\" is not required.103 - The "#" (to avoid putting quotes around dictionary104 keys) is neither required nor allowed - see |#{}|.105 106 *E1164*107 `:vim9cmd` cannot stand alone; it must be followed by a command.108 109:leg[acy] {cmd} *:leg* *:legacy*110 Evaluate and execute {cmd} using legacy Vim script syntax,111 semantics, and behavior. It is only applicable in a Vim9112 script or a `:def` function. Using an equivalent script to113 the one, above (see its notes for why the output differs): >vim9114 115 vim9script116 # Legacy context - so, this creates a popup with [769, 101]117 legacy call popup_notification('entrée'[5:]118 \ ->str2list()->string(), #{time: 7000})119 # Vim9 script context - so, this creates a pop up with [101]120 popup_notification('entrée'[5 :]121 ->str2list()->string(), {time: 7000})122<123 Vim9 script script-local variables may be used by prefixing124 "s:", like in legacy Vim script. This example shows the125 difference in syntax: "k" for the script-local variable in126 Vim9 script, "s:k" in the legacy Vim script context. >vim9127 128 vim9script129 var k: string = "Okay"130 echo k131 legacy echo s:k132< *E1189*133 Using `:legacy` is not allowed in compiled Vim9 script134 control flow contexts. For example: >vim9135 136 vim9script137 def F_1189()138 if v:version == 900139 # E1189: Cannot use :legacy with this command: endif140 legacy endif141 enddef142 F_1189()143< *E1234*144 `:legacy` cannot stand alone; it must be followed by a command.145 146 147==============================================================================148 1492. Differences from legacy Vim script *vim9-differences*150 151Overview ~152 *E1146*153Brief summary of the differences you will most often encounter when using Vim9154script and `:def` functions; details are below:155- Comments start with #, not ": >156 echo "hello" # comment157- Using a backslash for line continuation is hardly ever needed: >158 echo "hello "159 .. yourName160 .. ", how are you?"161- White space is required in many places to improve readability,162 see |vim9-white-space|.163- Assign values without `:let` *E1126* , declare variables with `:var`: >164 var count = 0165 count += 3166- Constants can be declared with `:final` and `:const`: >167 final matches = [] # add to the list later168 const names = ['Betty', 'Peter'] # cannot be changed169- `:final` cannot be used as an abbreviation of `:finally`.170- Variables and functions are script-local by default.171- Functions are declared with argument types and return type: >172 def CallMe(count: number, message: string): bool173- Call functions without `:call`: >174 writefile(['done'], 'file.txt')175- You cannot use old Ex commands:176 `:Print`177 `:append`178 `:change`179 `:d` directly followed by 'd' or 'p'.180 `:insert`181 `:k`182 `:mode`183 `:open`184 `:s` with only flags185 `:t`186 `:xit`187- Some commands, especially those used for flow control, cannot be shortened.188 E.g., `:throw` cannot be written as `:th`. *vim9-no-shorten*189- You cannot use curly-braces names.190- A range before a command must be prefixed with a colon: >191 :%s/this/that192- Executing a register with "@r" does not work, you can prepend a colon or use193 `:exe`: >194 :exe @a195- Unless mentioned specifically, the highest |scriptversion| is used.196- When defining an expression mapping, the expression will be evaluated in the197 context of the script where it was defined.198- When indexing a string the index is counted in characters, not bytes:199 |vim9-string-index|200- Some possibly unexpected differences: |vim9-gotchas|.201 202 203Comments starting with # ~204 205In legacy Vim script comments start with double quote. In Vim9 script206comments start with #. >207 # declarations208 var count = 0 # number of occurrences209 210The reason is that a double quote can also be the start of a string. In many211places, especially halfway through an expression with a line break, it's hard212to tell what the meaning is, since both a string and a comment can be followed213by arbitrary text. To avoid confusion only # comments are recognized. This214is the same as in shell scripts and Python programs.215 216In Vi # is a command to list text with numbers. In Vim9 script you can use217`:number` for that. >218 :101 number219 220To improve readability there must be a space between a command and the #221that starts a comment: >222 var name = value # comment223 var name = value# error!224< *E1170*225Do not start a comment with #{, it looks like the legacy dictionary literal226and produces an error where this might be confusing. #{{ or #{{{ are OK,227these can be used to start a fold.228 229When starting to read a script file Vim doesn't know it is |Vim9| script until230the `vim9script` command is found. Until that point you would need to use231legacy comments: >232 " legacy comment233 vim9script234 # Vim9 comment235 236That looks ugly, better put `vim9script` in the very first line: >237 vim9script238 # Vim9 comment239 240In legacy Vim script # is also used for the alternate file name. In Vim9241script you need to use %% instead. Instead of ## use %%% (stands for all242arguments).243 244 245Vim9 functions ~246 *E1099*247A function defined with `:def` is compiled. Execution is many times faster,248often 10 to 100 times.249 250Many errors are already found when compiling, before the function is executed.251The syntax is strict, to enforce code that is easy to read and understand.252 253Compilation is done when any of these is encountered:254- the first time the function is called255- when the `:defcompile` command is encountered in the script after the256 function was defined257- `:disassemble` is used for the function.258- a function that is compiled calls the function or uses it as a function259 reference (so that the argument and return types can be checked)260 *E1091* *E1191*261If compilation fails it is not tried again on the next call, instead this262error is given: "E1091: Function is not compiled: {name}".263Compilation will fail when encountering a user command that has not been264created yet. In this case you can call `execute()` to invoke it at runtime. >265 def MyFunc()266 execute('DefinedLater')267 enddef268 269`:def` has no options like `:function` does: "range", "abort", "dict" or270"closure". A `:def` function always aborts on an error (unless `:silent!` was271used for the command or the error was caught a `:try` block), does not get a272range passed, cannot be a "dict" function, and can always be a closure.273 *vim9-no-dict-function* *E1182*274You can use a Vim9 Class (|Vim9-class|) instead of a "dict function".275You can also pass the dictionary explicitly: >276 def DictFunc(self: dict<any>, arg: string)277 echo self[arg]278 enddef279 var ad = {item: 'value', func: DictFunc}280 ad.func(ad, 'item')281 282You can call a legacy dict function though: >283 func Legacy() dict284 echo self.value285 endfunc286 def CallLegacy()287 var d = {func: Legacy, value: 'text'}288 d.func()289 enddef290 291The argument types and return type need to be specified. The "any" type can292be used, type checking will then be done at runtime, like with legacy293functions.294 *E1106*295Arguments are accessed by name, without "a:", just like any other language.296There is no "a:" dictionary or "a:000" list.297 *vim9-variable-arguments* *E1055* *E1160* *E1180*298Variable arguments are defined as the last argument, with a name and have a299list type, similar to TypeScript. For example, a list of numbers: >300 def MyFunc(...itemlist: list<number>)301 for item in itemlist302 ...303 304When a function argument is optional (it has a default value) passing `v:none`305as the argument results in using the default value. This is useful when you306want to specify a value for an argument that comes after an argument that307should use its default value. Example: >308 def MyFunc(one = 'one', last = 'last')309 ...310 enddef311 MyFunc(v:none, 'LAST') # first argument uses default value 'one'312<313 *vim9-ignored-argument* *E1181*314The argument "_" (an underscore) can be used to ignore the argument. This is315most useful in callbacks where you don't need it, but do need to give an316argument to match the call. E.g. when using map() two arguments are passed,317the key and the value, to ignore the key: >318 map(numberList, (_, v) => v * 2)319There is no error for using the "_" argument multiple times. No type needs to320be given.321 322 323Functions and variables are script-local by default ~324 *vim9-scopes*325When using `:function` or `:def` to specify a new function at the script level326in a Vim9 script, the function is local to the script. Like prefixing "s:" in327legacy script. To define a global function or variable the "g:" prefix must328be used. For functions in a script that is to be imported and in an autoload329script "export" needs to be used for those to be used elsewhere. >330 def ThisFunction() # script-local331 def g:ThatFunction() # global332 export def Function() # for import and import autoload333< *E1075*334When using `:function` or `:def` to specify a nested function inside a `:def`335function and no namespace was given, this nested function is local to the code336block it is defined in. It cannot be used in `function()` with a string337argument, pass the function reference itself: >338 def Outer()339 def Inner()340 echo 'inner'341 enddef342 var Fok = function(Inner) # OK343 var Fbad = function('Inner') # does not work344 345Detail: this is because "Inner" will actually become a function reference to a346function with a generated name.347 348It is not possible to define a script-local function in a function. You can349define a local function and assign it to a script-local Funcref (it must have350been declared at the script level). It is possible to define a global351function by using the "g:" prefix.352 353When referring to a function and no "s:" or "g:" prefix is used, Vim will354search for the function:355- in the function scope, in block scopes356- in the script scope357 358Imported functions are found with the prefix from the `:import` command.359 360Since a script-local function reference can be used without "s:" the name must361start with an upper case letter even when using the "s:" prefix. In legacy362script "s:funcref" could be used, because it could not be referred to with363"funcref". In Vim9 script it can, therefore "s:Funcref" must be used to avoid364that the name interferes with builtin functions.365 *vim9-s-namespace* *E1268*366The use of the "s:" prefix is not supported at the Vim9 script level. All367functions and variables without a prefix are script-local.368 369In :def functions the use of "s:" depends on the script: Script-local370variables and functions in a legacy script do use "s:", while in a Vim9 script371they do not use "s:". This matches what you see in the rest of the file.372 373In legacy functions the use of "s:" for script items is required, as before.374No matter if the script is Vim9 or legacy.375 376In all cases the function must be defined before used. That is when it is377called, when `:defcompile` causes it to be compiled, or when code that calls378it is being compiled (to figure out the return type).379 380The result is that functions and variables without a namespace can usually be381found in the script, either defined there or imported. Global functions and382variables could be defined anywhere (good luck finding out where! You can383often see where it was last set using |:verbose|).384 *E1102*385Global functions can still be defined and deleted at nearly any time. In386Vim9 script script-local functions are defined once when the script is sourced387and cannot be deleted or replaced by itself (it can be by reloading the388script).389 390When compiling a function and a function call is encountered for a function391that is not (yet) defined, the |FuncUndefined| autocommand is not triggered.392You can use an autoload function if needed, or call a legacy function and have393|FuncUndefined| triggered there.394 395 396Reloading a Vim9 script clears functions and variables by default ~397 *vim9-reload* *E1149* *E1150*398When loading a legacy Vim script a second time nothing is removed, the399commands will replace existing variables and functions, create new ones, and400leave removed things hanging around.401 402When loading a Vim9 script a second time all existing script-local functions403and variables are deleted, thus you start with a clean slate. This is useful404if you are developing a plugin and want to try a new version. If you renamed405something you don't have to worry about the old name still hanging around.406 407If you do want to keep items, use: >408 vim9script noclear409 410You want to use this in scripts that use a `finish` command to bail out at411some point when loaded again. E.g. when a buffer local option is set to a412function, the function does not need to be defined more than once: >413 vim9script noclear414 setlocal completefunc=SomeFunc415 if exists('*SomeFunc')416 finish417 endif418 def SomeFunc()419 ....420 421 422Variable declarations with :var, :final and :const ~423 *vim9-declaration* *:var* *E1079*424 *E1017* *E1020* *E1054* *E1087* *E1124*425Local variables need to be declared with `:var`. Local constants need to be426declared with `:final` or `:const`. We refer to both as "variables" in this427section.428 429Variables can be local to a script, function or code block: >430 vim9script431 var script_var = 123432 def SomeFunc()433 var func_var = script_var434 if cond435 var block_var = func_var436 ...437 438The variables are only visible in the block where they are defined and nested439blocks. Once the block ends the variable is no longer accessible: >440 if cond441 var inner = 5442 else443 var inner = 0444 endif445 echo inner # Error!446 447The declaration must be done earlier: >448 var inner: number449 if cond450 inner = 5451 else452 inner = 0453 endif454 echo inner455 456Although this is shorter and faster for simple values: >457 var inner = 0458 if cond459 inner = 5460 endif461 echo inner462< *E1025* *E1128*463To intentionally hide a variable from code that follows, a block can be464used: >465 {466 var temp = 'temp'467 ...468 }469 echo temp # Error!470 471This is especially useful in a user command: >472 command -range Rename {473 var save = @a474 @a = 'some expression'475 echo 'do something with ' .. @a476 @a = save477 }478 479And with autocommands: >480 au BufWritePre *.go {481 var save = winsaveview()482 silent! exe ':%! some formatting command'483 winrestview(save)484 }485 486Although using a :def function probably works better.487 488 *E1022* *E1103* *E1130* *E1131* *E1133*489 *E1134*490Declaring a variable with a type but without an initializer will initialize to491false (for bool), empty (for string, list, dict, etc.) or zero (for number,492any, etc.). This matters especially when using the "any" type, the value will493default to the number zero. For example, when declaring a list, items can be494added: >495 var myList: list<number>496 myList->add(7)497 498Initializing a variable to a null value, e.g. `null_list`, differs from not499initializing the variable. This throws an error: >500 var myList = null_list501 myList->add(7) # E1130: Cannot add to null list502 503< *E1016* *E1052* *E1066*504In Vim9 script `:let` cannot be used. An existing variable is assigned to505without any command. The same for global, window, tab, buffer and Vim506variables, because they are not really declared. Those can also be deleted507with `:unlet`.508 *E1065*509You cannot use `:va` to declare a variable, it must be written with the full510name `:var`. Just to make sure it is easy to read.511 *E1178*512`:lockvar` does not work on local variables. Use `:const` and `:final`513instead.514 515The `exists()` and `exists_compiled()` functions do not work on local variables516or arguments.517 *E1006* *E1041* *E1167* *E1168* *E1213*518Variables, functions and function arguments cannot shadow previously defined519or imported variables and functions in the same script file.520Variables may shadow Ex commands, rename the variable if needed.521 522Global variables must be prefixed with "g:", also at the script level. >523 vim9script524 var script_local = 'text'525 g:global = 'value'526 var Funcref = g:ThatFunction527 528Global functions must be prefixed with "g:": >529 vim9script530 def g:GlobalFunc(): string531 return 'text'532 enddef533 echo g:GlobalFunc()534The "g:" prefix is not needed for auto-load functions.535 536 *vim9-function-defined-later*537Although global functions can be called without the "g:" prefix, they must538exist when compiled. By adding the "g:" prefix the function can be defined539later. Example: >540 def CallPluginFunc()541 if exists('g:loaded_plugin')542 g:PluginFunc()543 endif544 enddef545 546If you do it like this, you get an error at compile time that "PluginFunc"547does not exist, even when "g:loaded_plugin" does not exist: >548 def CallPluginFunc()549 if exists('g:loaded_plugin')550 PluginFunc() # Error - function not found551 endif552 enddef553 554You can use exists_compiled() to avoid the error, but then the function would555not be called, even when "g:loaded_plugin" is defined later: >556 def CallPluginFunc()557 if exists_compiled('g:loaded_plugin')558 PluginFunc() # Function may never be called559 endif560 enddef561 562Since `&opt = value` is now assigning a value to option "opt", ":&" cannot be563used to repeat a `:substitute` command.564 *vim9-unpack-ignore*565For an unpack assignment the underscore can be used to ignore a list item,566similar to how a function argument can be ignored: >567 [a, _, c] = theList568To ignore any remaining items: >569 [a, b; _] = longList570< *E1163* *E1080*571Declaring more than one variable at a time, using the unpack notation, is572possible. Each variable can have a type or infer it from the value: >573 var [v1: number, v2] = GetValues()574Use this only when there is a list with values, declaring one variable per575line is much easier to read and change later.576 577 578Constants ~579 *vim9-const* *vim9-final*580How constants work varies between languages. Some consider a variable that581can't be assigned another value a constant. JavaScript is an example. Others582also make the value immutable, thus when a constant uses a list, the list583cannot be changed. In Vim9 we can use both.584 *E1021* *E1307*585`:const` is used for making both the variable and the value a constant. Use586this for composite structures that you want to make sure will not be modified.587Example: >588 const myList = [1, 2]589 myList = [3, 4] # Error!590 myList[0] = 9 # Error!591 myList->add(3) # Error!592< *:final* *E1125*593`:final` is used for making only the variable a constant, the value can be594changed. This is well known from Java. Example: >595 final myList = [1, 2]596 myList = [3, 4] # Error!597 myList[0] = 9 # OK598 myList->add(3) # OK599 600It is common to write constants as ALL_CAPS, but you don't have to.601 602The constant only applies to the value itself, not what it refers to. >603 final females = ["Mary"]604 const NAMES = [["John", "Peter"], females]605 NAMES[0] = ["Jack"] # Error!606 NAMES[0][0] = "Jack" # Error!607 NAMES[1] = ["Emma"] # Error!608 NAMES[1][0] = "Emma" # OK, now females[0] == "Emma"609 610 611Omitting :call and :eval ~612 *E1190*613Functions can be called without `:call`: >614 writefile(lines, 'file')615Using `:call` is still possible, but this is discouraged.616 617A method call without `eval` is possible, so long as the start is an618identifier or can't be an Ex command. For a function either "(" or "->" must619be following, without a line break. Examples: >620 myList->add(123)621 g:myList->add(123)622 [1, 2, 3]->Process()623 {a: 1, b: 2}->Process()624 "foobar"->Process()625 ("foobar")->Process()626 'foobar'->Process()627 ('foobar')->Process()628 629In the rare case there is ambiguity between a function name and an Ex command,630prepend ":" to make clear you want to use the Ex command. For example, there631is both the `:substitute` command and the `substitute()` function. When the632line starts with `substitute(` this will use the function. Prepend a colon to633use the command instead: >634 :substitute(pattern (replacement (635 636If the expression starts with "!" this is interpreted as a shell command, not637negation of a condition. Thus this is a shell command: >638 !shellCommand->something639Put the expression in parentheses to use the "!" for negation: >640 (!expression)->Method()641 642Note that while variables need to be defined before they can be used,643functions can be called before being defined. This is required to allow644for cyclic dependencies between functions. It is slightly less efficient,645since the function has to be looked up by name. And a typo in the function646name will only be found when the function is called.647 648 649Omitting function() ~650 651A user defined function can be used as a function reference in an expression652without `function()`. The argument types and return type will then be checked.653The function must already have been defined. >654 655 var Funcref = MyFunction656 657When using `function()` the resulting type is "func", a function with any658number of arguments and any return type (including void). The function can be659defined later if the argument is in quotes.660 661 662Lambda using => instead of -> ~663 *vim9-lambda*664In legacy script there can be confusion between using "->" for a method call665and for a lambda. Also, when a "{" is found the parser needs to figure out if666it is the start of a lambda or a dictionary, which is now more complicated667because of the use of argument types.668 669To avoid these problems Vim9 script uses a different syntax for a lambda,670which is similar to JavaScript: >671 var Lambda = (arg) => expression672 var Lambda = (arg): type => expression673< *E1157*674No line break is allowed in the arguments of a lambda up to and including the675"=>" (so that Vim can tell the difference between an expression in parentheses676and lambda arguments). This is OK: >677 filter(list, (k, v) =>678 v > 0)679This does not work: >680 filter(list, (k, v)681 => v > 0)682This also does not work: >683 filter(list, (k,684 v) => v > 0)685But you can use a backslash to concatenate the lines before parsing: >686 filter(list, (k,687 \ v)688 \ => v > 0)689< *vim9-lambda-arguments* *E1172*690In legacy script a lambda could be called with any number of extra arguments,691there was no way to warn for not using them. In Vim9 script the number of692arguments must match. If you do want to accept any arguments, or any further693arguments, use "..._", which makes the function accept694|vim9-variable-arguments|. Example: >695 var Callback = (..._) => 'anything'696 echo Callback(1, 2, 3) # displays "anything"697 698< *inline-function* *E1171*699Additionally, a lambda can contain statements in {}: >700 var Lambda = (arg) => {701 g:was_called = 'yes'702 return expression703 }704This can be useful for a timer, for example: >705 var count = 0706 var timer = timer_start(500, (_) => {707 count += 1708 echom 'Handler called ' .. count709 }, {repeat: 3})710 711The ending "}" must be at the start of a line. It can be followed by other712characters, e.g.: >713 var d = mapnew(dict, (k, v): string => {714 return 'value'715 })716No command can follow the "{", only a comment can be used there.717 718 *command-block* *E1026*719The block can also be used for defining a user command. Inside the block Vim9720syntax will be used.721 722This is an example of using here-docs: >723 com SomeCommand {724 g:someVar =<< trim eval END725 ccc726 ddd727 END728 }729 730If the statements include a dictionary, its closing bracket must not be731written at the start of a line. Otherwise, it would be parsed as the end of732the block. This does not work: >733 command NewCommand {734 g:mydict = {735 'key': 'value',736 } # ERROR: will be recognized as the end of the block737 }738Put the '}' after the last item to avoid this: >739 command NewCommand {740 g:mydict = {741 'key': 'value' }742 }743 744Rationale: The "}" cannot be after a command because it would require parsing745the commands to find it. For consistency with that no command can follow the746"{". Unfortunately this means using "() => { command }" does not work, line747breaks are always required.748 749 *vim9-curly*750To avoid the "{" of a dictionary literal to be recognized as a statement block751wrap it in parentheses: >752 var Lambda = (arg) => ({key: 42})753 754Also when confused with the start of a command block: >755 ({756 key: value757 })->method()758 759 760Automatic line continuation ~761 *vim9-line-continuation* *E1097*762In many cases it is obvious that an expression continues on the next line. In763those cases there is no need to prefix the line with a backslash (see764|line-continuation|). For example, when a list spans multiple lines: >765 var mylist = [766 'one',767 'two',768 ]769And when a dict spans multiple lines: >770 var mydict = {771 one: 1,772 two: 2,773 }774With a function call: >775 var result = Func(776 arg1,777 arg2778 )779 780For binary operators in expressions not in [], {} or () a line break is781possible just before or after the operator. For example: >782 var text = lead783 .. middle784 .. end785 var total = start +786 end -787 correction788 var result = positive789 ? PosFunc(arg)790 : NegFunc(arg)791 792For a method call using "->" and a member using a dot, a line break is allowed793before it: >794 var result = GetBuilder()795 ->BuilderSetWidth(333)796 ->BuilderSetHeight(777)797 ->BuilderBuild()798 var result = MyDict799 .member800 801For commands that have an argument that is a list of commands, the | character802at the start of the line indicates line continuation: >803 autocmd BufNewFile *.match if condition804 | echo 'match'805 | endif806 807Note that this means that in heredoc the first line cannot start with a bar: >808 var lines =<< trim END809 | this doesn't work810 END811Either use an empty line at the start or do not use heredoc. Or temporarily812add the "C" flag to 'cpoptions': >813 set cpo+=C814 var lines =<< trim END815 | this works816 END817 set cpo-=C818If the heredoc is inside a function 'cpoptions' must be set before :def and819restored after the :enddef.820 821In places where line continuation with a backslash is still needed, such as822splitting up a long Ex command, comments can start with '#\ ': >823 syn region Text824 \ start='foo'825 #\ comment826 \ end='bar'827Like with legacy script '"\ ' is used. This is also needed when line828continuation is used without a backslash and a line starts with a bar: >829 au CursorHold * echom 'BEFORE bar'830 #\ some comment831 | echom 'AFTER bar'832<833 *E1050*834To make it possible for the operator at the start of the line to be835recognized, it is required to put a colon before a range. This example will836add "start" and "print": >837 var result = start838 + print839Like this: >840 var result = start + print841 842This will assign "start" and print a line: >843 var result = start844 :+ print845 846After the range an Ex command must follow. Without the colon you can call a847function without `:call`, but after a range you do need it: >848 MyFunc()849 :% call MyFunc()850 851Note that the colon is not required for the |+cmd| argument: >852 edit +6 fname853 854It is also possible to split a function header over multiple lines, in between855arguments: >856 def MyFunc(857 text: string,858 separator = '-'859 ): string860 861Since a continuation line cannot be easily recognized the parsing of commands862has been made stricter. E.g., because of the error in the first line, the863second line is seen as a separate command: >864 popup_create(some invalid expression, {865 exit_cb: Func})866Now "exit_cb: Func})" is actually a valid command: save any changes to the867file "_cb: Func})" and exit. To avoid this kind of mistake in Vim9 script868there must be white space between most command names and the argument.869*E1144*870 871However, the argument of a command that is a command won't be recognized. For872example, after "windo echo expr" a line break inside "expr" will not be seen.873 874 875Notes:876- "enddef" cannot be used at the start of a continuation line, it ends the877 current function.878- No line break is allowed in the LHS of an assignment. Specifically when879 unpacking a list |:let-unpack|. This is OK: >880 [var1, var2] =881 Func()882< This does not work: >883 [var1,884 var2] =885 Func()886- No line break is allowed in between arguments of an `:echo`, `:execute` and887 similar commands. This is OK: >888 echo [1,889 2] [3,890 4]891< This does not work: >892 echo [1, 2]893 [3, 4]894- In some cases it is difficult for Vim to parse a command, especially when895 commands are used as an argument to another command, such as `:windo`. In896 those cases the line continuation with a backslash has to be used.897 898 899White space ~900 *vim9-white-space* *E1004* *E1068* *E1069* *E1074* *E1127* *E1202*901Vim9 script enforces proper use of white space. This is no longer allowed: >902 var name=234 # Error!903 var name= 234 # Error!904 var name =234 # Error!905There must be white space before and after the "=": >906 var name = 234 # OK907White space must also be put before the # that starts a comment after a908command: >909 var name = 234# Error!910 var name = 234 # OK911 912White space is required around most operators.913 914White space is required in a sublist (list slice) around the ":", except at915the start and end: >916 otherlist = mylist[v : count] # v:count has a different meaning917 otherlist = mylist[:] # make a copy of the List918 otherlist = mylist[v :]919 otherlist = mylist[: v]920 921White space is not allowed:922- Between a function name and the "(": >923 Func (arg) # Error!924 Func925 \ (arg) # Error!926 Func927 (arg) # Error!928 Func(arg) # OK929 Func(930 arg) # OK931 Func(932 arg # OK933 )934< *E1205*935White space is not allowed in a `:set` command between the option name and a936following "&", "!", "<", "=", "+=", "-=" or "^=".937 938 939No curly braces expansion ~940 941|curly-braces-names| cannot be used.942 943 944Command modifiers are not ignored ~945 *E1176*946Using a command modifier for a command that does not use it gives an error.947 *E1082*948Also, using a command modifier without a following command is now an error.949 950 951Dictionary literals ~952 *vim9-literal-dict* *E1014*953Traditionally Vim has supported dictionary literals with a {} syntax: >954 let dict = {'key': value}955 956Later it became clear that using a simple text key is very common, thus957literal dictionaries were introduced in a backwards compatible way: >958 let dict = #{key: value}959 960However, this #{} syntax is unlike any existing language. As it turns out961that using a literal key is much more common than using an expression, and962considering that JavaScript uses this syntax, using the {} form for dictionary963literals is considered a much more useful syntax. In Vim9 script the {} form964uses literal keys: >965 var dict = {key: value}966 967This works for alphanumeric characters, underscore and dash. If you want to968use another character, use a single or double quoted string: >969 var dict = {'key with space': value}970 var dict = {"key\twith\ttabs": value}971 var dict = {'': value} # empty key972< *E1139*973In case the key needs to be an expression, square brackets can be used, just974like in JavaScript: >975 var dict = {["key" .. nr]: value}976 977The key type can be string, number, bool or float. Other types result in an978error. Without using [] the value is used as a string, keeping leading zeros.979An expression given with [] is evaluated and then converted to a string.980Leading zeros will then be dropped: >981 var dict = {000123: 'without', [000456]: 'with'}982 echo dict983 {'456': 'with', '000123': 'without'}984A float only works inside [] because the dot is not accepted otherwise: >985 var dict = {[00.013]: 'float'}986 echo dict987 {'0.013': 'float'}988 989 990No :xit, :t, :k, :append, :change or :insert ~991 *E1100*992These commands are too easily confused with local variable names.993Instead of `:x` or `:xit` you can use `:exit`.994Instead of `:t` you can use `:copy`.995Instead of `:k` you can use `:mark`.996 997 998Comparators ~999 1000The 'ignorecase' option is not used for comparators that use strings.1001Thus "=~" works like "=~#".1002 1003"is" and "isnot" (|expr-is| and |expr-isnot|) when used on strings now return1004false. In legacy script they just compare the strings, in |Vim9| script they1005check identity, and strings are copied when used, thus two strings are never1006the same (this might change someday if strings are not copied but reference1007counted).1008 1009 1010Abort after error ~1011 1012In legacy script, when an error is encountered, Vim continues to execute1013following lines. This can lead to a long sequence of errors and need to type1014CTRL-C to stop it. In Vim9 script execution of commands stops at the first1015error. Example: >1016 vim9script1017 var x = does-not-exist1018 echo 'not executed'1019 1020 1021For loop ~1022 *E1254*1023The loop variable must not be declared yet: >1024 var i = 11025 for i in [1, 2, 3] # Error!1026 1027It is possible to use a global variable though: >1028 g:i = 11029 for g:i in [1, 2, 3]1030 echo g:i1031 endfor1032 1033Legacy Vim script has some tricks to make a for loop over a list handle1034deleting items at the current or previous item. In Vim9 script it just uses1035the index, if items are deleted then items in the list will be skipped.1036Example legacy script: >1037 let l = [1, 2, 3, 4]1038 for i in l1039 echo i1040 call remove(l, index(l, i))1041 endfor1042Would echo:1043 11044 21045 31046 41047In compiled Vim9 script you get:1048 11049 31050Generally, you should not change the list that is iterated over. Make a copy1051first if needed.1052When looping over a list of lists, the nested lists can be changed. The loop1053variable is "final", it cannot be changed but what its value can be changed.1054 *E1306*1055The depth of loops, :for and :while loops added together, cannot exceed 10.1056 1057 1058Conditions and expressions ~1059 *vim9-boolean*1060Conditions and expressions are mostly working like they do in other languages.1061Some values are different from legacy Vim script:1062 value legacy Vim script Vim9 script ~1063 0 falsy falsy1064 1 truthy truthy1065 99 truthy Error!1066 "0" falsy Error!1067 "99" truthy Error!1068 "text" falsy Error!1069 1070For the "??" operator and when using "!" then there is no error, every value1071is either falsy or truthy. This is mostly like JavaScript, except that an1072empty list and dict is falsy:1073 1074 type truthy when ~1075 bool true, v:true or 11076 number non-zero1077 float non-zero1078 string non-empty1079 blob non-empty1080 list non-empty (different from JavaScript)1081 tuple non-empty (different from JavaScript)1082 dictionary non-empty (different from JavaScript)1083 func when there is a function name1084 special true or v:true1085 job when not NULL1086 channel when not NULL1087 class not applicable1088 object when not NULL1089 enum not applicable1090 enum value always1091 typealias not applicable1092 1093The boolean operators "||" and "&&" expect the values to be boolean, zero or1094one: >1095 1 || false == true1096 0 || 1 == true1097 0 || false == false1098 1 && true == true1099 0 && 1 == false1100 8 || 0 Error!1101 'yes' && 0 Error!1102 [] || 99 Error!1103 1104When using "!" for inverting, there is no error for using any type and the1105result is a boolean. "!!" can be used to turn any value into boolean: >1106 !'yes' == false1107 !![] == false1108 !![1, 2, 3] == true1109 1110When using "`.."` for string concatenation arguments of simple types are1111always converted to string: >1112 'hello ' .. 123 == 'hello 123'1113 'hello ' .. v:true == 'hello true'1114 1115Simple types are Number, Float, Special and Bool. For other types |string()|1116should be used.1117 *false* *true* *null* *null_blob* *null_channel*1118 *null_class* *null_dict* *null_function* *null_job*1119 *null_list* *null_object* *null_partial* *null_string*1120 *E1034*1121In Vim9 script one can use the following predefined values: >1122 true1123 false1124 null1125 null_blob1126 null_channel1127 null_class1128 null_dict1129 null_function1130 null_job1131 null_list1132 null_tuple1133 null_object1134 null_partial1135 null_string1136`true` is the same as `v:true`, `false` the same as `v:false`, `null` the same1137as `v:null`.1138 1139While `null` has the type "special", the other "null_" values have the type1140indicated by their name. Quite often a null value is handled the same as an1141empty value, but not always. The values can be useful to clear a script-local1142variable, since they cannot be deleted with `:unlet`. E.g.: >1143 var theJob = job_start(...)1144 # let the job do its work1145 theJob = null_job1146 1147The values can also be useful as the default value for an argument: >1148 def MyFunc(b: blob = null_blob)1149 # Note: compare against null, not null_blob,1150 # to distinguish the default value from an empty blob.1151 if b == null1152 # b argument was not given1153See |null-compare| for more information about testing against null.1154 1155It is possible to compare `null` with any value, this will not give a type1156error. However, comparing `null` with a number, float or bool will always1157result in `false`. This is different from legacy script, where comparing1158`null` with zero or `false` would return `true`.1159 *vim9-false-true*1160When converting a boolean to a string `false` and `true` are used, not1161`v:false` and `v:true` like in legacy script. `v:none` has no `none`1162replacement, it has no equivalent in other languages.1163 *vim9-string-index*1164Indexing a string with [idx] or taking a slice with [idx : idx] uses character1165indexes instead of byte indexes. Composing characters are included.1166Example: >1167 echo 'bár'[1]1168In legacy script this results in the character 0xc3 (an illegal byte), in Vim91169script this results in the string 'á'.1170A negative index is counting from the end, "[-1]" is the last character.1171To exclude the last character use |slice()|.1172To count composing characters separately use |strcharpart()|.1173If the index is out of range then an empty string results.1174 1175In legacy script "++var" and "--var" would be silently accepted and have no1176effect. This is an error in Vim9 script.1177 1178Numbers starting with zero are not considered to be octal, only numbers1179starting with "0o" are octal: "0o744". |scriptversion-4|1180 1181 1182What to watch out for ~1183 *vim9-gotchas*1184Vim9 was designed to be closer to often used programming languages, but at the1185same time tries to support the legacy Vim commands. Some compromises had to1186be made. Here is a summary of what might be unexpected.1187 1188Ex command ranges need to be prefixed with a colon. >1189 -> legacy Vim: shifts the previous line to the right1190 ->func() Vim9: method call in a continuation line1191 :-> Vim9: shifts the previous line to the right1192 1193 %s/a/b legacy Vim: substitute on all lines1194 x = alongname1195 % another Vim9: modulo operator in a continuation line1196 :%s/a/b Vim9: substitute on all lines1197 't legacy Vim: jump to mark t1198 'text'->func() Vim9: method call1199 :'t Vim9: jump to mark t1200 