diff options
Diffstat (limited to 'runtime/doc/usr_46.txt')
-rw-r--r-- | runtime/doc/usr_46.txt | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/runtime/doc/usr_46.txt b/runtime/doc/usr_46.txt new file mode 100644 index 0000000000..b588223a8d --- /dev/null +++ b/runtime/doc/usr_46.txt @@ -0,0 +1,192 @@ +*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 suprising 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: |