mirror of
https://github.com/vim/vim.git
synced 2025-07-04 23:07:33 -04:00
193 lines
6.9 KiB
Plaintext
193 lines
6.9 KiB
Plaintext
*usr_46.txt* For Vim version 8.2. Last change: 2020 Jun 14
|
|
|
|
VIM USER MANUAL - by Bram Moolenaar
|
|
|
|
Write plugins using Vim9 script
|
|
|
|
|
|
The Vim9 script language is used for writing plugins, especially larger ones
|
|
that use multiple files. This chapter explains how to split up a plugin into
|
|
modules, import and export items and keep the rest local.
|
|
|
|
|46.1| Introduction
|
|
|46.2| Variable declarations
|
|
|46.3| Functions and types
|
|
|46.?| Using a Vim9 script from legacy script
|
|
|
|
Next chapter: |usr_90.txt| Installing Vim
|
|
Previous chapter: |usr_45.txt| Select your language (locale)
|
|
Table of contents: |usr_toc.txt|
|
|
|
|
==============================================================================
|
|
*46.1* Introduction *vim9-script-intro*
|
|
|
|
Vim9 script was designed to make it easier to write large Vim scripts. It
|
|
looks more like other script languages, especially Typescript. Also,
|
|
functions are compiled into instructions that can be executed quickly. This
|
|
makes Vim9 script a lot faster, up to a 100 times.
|
|
|
|
The basic idea is that a script file has items that are private, only used
|
|
inside the script file, and items that are exported, used outside of the
|
|
script file. The exported items can then be used by scripts that import them.
|
|
That makes very clear what is defined where.
|
|
|
|
Let's start with an example, a script that exports one function and has one
|
|
private function: >
|
|
|
|
vim9script " This indicates a Vim9 script file.
|
|
|
|
export def GetMessage(): string
|
|
let result = ''
|
|
...
|
|
result = GetPart(count)
|
|
...
|
|
return result
|
|
enddef
|
|
|
|
def GetPart(nr: number): string
|
|
if nr == 4
|
|
return 'yes'
|
|
else
|
|
return 'no'
|
|
endif
|
|
enddef
|
|
|
|
The `vim9script` command must be the very first command in the file. Without
|
|
it Vim will assume legacy script syntax.
|
|
|
|
The `export def GetMessage(): string` line starts with `export`, meaning that
|
|
this function can be imported and called by other scripts. The line
|
|
`def GetPart(...` does not start with `export`, this is a script-local
|
|
function, it can only be used inside this script file.
|
|
|
|
In the `export def GetMessage(): string` line you will notice the colon and
|
|
the return type. Vim9 functions, defined with `def`, require specifying the
|
|
type of arguments and the return type. That way Vim can compile the code
|
|
efficiently. The GetPart function defines an argument "nr" of type "number".
|
|
|
|
Notice that the assignment `result = GetPart(count)` does not use the `let`
|
|
command. That is explained in the next section.
|
|
|
|
==============================================================================
|
|
*46.2* Variable declarations *vim9-declarations*
|
|
|
|
In Vim9 script variables are declared once with a `:let` or `:const` command.
|
|
Assigning a value is done without `:let` and it is not possible to `:unlet`
|
|
the variable.
|
|
|
|
In most cases you will want to declare the variable and initialize it at the
|
|
same time: >
|
|
let myText = 'some text'
|
|
...
|
|
myText = 'other text'
|
|
|
|
The type of the variable will be inferred from the expression. In this case
|
|
it is a string. If you initialize with a number, then the type is number: >
|
|
let myNumber = 1234
|
|
...
|
|
myNumber = 0
|
|
|
|
If you try to assign a string to this variable, you will get an error: >
|
|
let myNumber = 'this fails!'
|
|
|
|
In the rare case you want a variable that can take values of any type, you
|
|
have to specify the type: >
|
|
let myVar: any = 1234
|
|
myVar = 'text also works'
|
|
|
|
You can also declare a variable without assigning a value. In that case Vim
|
|
will initialize it to zero or empty: >
|
|
let word: string
|
|
if condition
|
|
word = 'yes'
|
|
else
|
|
word = 'no'
|
|
endif
|
|
|
|
Although it's shorter to do: >
|
|
let word = condition ? 'yes' : 'no'
|
|
|
|
==============================================================================
|
|
*46.3* Functions and types
|
|
|
|
Legacy Vim script does have type checking, but this happens at runtime, when
|
|
the code is executed. And it's permissive, often a computation gives an
|
|
unexpected value instead of reporting an error. Thus you can define a
|
|
function and think it's fine, but see a problem only later when it is called: >
|
|
let s:collected = ''
|
|
func ExtendAndReturn(add)
|
|
let s:collected += a:add
|
|
return s:collected
|
|
endfunc
|
|
|
|
Can you spot the error? Try this: >
|
|
echo ExtendAndReturn('text')
|
|
And you'll see zero. Why? Because in legacy Vim script "+=" will convert the
|
|
arguments to numbers, and any string without a number results in zero!
|
|
|
|
With `:def` the type checking happens when compiling the function. For that
|
|
you need to specify the argument types and the return type. Also notice that
|
|
the argument is used without the "a:" prefix: >
|
|
let s:collected = ''
|
|
def ExtendAndReturn(add: string): string
|
|
s:collected += add
|
|
return s:collected
|
|
enddef
|
|
defcompile
|
|
|
|
Here we use `:defcompile` to do the compilation right away, without it the
|
|
compilation would happen when the function is called. Vim will tell you what
|
|
you did wrong: >
|
|
E1013: type mismatch, expected number but got string
|
|
|
|
Vim9 script is strict, it uses the "+" operator only for numbers and floats.
|
|
For string concatenation ".." must be used. This avoids mistakes and avoids
|
|
the automatic conversion that gave a surprising result above. So you change
|
|
the first line of the function to: >
|
|
s:collected ..= add
|
|
And now it works.
|
|
|
|
If the function does not return anything, just leave out the return type: >
|
|
def ReportResult(result: string)
|
|
echo 'The result is: ' .. result
|
|
enddef
|
|
|
|
This is also checked, if you try to return a value you'll get an error.
|
|
|
|
In case you don't care about types or have a function that does work with
|
|
multiple types, you can use the "any" type: >
|
|
def Store(key: string, value: any)
|
|
resultDict[key] = value
|
|
enddef
|
|
|
|
==============================================================================
|
|
*46.?* Using a Vim9 script from legacy script *source-vim9-script*
|
|
|
|
In some cases you have a legacy Vim script where you want to use items from a
|
|
Vim9 script. For example in your .vimrc you want to initialize a plugin. The
|
|
best way to do this is to use `:import`. For example: >
|
|
|
|
import Init as NiceInit from 'myNicePlugin.vim'
|
|
call NiceInit('today')
|
|
|
|
This finds the exported function "Init" in the Vim9 script file and makes it
|
|
available as script-local item "NiceInit". `:import` always uses the script
|
|
namespace, even when "s:" is not given. If "myNicePlugin.vim" was already
|
|
sourced it is not sourced again.
|
|
|
|
Besides avoiding putting any items in the global namespace (where name clashes
|
|
can cause unexpected errors), this also means the script is sourced only once,
|
|
no matter how many times items from it are imported.
|
|
|
|
In some cases, e.g. for testing, you may just want to source the Vim9 script.
|
|
That is OK, but then only global items will be available. The Vim9 script
|
|
will have to make sure to use a unique name for these global items. Example: >
|
|
source ~/.vim/extra/myNicePlugin.vim
|
|
call g:NicePluginTest()
|
|
|
|
==============================================================================
|
|
|
|
Next chapter: |usr_90.txt| Installing Vim
|
|
|
|
Copyright: see |manual-copyright| vim:tw=78:ts=8:noet:ft=help:norl:
|