diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 08:50:31 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 08:50:31 +0000 |
commit | aed8ce9da277f5ecffe968b324f242c41c3b752a (patch) | |
tree | d2e538394cb7a8a7c42a4aac6ccf1a8e3256999b /runtime/doc/usr_52.txt | |
parent | Initial commit. (diff) | |
download | vim-aed8ce9da277f5ecffe968b324f242c41c3b752a.tar.xz vim-aed8ce9da277f5ecffe968b324f242c41c3b752a.zip |
Adding upstream version 2:9.0.1378.upstream/2%9.0.1378upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'runtime/doc/usr_52.txt')
-rw-r--r-- | runtime/doc/usr_52.txt | 343 |
1 files changed, 343 insertions, 0 deletions
diff --git a/runtime/doc/usr_52.txt b/runtime/doc/usr_52.txt new file mode 100644 index 0000000..787dd91 --- /dev/null +++ b/runtime/doc/usr_52.txt @@ -0,0 +1,343 @@ +*usr_52.txt* For Vim version 9.0. Last change: 2022 Jun 04 + + VIM USER MANUAL - by Bram Moolenaar + + Write larger plugins + +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. + +|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 + + Next chapter: |usr_90.txt| Installing Vim + Previous chapter: |usr_51.txt| Create a plugin +Table of contents: |usr_toc.txt| + +============================================================================== +*52.1* Export and import + +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, which can 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 + + export def GetMessage(count: string): string + var nr = str2nr(count) + var result = $'To {nr} we say ' + result ..= GetReply(nr) + return result + enddef + + def GetReply(nr: number): string + if nr == 42 + return 'yes' + elseif nr = 22 + return 'maybe' + else + return 'no' + endif + enddef + +The `vim9script` command is required, `export` only works in a |Vim9| script. + +The `export def GetMessage(...` line starts with `export`, meaning that this +function can be called by other scripts. The line `def GetReply(...` does not +start with `export`, this is a script-local function, it can only be used +inside this script file. + +Now about the script where this is imported. In this example we use this +layout, which works well for a plugin below the "pack" directory: + .../plugin/theplugin.vim + .../lib/getmessage.vim + +Assuming the "..." directory has been added to 'runtimepath', Vim will look +for plugins in the "plugin" directory and source "theplugin.vim". Vim does +not recognize the "lib" directory, you can put any scripts there. + +The above script that exports GetMessage() goes in lib/getmessage.vim. The +GetMessage() function is used in plugin/theplugin.vim: > + + vim9script + + import "../lib/getmessage.vim" + command -nargs=1 ShowMessage echomsg getmessage.GetMessage(<f-args>) + +The `import` command uses a relative path, it starts with "../", which means +to go one directory up. For other kinds of paths see the `:import` command. + +How we can try out the command that the plugin provides: > + ShowMessage 1 +< To 1 we say no ~ +> + ShowMessage 22 +< To 22 we say maybe ~ + +Notice that the function GetMessage() is prefixed with the imported script +name "getmessage". That way, for every imported function used, you know what +script it was imported from. If you import several scripts each of them could +define a GetMessage() function: > + + vim9script + + import "../lib/getmessage.vim" + import "../lib/getother.vim" + command -nargs=1 ShowMessage echomsg getmessage.GetMessage(<f-args>) + command -nargs=1 ShowOther echomsg getother.GetMessage(<f-args>) + +If the imported script name is long or you use it in many places, you can +shorten it by adding an "as" argument: > + import "../lib/getmessage.vim" as msg + command -nargs=1 ShowMessage echomsg msg.GetMessage(<f-args>) + + +RELOADING + +One thing to keep in mind: the imported "lib/getmessage.vim" script will be +sourced only once. When it is imported a second time sourcing it will be +skipped, since the items in it have already been created. It does not matter +if this import command is in another script, or in the same script that is +sourced again. + +This is efficient when using a plugin, but when still developing a plugin it +means that changing "lib/getmessage.vim" after it has been imported will have +no effect. You need to quit Vim and start it again. (Rationale: the items +defined in the script could be used in a compiled function, sourcing the +script again may break those functions). + + +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' + +============================================================================== +*52.2* Autoloading + +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. Using the example above, only one change needs to be made in +the plugin/theplugin.vim script: > + import autoload "../lib/getmessage.vim" + +Nothing in the rest of the script needs to change. However, the types will +not be checked. Not even the existence of the GetMessage() function is +checked until it is used. You will have to decide what is more important for +your script: fast startup or getting errors early. You can also add the +"autoload" argument later, after you have checked everything works. + + +AUTOLOAD DIRECTORY + +Another form is to use autoload with 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 one of the directories often is "~/.vim/autoload". +It will also search under 'packpath', under "start". + +The main advantage of this is that this script can be easily 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 with a plugin manager, it may add a directory to +'runtimepath', each of which might have an "autoload" directory. + +Without autoload: > + import "monthlib.vim" + +Vim will search for the script "monthlib.vim" in the import directories of +'runtimepath'. Note that in this case adding or removing "autoload" changes +where the script is found. With a relative or absolute path the location does +not change. + +============================================================================== +*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. + +The autoload mechanism is based on a function name that has "#" characters: > + + 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 + enddef + +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. + +============================================================================== +*52.5* 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 'myNicePlugin.vim' + call myNicePlugin.NiceInit('today') + +This finds the exported function "NiceInit" in the Vim9 script file and makes +it available as script-local item "myNicePlugin.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: |