runtime(doc): Update and clarify vim9.txt Section 3

closes: #18779

Signed-off-by: Peter Kenny <github.com@k1w1.cyou>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
Peter Kenny
2025-11-30 09:40:04 +00:00
committed by Christian Brabandt
parent 49f731d243
commit 8b9b422111
2 changed files with 448 additions and 162 deletions

View File

@ -6815,6 +6815,7 @@ conversion-server mbyte.txt /*conversion-server*
convert-to-HTML syntax.txt /*convert-to-HTML* convert-to-HTML syntax.txt /*convert-to-HTML*
convert-to-XHTML syntax.txt /*convert-to-XHTML* convert-to-XHTML syntax.txt /*convert-to-XHTML*
convert-to-XML syntax.txt /*convert-to-XML* convert-to-XML syntax.txt /*convert-to-XML*
convert_:function_to_:def vim9.txt /*convert_:function_to_:def*
convert_legacy_function_to_vim9 vim9.txt /*convert_legacy_function_to_vim9* convert_legacy_function_to_vim9 vim9.txt /*convert_legacy_function_to_vim9*
copy() builtin.txt /*copy()* copy() builtin.txt /*copy()*
copy-diffs diff.txt /*copy-diffs* copy-diffs diff.txt /*copy-diffs*
@ -11637,6 +11638,7 @@ vim9-types vim9.txt /*vim9-types*
vim9-unpack-ignore vim9.txt /*vim9-unpack-ignore* vim9-unpack-ignore vim9.txt /*vim9-unpack-ignore*
vim9-user-command vim9.txt /*vim9-user-command* vim9-user-command vim9.txt /*vim9-user-command*
vim9-variable-arguments vim9.txt /*vim9-variable-arguments* vim9-variable-arguments vim9.txt /*vim9-variable-arguments*
vim9-white-space vim9.txt /*vim9-white-space*
vim9.txt vim9.txt /*vim9.txt* vim9.txt vim9.txt /*vim9.txt*
vim9class.txt vim9class.txt /*vim9class.txt* vim9class.txt vim9class.txt /*vim9class.txt*
vim9script vim9.txt /*vim9script* vim9script vim9.txt /*vim9script*

View File

@ -1,4 +1,4 @@
*vim9.txt* For Vim version 9.1. Last change: 2025 Nov 11 *vim9.txt* For Vim version 9.1. Last change: 2025 Nov 30
VIM REFERENCE MANUAL by Bram Moolenaar VIM REFERENCE MANUAL by Bram Moolenaar
@ -104,7 +104,8 @@ script and `:def` functions; details are below:
echo "hello " echo "hello "
.. yourName .. yourName
.. ", how are you?" .. ", how are you?"
- White space is required in many places to improve readability. - White space is required in many places to improve readability,
see |vim9-white-space|.
- Assign values without `:let` *E1126* , declare variables with `:var`: > - Assign values without `:let` *E1126* , declare variables with `:var`: >
var count = 0 var count = 0
count += 3 count += 3
@ -232,7 +233,7 @@ You can call a legacy dict function though: >
var d = {func: Legacy, value: 'text'} var d = {func: Legacy, value: 'text'}
d.func() d.func()
enddef enddef
< *E1096* *E1174* *E1175*
The argument types and return type need to be specified. The "any" type can The argument types and return type need to be specified. The "any" type can
be used, type checking will then be done at runtime, like with legacy be used, type checking will then be done at runtime, like with legacy
functions. functions.
@ -275,7 +276,7 @@ script "export" needs to be used for those to be used elsewhere. >
def ThisFunction() # script-local def ThisFunction() # script-local
def g:ThatFunction() # global def g:ThatFunction() # global
export def Function() # for import and import autoload export def Function() # for import and import autoload
< *E1058* *E1075* < *E1075*
When using `:function` or `:def` to specify a nested function inside a `:def` When using `:function` or `:def` to specify a nested function inside a `:def`
function and no namespace was given, this nested function is local to the code function and no namespace was given, this nested function is local to the code
block it is defined in. It cannot be used in `function()` with a string block it is defined in. It cannot be used in `function()` with a string
@ -842,7 +843,7 @@ Notes:
White space ~ White space ~
*E1004* *E1068* *E1069* *E1074* *E1127* *E1202* *vim9-white-space* *E1004* *E1068* *E1069* *E1074* *E1127* *E1202*
Vim9 script enforces proper use of white space. This is no longer allowed: > Vim9 script enforces proper use of white space. This is no longer allowed: >
var name=234 # Error! var name=234 # Error!
var name= 234 # Error! var name= 234 # Error!
@ -1236,69 +1237,245 @@ subtracting one: >
Using ++var or --var in an expression is not supported yet. Using ++var or --var in an expression is not supported yet.
============================================================================== ==============================================================================
3. New style functions *fast-functions* 3. New style functions *fast-functions*
*:def* *E1028* *:def*
:def[!] {name}([arguments])[: {return-type}] :def[!] {name}([arguments])[: {return-type}]
Define a new function by the name {name}. The body of Define a new function by the name {name}. The body of
the function follows in the next lines, until the the function follows in the next lines, until the
matching `:enddef`. *E1073* matching `:enddef`.
*E1011* *E1073*
The {name} cannot be reused at the script-local level: >vim9
vim9script
def F_1073()
enddef
def F_1073() # E1073: Name already defined: <SNR>...
enddef
< *E1011*
The {name} must be less than 100 bytes long. The {name} must be less than 100 bytes long.
*E1003* *E1027* *E1056* *E1059*
The type of value used with `:return` must match *E1077*
{return-type}. When {return-type} is omitted or is
"void" the function is not expected to return
anything.
*E1077* *E1123*
{arguments} is a sequence of zero or more argument {arguments} is a sequence of zero or more argument
declarations. There are three forms: declarations. There are three forms:
{name}: {type} {name}: {type}
{name} = {value} {name} = {value}
{name}: {type} = {value} {name}: {type} = {value}
The first form is a mandatory argument, the caller The first form is a mandatory argument. So, the
must always provide them. declaration must provide a type. Example: >vim9
The second and third form are optional arguments.
When the caller omits an argument the {value} is used.
vim9script
def F_1077(x): void
# E1077: Missing argument type for x
enddef
<
For the second form, because the declaration does not
specify it, Vim infers the type. For both second and
third forms, a default {value} applies when the
caller omits it. Examples: >vim9
vim9script
def SecondForm(arg = "Hi"): void
echo $'2. arg is a "{arg->typename()}" type ' ..
$'and the default value of arg is "{arg}"'
enddef
SecondForm()
def ThirdForm(arg2: number = 9): void
echo $'3. default value of arg2 is {arg2}'
enddef
ThirdForm()
< *E1123*
Arguments in a builtin function called in a `:def`
function must have commas between arguments: >vim9
vim9script
def F_1123(a: number, b: number): void
echo max(a b)
# E1123: Missing comma before argument: b)
enddef
F_1123(1, 2)
< *E1003* *E1027* *E1096*
The type of value used with `:return` must match
{return-type}. When {return-type} is omitted or is
"void" the function is not allowed to return
anything. Examples: >vim9
vim9script
def F_1003(): bool
return # E1003: Missing return value
enddef
F_1003()
< >vim9
vim9script
def F_1027(): bool
echo false # E1027: Missing return statement
enddef
F_1027()
< >vim9
vim9script
def F_1096(): void
return false # E1096: Returning a value ...
enddef
F_1096()
< *E1056* *E1059*
When ": {return-type}" is specified, {return-type}
cannot be omitted (leaving a hanging colon). The ": "
also cannot be preceded by white space. Examples: >vim
def F_1056():
# E1056: Expected a type:
enddef
def F_1059() : bool
# E1059: No white space allowed before colon:...
enddef
<
The function will be compiled into instructions when The function will be compiled into instructions when
called, or when `:disassemble` or `:defcompile` is called or when either `:defcompile` or `:disassemble` is
used. Syntax and type errors will be produced at that used. (For an example, see |:disassemble|.) Syntax
time. and type errors will be produced at that time.
*E1058*
It is possible to nest `:def` inside another `:def` or It is possible to nest `:def` inside another `:def` or
`:function` up to about 50 levels deep. `:function` only up to 49 levels deep. At 50 or more
levels, it is a |E1058| error.
*E1117* *E1117*
[!] is used as with `:function`. Note that [!] is allowed only in legacy Vim script because it
script-local functions cannot be deleted or redefined permits function redefinition (as with `:function`!).
later in Vim9 script. They can only be removed by In Vim9 script, ! is not allowed because script-local
reloading the same script. functions cannot be deleted or redefined, though they
can be removed by reloading the script. Also, nested
functions cannot use ! for redefinition. Examples: >vim
" Legacy Vim script :def! example
def! LegacyFunc()
echo "def! is allowed in a legacy Vim script"
enddef
call LegacyFunc()
< >vim9
vim9script
def Func()
def! InnerFunc()
# E1117: Cannot use ! with nested :def
enddef
enddef
Func()
< >vim9
vim9script
def! F_477(): void # E477: No ! allowed
enddef
< >vim9
vim9script
def F_1084(): void
enddef
delfunction! F_1084
# E1084: Cannot delete Vim9 script function F_1084
<
Note: The generic error *E1028* ("Compiling :def
function failed") indicates an undeterminable error
during compilation. If reproducible, it may be
reported at https://github.com/vim/vim/issues as
it could represent a gap in Vim's error reporting.
*:enddef* *E1057* *E1152* *E1173* *:enddef* *E1057* *E1152* *E1173*
:enddef End of a function defined with `:def`. It should be on :enddef End of a function defined with `:def`. It should be on
a line by its own. a line by itself. Examples: >vim9
vim9script
def MyFunc()
echo 'Do Something' | enddef
# E1057: Missing :enddef
< >vim9
vim9script
def F_1173()
enddef echo 'X'
# E1173: Text found after enddef: echo 'X'
< >vim9
vim9script
def F_1152()
function X()
enddef # E1152: Mismatched enddef
enddef
<
You may also find this wiki useful. It was written by an early adopter of You may also find this wiki useful. It was written by an early adopter of
Vim9 script: https://github.com/lacygoill/wiki/blob/master/vim/vim9.md Vim9 script: https://github.com/lacygoill/wiki/blob/master/vim/vim9.md
If the script the function is defined in is Vim9 script, then script-local If the script the `:def` function is defined in is Vim9 script, script-local
variables can be accessed without the "s:" prefix. They must be defined variables must be accessed without using the "s:" prefix. They must be
before the function is compiled. If the script the function is defined in is defined before the function is compiled and there is no way to avoid errors
legacy script, then script-local variables must be accessed with the "s:" (e.g., by using |exists()|) to conditionally skip undeclared variables.
prefix if they do not exist at the time of compiling. For example: >vim9
*E1269*
Script-local variables in a |Vim9| script must be declared at the script
level. They cannot be created in a function, also not in a legacy function.
vim9script
def MyVim9def()
echo unus # Echoes 1
# echo s:unus # This would be E1268 (Cannot use s: in Vim9)
if exists('duo')
# echo duo # This would be E1001 (Variable not found: duo)
endif
enddef
var unus: number = 1
MyVim9def() # MyVim9def is compiled ("duo" does not exist yet)
var duo: number = 2
<
If the script the `:def` function is defined in is legacy Vim script,
script-local variables may be accessed with or without the "s:" prefix.
However, using "s:" may defer variable resolution to runtime, avoiding
compilation errors for variables that may not exist yet, as this example
explains: >vim
" legacy Vim script
def! MyLegacyDef(): void
echo [unus, s:unus] # Echoes [1, 1]
# (If uncommented) First sourcing of 'echo s:duo' is E121 and
# causes a compilation error; subsequent sourcing echoes 2:
# echo s:duo
if exists("s:duo")
# First sourcing: skips echo; subsequent sourcing: echoes 2
echo s:duo
endif
if exists("duo")
# (If uncommented) First sourcing of 'echo duo' is E1001 and
# causes a compilation error; subsequent sourcing echoes 2:
# echo duo
endif
enddef
let s:unus = 1
call MyLegacyDef() " Calls MyLegacyDef() and compiles if not already
let s:duo = 2
< *E1269*
Script-local variables in a Vim9 script must be declared at the script
level. They cannot be created in a `:def` function and may not be declared
in a legacy function with the "s:" prefix. For example: >vim9
vim9script
function F_1269()
let s:i_wish = v:true
endfunction
F_1269()
# E1269: Cannot create a Vim9 script variable in a function: s:i_wish
<
*:defc* *:defcompile* *:defc* *:defcompile*
:defc[ompile] Compile functions and classes (|class-compile|) :defc[ompile] Compile functions and classes (|class-compile|)
defined in the current script that were not compiled defined in the current script that were not compiled
yet. This will report any errors found during yet. This will report any errors found during
compilation. compilation.
:defc[ompile] MyClass Compile all methods in a class. |class-compile| Example: When the three lines (up to and including
`enddef`) are sourced, there is no error because the
Vim9 `:def` function is not compiled. However, if all
four lines are sourced, compilation fails: >vim9
vim9script
def F_1027(): string
enddef
defcompile F_1027 # E1027: Missing return statement
:defc[ompile] MyClass Compile all methods in a class. (See |:disassemble|
for an example.)
:defc[ompile] {func} :defc[ompile] {func}
:defc[ompile] debug {func} :defc[ompile] debug {func}
@ -1306,16 +1483,35 @@ level. They cannot be created in a function, also not in a legacy function.
Compile function {func}, if needed. Use "debug" and Compile function {func}, if needed. Use "debug" and
"profile" to specify the compilation mode. "profile" to specify the compilation mode.
This will report any errors found during compilation. This will report any errors found during compilation.
{func} call also be "ClassName.functionName" to {func} can also be "ClassName.functionName" to
compile a function or method in a class. compile a function or method in a class.
{func} call also be "ClassName" to compile all {func} can also be "ClassName" to compile all
functions and methods in a class. functions and methods in a class.
*:disa* *:disassemble* *:disa* *:disassemble*
:disa[ssemble] {func} Show the instructions generated for {func}. :disa[ssemble] {func} Show the instructions generated for {func}.
This is for debugging and testing. *E1061* This is for debugging and testing.
Note that for command line completion of {func} you If {func} is not found, error *E1061* occurs.
can prepend "s:" to find script-local functions. {func} can also be "ClassName.functionName" to
disassemble a function in a class.
The following example demonstrates using `:defcompile`
with a |class| and `:disassemble` with a
"ClassName.functionName" (positioning the cursor on
the last line of the visually sourced script): >vim9
vim9script
class Line
var lnum: number
def new(this.lnum)
enddef
def SetLnum()
cursor(this.lnum, 52)
enddef
endclass
defcompile Line
disassemble Line.SetLnum
var vlast: Line = Line.new(line("'>"))
vlast.SetLnum() # Cursor is positioned here->_
:disa[ssemble] profile {func} :disa[ssemble] profile {func}
Like `:disassemble` but with the instructions used for Like `:disassemble` but with the instructions used for
@ -1325,156 +1521,234 @@ level. They cannot be created in a function, also not in a legacy function.
Like `:disassemble` but with the instructions used for Like `:disassemble` but with the instructions used for
debugging. debugging.
Note: For command line completion of {func}, script-local functions
are shown with their <SNR>. Depending on options, including
|wildmenumode()|, completion may work with "s:", "<S", or the function
name directly. (For example, in Vim started with |-u| NONE, ":disa s:"
and |c_CTRL-E| lists script-local function names.)
Limitations ~ Limitations ~
Local variables will not be visible to string evaluation. For example: > Variables local to `:def` functions are not visible to string evaluation.
def MapList(): list<string> The following example shows that the script-local constant "SCRIPT_LOCAL" is
var list = ['aa', 'bb', 'cc', 'dd'] visible whereas the function-local constant "DEF_LOCAL" is not: >vim9
return range(1, 2)->map('list[v:val]')
enddef
vim9script
const SCRIPT_LOCAL = ['A', 'script-local', 'list']
def MapList(scope: string): list<string>
const DEF_LOCAL: list<string> = ['A', 'def-local', 'list']
if scope == 'script local'
return [1]->map('SCRIPT_LOCAL[v:val]')
else
return [1]->map('DEF_LOCAL[v:val]')
endif
enddef
echo 'script local'->MapList() # Echoes ['script-local']
echo 'def local'->MapList() # E121: Undefined variable: DEF_LOCAL
<
The map argument is a string expression, which is evaluated without the The map argument is a string expression, which is evaluated without the
function scope. Instead, use a lambda: > function scope. Instead, in Vim9 script, use a lambda: >vim9
vim9script
def MapList(): list<string> def MapList(): list<string>
var list = ['aa', 'bb', 'cc', 'dd'] const DEF_LOCAL: list<string> = ['A', 'def-local', 'list']
return range(1, 2)->map((_, v) => list[v]) return [1]->map((_, v) => DEF_LOCAL[v])
enddef enddef
echo MapList() # Echoes ['def-local']
<
For commands that are not compiled, such as `:edit`, |backtick-expansion| can
be used and it can use the local scope. Example: >vim9
For commands that are not compiled, such as `:edit`, backtick expansion can be vim9script
used and it can use the local scope. Example: > def EditNewBlah()
def Replace() var fname: string = 'blah.txt'
var fname = 'blah.txt' split
edit `=fname` edit `=fname`
enddef enddef
EditNewBlah() # A new split is created as buffer 'blah.txt'
<
Closures defined in a loop can either share a variable or each have their own
copy, depending on where the variable is declared. With a variable declared
outside the loop, all closures reference the same shared variable.
The following example demonstrates the consequences, with the "outloop"
variable existing only once: >vim9
Closures defined in a loop will share the same context. For example: > vim9script
var flist: list<func> var flist: list<func>
for i in range(5) def ClosureEg(n: number): void
var inloop = i var outloop: number = 0 # outloop is declared outside the loop!
flist[i] = () => inloop for i in range(n)
endfor outloop = i
echo range(5)->map((i, _) => flist[i]()) flist[i] = (): number => outloop # Closures ref the same var
# Result: [4, 4, 4, 4, 4] endfor
echo range(n)->map((i, _) => flist[i]())
enddef
ClosureEg(4) # Echoes [3, 3, 3, 3]
<
All closures put in the list refer to the same instance, which, in the end,
is 3.
However, when the variable is declared inside the loop, each closure gets its
own copy, as shown in this example: >vim9
vim9script
var flist: list<func>
def ClosureEg(n: number): void
for i in range(n)
var inloop: number = i # inloop is declared inside the loop
flist[i] = (): number => inloop # Closures ref each inloop
endfor
echo range(n)->map((i, _) => flist[i]())
enddef
ClosureEg(4) # Echoes [0, 1, 2, 3]
Another way to have a separate context for each closure is to call a
function to define it: >vim9
vim9script
def GetClosure(i: number): func
var infunc: number = i
return (): number => infunc
enddef
var flist: list<func>
def ClosureEg(n: number): void
for i in range(n)
flist[i] = GetClosure(i)
endfor
echo range(n)->map((i, _) => flist[i]())
enddef
ClosureEg(4) # Echoes [0, 1, 2, 3]
< *E1271* < *E1271*
A closure must be compiled in the context that it is defined in, so that A closure must be compiled in the context that it is defined in, so that
variables in that context can be found. This mostly happens correctly, except variables in that context can be found. This mostly happens correctly,
when a function is marked for debugging with `:breakadd` after it was compiled. except when a function is marked for debugging with `:breakadd` after it was
Make sure to define the breakpoint before compiling the outer function. compiled. Make sure to define the breakpoint before compiling the outer
function.
*E1248*
In some situations, such as when a Vim9 closure which captures local variables
is converted to a string and then executed, an error occurs. This happens
because the string execution context cannot access the local variables from
the original context where the closure was defined. For example: >vim9
The "inloop" variable will exist only once, all closures put in the list refer vim9script
to the same instance, which in the end will have the value 4. This is def F_1248(): void
efficient, also when looping many times. If you do want a separate context var n: number
for each closure, call a function to define it: > var F: func = () => {
def GetClosure(i: number): func n += 1
var infunc = i }
return () => infunc try
execute printf("call %s()", F)
catch
echo v:exception
endtry
enddef enddef
F_1248() # Vim(call):E1248: Closure called from invalid context
var flist: list<func> In Vim9 script, a loop variable is invalid after the loop is closed.
for i in range(5) For example, this timer will echo 0 to 2 on separate lines. However, if
flist[i] = GetClosure(i) the variable "n" is used after the `:endfor`, that is an |E121| error: >vim9
vim9script
for n in range(3)
var nr: number = n
timer_start(1000 * n, (_) => {
echowindow nr
})
endfor endfor
echo range(5)->map((i, _) => flist[i]()) try
# Result: [0, 1, 2, 3, 4] echowindow n
catch
In some situations, especially when calling a Vim9 closure from legacy echo v:exception
context, the evaluation will fail. *E1248* endtry
<
Note that at the script level the loop variable will be invalid after the Note: Using `:echowindow` is useful in a timer because messages go
loop, also when used in a closure that is called later, e.g. with a timer. into a popup and will not interfere with what the user is
This will generate error |E1302|: > doing when it triggers.
for n in range(4)
timer_start(500 * n, (_) => {
echowin n
})
endfor
You need to use a block and define a variable there, and use that one in the
closure: >
for n in range(4)
{
var nr = n
timer_start(500 * n, (_) => {
echowin nr
})
}
endfor
Using `:echowindow` is useful in a timer, the messages go into a popup and will
not interfere with what the user is doing when it triggers.
Converting a function from legacy to Vim9 ~ Converting a :function to a :def~
*convert_legacy_function_to_vim9* *convert_legacy_function_to_vim9*
These are the most changes that need to be made to convert a legacy function *convert_:function_to_:def*
to a Vim9 function: There are many changes that need to be made to convert a `:function` to
a `:def` function. The following are some of them:
- Change `let` used to declare variables to one of `var`, `const`, or `final`,
and remove the "s:" from each |script-variable|.
- Change `func` or `function` to `def`. - Change `func` or `function` to `def`.
- Change `endfunc` or `endfunction` to `enddef`. - Change `endfunc` or `endfunction` to `enddef`.
- Add types to the function arguments. - Add the applicable type (or "any") to each function argument.
- If the function returns something, add the return type. - Remove "a:" from each |function-argument|.
- Change comments to start with # instead of ". - Remove inapplicable options such as |:func-range|, |:func-abort|,
|:func-dict|, and |:func-closure|.
- If the function returns something, add the return type. (Ideally, add
"void" if it does not return anything.)
- Remove line continuation backslashes from places they are not required.
- Remove `let` for assigning values to |g:|, |b:|, |w:|, |t:|, or |l:| variables.
- Rewrite |lambda| expressions in Vim9 script syntax (see |vim9-lambda|).
- Change comments to start with # (preceded by white space) instead of ".
- Insert white space in expressions where required (see |vim9-white-space|).
- Change "." used for string concatenation to " .. ". (Alternatively, use
an |interpolated-string|.)
For example, a legacy function: > The following legacy Vim script and Vim9 script examples demonstrate all
func MyFunc(text) those differences. First, legacy Vim script: >vim
" function body
endfunc let s:lnum=0
< Becomes: > function Leg8(arg) abort
def MyFunc(text: string): number let l:pre=['Result',
# function body \': ']
let b:arg=a:arg
let s:lnum+=2
let b:arg*=4
let l:result={pre->join(pre,'')}(l:pre)
return l:result.(b:arg+s:lnum)"no space before comment
endfunction
call Leg8(10)->popup_notification(#{time: 3000})" Pops up 'Result: 42'
The equivalent in Vim9 script: >vim9
vim9script
var lnum: number
def Vim9(arg: number): string
final pre = ['Result',
': ']
b:arg = arg
lnum += 2
b:arg *= 4
const RESULT: string = ((lpre) => join(lpre, ''))(pre)
return RESULT .. (b:arg + lnum) # space required before # comment
enddef enddef
Vim9(10)->popup_notification({time: 3000}) # Pops up 'Result: 42'
- Remove "a:" used for arguments. E.g.: > < Note: This example also demonstrates (outside the `:def` function):
return len(a:text) - Removing "#" from the legacy |#{}| - see |vim9-literal-dict|
< Becomes: > - Omitting `:call` (allowed, though unnecessary in Vim9 script)
return len(text)
- Change `let` used to declare a variable to `var`.
- Remove `let` used to assign a value to a variable. This is for local
variables already declared and b: w: g: and t: variables.
For example, legacy function: >
let lnum = 1
let lnum += 3
let b:result = 42
< Becomes: >
var lnum = 1
lnum += 3
b:result = 42
- Insert white space in expressions where needed.
- Change "." used for concatenation to "..".
For example, legacy function: >
echo line(1).line(2)
< Becomes: >
echo line(1) .. line(2)
- line continuation does not always require a backslash: >
echo ['one',
\ 'two',
\ 'three'
\ ]
< Becomes: >
echo ['one',
'two',
'three'
]
Calling a function in an expr option ~ Calling a :def function in an expr option ~
*expr-option-function* *expr-option-function*
The value of a few options, such as 'foldexpr', is an expression that is The value of a few options, such as 'foldexpr', is an expression that is
evaluated to get a value. The evaluation can have quite a bit of overhead. evaluated to get a value. The evaluation can have quite a bit of overhead.
One way to minimize the overhead, and also to keep the option value very One way to minimize the overhead, and also to keep the option value simple,
simple, is to define a compiled function and set the option to call it is to define a compiled function and set the option to call it without
without arguments. Example: > arguments. For example: >vim9
vim9script vim9script
def MyFoldFunc(): any def MyFoldFunc(): string
... compute fold level for line v:lnum # This matches start of line (^), followed by a digit, a full stop
return level # a space or tab, an uppercase character, with an empty next line
return getline(v:lnum) =~ '^[[:digit:]]\.[[:blank:]][[:upper:]]'
&& getline(v:lnum + 1)->empty() ? '>1' : '1'
enddef enddef
set foldexpr=s:MyFoldFunc() set foldexpr=MyFoldFunc()
set foldmethod=expr
norm! zM
<
Warning: This script creates and applies folds at the "Heading 1" level of
this vim9.txt help buffer. (You can use |zR|, in Normal mode, to
open all the folds after sourcing the script.)
============================================================================== ==============================================================================
@ -1927,8 +2201,8 @@ dictionary when it is required: >vim
echo [8, 9]->keys() echo [8, 9]->keys()
vim9cmd echo [8, 9]->keys() # E1206: Dictionary required vim9cmd echo [8, 9]->keys() # E1206: Dictionary required
< <
*E1023* *E1024* *E1029* *E1023* *E1024* *E1029* *E1030*
*E1030* *E1210* *E1212* *E1174* *E1175* *E1210* *E1212*
However, sometimes there will be an error in Vim9 script, which breaks However, sometimes there will be an error in Vim9 script, which breaks
backwards compatibility. The following examples illustrate various places backwards compatibility. The following examples illustrate various places
this happens. The legacy Vim script behavior, which does not fail, is shown this happens. The legacy Vim script behavior, which does not fail, is shown
@ -1963,6 +2237,16 @@ in Vim9 script.
let b:l = [42] | unlet b:l['#'] | echo b:l let b:l = [42] | unlet b:l['#'] | echo b:l
vim9cmd b:l = [42] | vim9cmd unlet b:l['#'] # E1030: Using a string... vim9cmd b:l = [42] | vim9cmd unlet b:l['#'] # E1030: Using a string...
<
- Not using a string where an argument requires a string: >vim9
echo substitute('Hallo', 'a', 'e', v:true)
vim9cmd echo substitute('Hallo', 'a', 'e', true) # E1174: String...
<
- Using an empty string in an argument that requires a non-empty string: >vim9
echo exepath('')
vim9cmd echo exepath('') # E1175: Non-empty string required for arg...
< <
- Not using a number when it is required: >vim - Not using a number when it is required: >vim