2022-06-03 21:59:47 +01:00
|
|
|
*usr_52.txt* For Vim version 8.2. Last change: 2022 Jun 03
|
2020-06-14 17:29:55 +02:00
|
|
|
|
|
|
|
VIM USER MANUAL - by Bram Moolenaar
|
|
|
|
|
2022-06-03 21:59:47 +01:00
|
|
|
Write larger plugins
|
2020-06-14 17:29:55 +02:00
|
|
|
|
2022-06-03 21:59:47 +01:00
|
|
|
TODO: this file needs to be updated
|
2020-06-14 17:29:55 +02:00
|
|
|
|
2022-06-03 21:59:47 +01:00
|
|
|
When plugins do more than simple things, they tend to grow big. This file
|
|
|
|
explains how to make sure they still load fast and how to split them up in
|
|
|
|
smaller parts
|
2020-06-14 17:29:55 +02:00
|
|
|
|
2022-06-03 21:59:47 +01:00
|
|
|
|52.1| Export and import
|
|
|
|
|52.2| Autoloading
|
|
|
|
|52.3| Autoloading without import/export
|
|
|
|
|52.4| Other mechanisms to use
|
|
|
|
|52.5| Using a Vim9 script from legacy script
|
2020-06-14 17:29:55 +02:00
|
|
|
|
|
|
|
Next chapter: |usr_90.txt| Installing Vim
|
2022-05-14 13:33:50 +01:00
|
|
|
Previous chapter: |usr_51.txt| Create a plugin
|
2020-06-14 17:29:55 +02:00
|
|
|
Table of contents: |usr_toc.txt|
|
|
|
|
|
|
|
|
==============================================================================
|
2022-06-03 21:59:47 +01:00
|
|
|
*52.1* Export and import
|
2020-06-14 17:29:55 +02:00
|
|
|
|
|
|
|
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: >
|
|
|
|
|
2020-08-07 19:54:59 +02:00
|
|
|
vim9script " This indicates a Vim9 script file.
|
2020-06-14 17:29:55 +02:00
|
|
|
|
|
|
|
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".
|
|
|
|
|
2022-06-03 21:59:47 +01:00
|
|
|
TODO: import/export example
|
|
|
|
|
|
|
|
USING GLOBALS
|
|
|
|
|
|
|
|
Sometimes you will want to use global variables or functions, so that they can
|
|
|
|
be used anywhere. A good example is a global variable that passes a
|
|
|
|
preference to a plugin. To avoid other scripts using the same name, use a
|
|
|
|
prefix that is very unlikely to be used elsewhere. For example, if you have a
|
|
|
|
"mytags" plugin, you could use: >
|
|
|
|
|
|
|
|
g:mytags_location = '$HOME/project'
|
|
|
|
g:mytags_style = 'fast'
|
2020-06-14 17:29:55 +02:00
|
|
|
|
|
|
|
==============================================================================
|
2022-06-03 21:59:47 +01:00
|
|
|
*52.2* Autoloading
|
|
|
|
|
|
|
|
TODO: autoloading with import/export
|
|
|
|
|
|
|
|
After splitting your large script into pieces, all the lines will still be
|
|
|
|
loaded and executed the moment the script is used. Every `import` loads the
|
|
|
|
imported script to find the items defined there. Although that is good for
|
|
|
|
finding errors early, it also takes time. Which is wasted if the
|
|
|
|
functionality is not often used.
|
|
|
|
|
|
|
|
Instead of having `import` load the script immediately, it can be postponed
|
|
|
|
until needed. >
|
|
|
|
import autoload "./LoadLater.vim"
|
2020-06-14 17:29:55 +02:00
|
|
|
|
2022-06-03 21:59:47 +01:00
|
|
|
Now you can use exported items as usual: "LoadLater.GetMonth(4)".
|
|
|
|
However, the type will not be checked. Not even the existence of the
|
|
|
|
GetMonth() function is checked until it is used. You will have to decide what
|
|
|
|
is more important for your script. You can also add the "autoload" argument
|
|
|
|
later, after you have checked everything works.
|
|
|
|
|
|
|
|
Another form is to use a script name that is not an absolute or relative
|
|
|
|
path: >
|
|
|
|
import autload "monthlib.vim"
|
|
|
|
|
|
|
|
This will search for the script "monthlib.vim" in the autoload directories of
|
|
|
|
'runtimepath'. With Unix the directory often is "~/.vim/autoload".
|
|
|
|
|
|
|
|
The main advantage of this is that this script can be shared with other
|
|
|
|
scripts. You do need to make sure that the script name is unique, since Vim
|
|
|
|
will search all the "autoload" directories in 'runtimepath', and if you are
|
|
|
|
using several plugins, these may add several directories to 'runtimepath',
|
|
|
|
each of which might have an "autoload" directory.
|
2020-06-14 17:29:55 +02:00
|
|
|
|
|
|
|
==============================================================================
|
2022-06-03 21:59:47 +01:00
|
|
|
*52.3* Autoloading without import/export
|
|
|
|
|
|
|
|
*write-library-script*
|
|
|
|
A mechanism from before import/export is still useful and some users may find
|
|
|
|
it a bit simpler. The idea is that you call a function with a special name.
|
|
|
|
That function is then in an autoload script. We will call that one script a
|
|
|
|
library script.
|
2020-06-14 17:29:55 +02:00
|
|
|
|
2022-06-03 21:59:47 +01:00
|
|
|
The autoload mechanism is based on a funtion name that has "#" characters: >
|
2020-06-14 17:29:55 +02:00
|
|
|
|
2022-06-03 21:59:47 +01:00
|
|
|
mylib#myfunction(arg)
|
|
|
|
|
|
|
|
Vim will recognize the function name by the embedded "#" character and when
|
|
|
|
it is not defined yet search for the script "autoload/mylib.vim" in
|
|
|
|
'runtimepath'. That script must define the "mylib#myfunction()" function.
|
|
|
|
Obviously the name "mylib" is the part before the "#" and is used as the name
|
|
|
|
of the script, adding ".vim".
|
|
|
|
|
|
|
|
You can put many other functions in the mylib.vim script, you are free to
|
|
|
|
organize your functions in library scripts. But you must use function names
|
|
|
|
where the part before the '#' matches the script name. Otherwise Vim would
|
|
|
|
not know what script to load. This is where it differs from the import/export
|
|
|
|
mechanism.
|
|
|
|
|
|
|
|
If you get really enthusiastic and write lots of library scripts, you may
|
|
|
|
want to use subdirectories. Example: >
|
|
|
|
|
|
|
|
netlib#ftp#read('somefile')
|
|
|
|
|
|
|
|
Here the script name is taken from the function name up to the last "#". The
|
|
|
|
"#" in the middle are replaced by a slash, the last one by ".vim". Thus you
|
|
|
|
get "netlib/ftp.vim". For Unix the library script used for this could be:
|
|
|
|
|
|
|
|
~/.vim/autoload/netlib/ftp.vim
|
|
|
|
|
|
|
|
Where the function is defined like this: >
|
|
|
|
|
|
|
|
def netlib#ftp#read(fname: string)
|
|
|
|
# Read the file fname through ftp
|
2020-06-14 17:29:55 +02:00
|
|
|
enddef
|
|
|
|
|
2022-06-03 21:59:47 +01:00
|
|
|
Notice that the name the function is defined with is exactly the same as the
|
|
|
|
name used for calling the function. And the part before the last '#'
|
|
|
|
exactly matches the subdirectory and script name.
|
|
|
|
|
|
|
|
You can use the same mechanism for variables: >
|
|
|
|
|
|
|
|
var weekdays = dutch#weekdays
|
|
|
|
|
|
|
|
This will load the script "autoload/dutch.vim", which should contain something
|
|
|
|
like: >
|
|
|
|
|
|
|
|
var dutch#weekdays = ['zondag', 'maandag', 'dinsdag', 'woensdag',
|
|
|
|
\ 'donderdag', 'vrijdag', 'zaterdag']
|
|
|
|
|
|
|
|
Further reading: |autoload|.
|
|
|
|
|
|
|
|
==============================================================================
|
|
|
|
*52.4* Other mechanisms to use
|
|
|
|
|
|
|
|
Some may find the use of several files a hassle and prefer to keep everything
|
|
|
|
together in one script. To avoid this resulting in slow startup there is a
|
|
|
|
mechanism that only defines a small part and postpones the rest to when it is
|
|
|
|
actually used. *write-plugin-quickload*
|
|
|
|
|
|
|
|
The basic idea is that the plugin is loaded twice. The first time user
|
|
|
|
commands and mappings are defined that offer the functionality. The second
|
|
|
|
time the functions that implement the functionality are defined.
|
|
|
|
|
|
|
|
It may sound surprising that quickload means loading a script twice. What we
|
|
|
|
mean is that it loads quickly the first time, postponing the bulk of the
|
|
|
|
script to the second time, which only happens when you actually use it. When
|
|
|
|
you always use the functionality it actually gets slower!
|
|
|
|
|
|
|
|
This uses a FuncUndefined autocommand. This works differently from the
|
|
|
|
|autoload| functionality explained above.
|
|
|
|
|
|
|
|
The following example shows how it's done: >
|
|
|
|
|
|
|
|
" Vim global plugin for demonstrating quick loading
|
|
|
|
" Last Change: 2005 Feb 25
|
|
|
|
" Maintainer: Bram Moolenaar <Bram@vim.org>
|
|
|
|
" License: This file is placed in the public domain.
|
|
|
|
|
|
|
|
if !exists("s:did_load")
|
|
|
|
command -nargs=* BNRead call BufNetRead(<f-args>)
|
|
|
|
map <F19> :call BufNetWrite('something')<CR>
|
|
|
|
|
|
|
|
let s:did_load = 1
|
|
|
|
exe 'au FuncUndefined BufNet* source ' .. expand('<sfile>')
|
|
|
|
finish
|
|
|
|
endif
|
|
|
|
|
|
|
|
function BufNetRead(...)
|
|
|
|
echo 'BufNetRead(' .. string(a:000) .. ')'
|
|
|
|
" read functionality here
|
|
|
|
endfunction
|
|
|
|
|
|
|
|
function BufNetWrite(...)
|
|
|
|
echo 'BufNetWrite(' .. string(a:000) .. ')'
|
|
|
|
" write functionality here
|
|
|
|
endfunction
|
|
|
|
|
|
|
|
When the script is first loaded "s:did_load" is not set. The commands between
|
|
|
|
the "if" and "endif" will be executed. This ends in a |:finish| command, thus
|
|
|
|
the rest of the script is not executed.
|
|
|
|
|
|
|
|
The second time the script is loaded "s:did_load" exists and the commands
|
|
|
|
after the "endif" are executed. This defines the (possible long)
|
|
|
|
BufNetRead() and BufNetWrite() functions.
|
|
|
|
|
|
|
|
If you drop this script in your plugin directory Vim will execute it on
|
|
|
|
startup. This is the sequence of events that happens:
|
|
|
|
|
|
|
|
1. The "BNRead" command is defined and the <F19> key is mapped when the script
|
|
|
|
is sourced at startup. A |FuncUndefined| autocommand is defined. The
|
|
|
|
":finish" command causes the script to terminate early.
|
|
|
|
|
|
|
|
2. The user types the BNRead command or presses the <F19> key. The
|
|
|
|
BufNetRead() or BufNetWrite() function will be called.
|
|
|
|
|
|
|
|
3. Vim can't find the function and triggers the |FuncUndefined| autocommand
|
|
|
|
event. Since the pattern "BufNet*" matches the invoked function, the
|
|
|
|
command "source fname" will be executed. "fname" will be equal to the name
|
|
|
|
of the script, no matter where it is located, because it comes from
|
|
|
|
expanding "<sfile>" (see |expand()|).
|
|
|
|
|
|
|
|
4. The script is sourced again, the "s:did_load" variable exists and the
|
|
|
|
functions are defined.
|
|
|
|
|
|
|
|
Notice that the functions that are loaded afterwards match the pattern in the
|
|
|
|
|FuncUndefined| autocommand. You must make sure that no other plugin defines
|
|
|
|
functions that match this pattern.
|
|
|
|
|
2020-06-14 17:29:55 +02:00
|
|
|
==============================================================================
|
2022-06-03 21:59:47 +01:00
|
|
|
*52.5* Using a Vim9 script from legacy script *source-vim9-script*
|
2020-06-14 17:29:55 +02:00
|
|
|
|
|
|
|
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
|
|
|
|
|
2022-06-03 21:59:47 +01:00
|
|
|
|
2020-06-14 17:29:55 +02:00
|
|
|
Copyright: see |manual-copyright| vim:tw=78:ts=8:noet:ft=help:norl:
|