blob: 2c3e13be360657f708b7f3c31668b6da25730875 [file] [log] [blame]
Bram Moolenaar016188f2022-06-06 20:52:59 +01001*usr_52.txt* For Vim version 8.2. Last change: 2022 Jun 04
Bram Moolenaar65e0d772020-06-14 17:29:55 +02002
3 VIM USER MANUAL - by Bram Moolenaar
4
Bram Moolenaarcfa8f9a2022-06-03 21:59:47 +01005 Write larger plugins
Bram Moolenaar65e0d772020-06-14 17:29:55 +02006
Bram Moolenaarcfa8f9a2022-06-03 21:59:47 +01007When plugins do more than simple things, they tend to grow big. This file
8explains how to make sure they still load fast and how to split them up in
Bram Moolenaar016188f2022-06-06 20:52:59 +01009smaller parts.
Bram Moolenaar65e0d772020-06-14 17:29:55 +020010
Bram Moolenaarcfa8f9a2022-06-03 21:59:47 +010011|52.1| Export and import
12|52.2| Autoloading
13|52.3| Autoloading without import/export
14|52.4| Other mechanisms to use
15|52.5| Using a Vim9 script from legacy script
Bram Moolenaar65e0d772020-06-14 17:29:55 +020016
17 Next chapter: |usr_90.txt| Installing Vim
Bram Moolenaar30ab04e2022-05-14 13:33:50 +010018 Previous chapter: |usr_51.txt| Create a plugin
Bram Moolenaar65e0d772020-06-14 17:29:55 +020019Table of contents: |usr_toc.txt|
20
21==============================================================================
Bram Moolenaarcfa8f9a2022-06-03 21:59:47 +010022*52.1* Export and import
Bram Moolenaar65e0d772020-06-14 17:29:55 +020023
24Vim9 script was designed to make it easier to write large Vim scripts. It
25looks more like other script languages, especially Typescript. Also,
26functions are compiled into instructions that can be executed quickly. This
27makes Vim9 script a lot faster, up to a 100 times.
28
29The basic idea is that a script file has items that are private, only used
Bram Moolenaar016188f2022-06-06 20:52:59 +010030inside the script file, and items that are exported, which can be used by
31scripts that import them. That makes very clear what is defined where.
Bram Moolenaar65e0d772020-06-14 17:29:55 +020032
33Let's start with an example, a script that exports one function and has one
34private function: >
35
Bram Moolenaar016188f2022-06-06 20:52:59 +010036 vim9script
Bram Moolenaar65e0d772020-06-14 17:29:55 +020037
Bram Moolenaar016188f2022-06-06 20:52:59 +010038 export def GetMessage(count: string): string
39 var nr = str2nr(count)
40 var result = $'To {nr} we say '
41 result ..= GetReply(nr)
Bram Moolenaar65e0d772020-06-14 17:29:55 +020042 return result
43 enddef
44
Bram Moolenaar016188f2022-06-06 20:52:59 +010045 def GetReply(nr: number): string
46 if nr == 42
Bram Moolenaar65e0d772020-06-14 17:29:55 +020047 return 'yes'
Bram Moolenaar016188f2022-06-06 20:52:59 +010048 elseif nr = 22
49 return 'maybe'
Bram Moolenaar65e0d772020-06-14 17:29:55 +020050 else
51 return 'no'
52 endif
53 enddef
54
Bram Moolenaar016188f2022-06-06 20:52:59 +010055The `vim9script` command is required, `export` only works in a |Vim9| script.
Bram Moolenaar65e0d772020-06-14 17:29:55 +020056
Bram Moolenaar016188f2022-06-06 20:52:59 +010057The `export def GetMessage(...` line starts with `export`, meaning that this
58function can be called by other scripts. The line `def GetReply(...` does not
59start with `export`, this is a script-local function, it can only be used
60inside this script file.
Bram Moolenaar65e0d772020-06-14 17:29:55 +020061
Bram Moolenaar016188f2022-06-06 20:52:59 +010062Now about the script where this is imported. In this example we use this
63layout, which works well for a plugin below the "pack" directory:
64 .../plugin/theplugin.vim
65 .../lib/getmessage.vim
Bram Moolenaar65e0d772020-06-14 17:29:55 +020066
Bram Moolenaar016188f2022-06-06 20:52:59 +010067Assuming the "..." directory has been added to 'runtimepath', Vim will look
68for plugins in the "plugin" directory and source "theplugin.vim". Vim does
69not recognize the "lib" directory, you can put any scripts there.
70
71The above script that exports GetMessage() goes in lib/getmessage.vim. The
72GetMessage() function is used in plugin/theplugin.vim: >
73
74 vim9script
75
76 import "../lib/getmessage.vim"
77 command -nargs=1 ShowMessage echomsg getmessage.GetMessage(<f-args>)
78
79The `import` command uses a relative path, it starts with "../", which means
80to go one directory up. For other kinds of paths see the `:import` command.
81
82How we can try out the command that the plugin provides: >
83 ShowMessage 1
84< To 1 we say no ~
85>
86 ShowMessage 22
87< To 22 we say maybe ~
88
89Notice that the function GetMessage() is prefixed with the imported script
90name "getmessage". That way, for every imported function used, you know what
91script it was imported from. If you import several scripts each of them could
92define a GetMessage() function: >
93
94 vim9script
95
96 import "../lib/getmessage.vim"
97 import "../lib/getother.vim"
98 command -nargs=1 ShowMessage echomsg getmessage.GetMessage(<f-args>)
99 command -nargs=1 ShowOther echomsg getother.GetMessage(<f-args>)
100
101If the imported script name is long or you use it in many places, you can
102shorten it by adding an "as" argument: >
103 import "../lib/getmessage.vim" as msg
104 command -nargs=1 ShowMessage echomsg msg.GetMessage(<f-args>)
105
106
107RELOADING
108
109One thing to keep in mind: the imported "lib/getmessage.vim" script will be
110sourced only once. When it is imported a second time sourcing it will be
111skipped, since the items in it have already been created. It does not matter
112if this import command is in another script, or in the same script that is
113sourced again.
114
115This is efficient when using a plugin, but when still developing a plugin it
116means that changing "lib/getmessage.vim" after it has been imported will have
117no effect. You need to quit Vim and start it again. (Rationale: the items
118defined in the script could be used in a compiled function, sourcing the
119script again may break those functions).
120
Bram Moolenaarcfa8f9a2022-06-03 21:59:47 +0100121
122USING GLOBALS
123
124Sometimes you will want to use global variables or functions, so that they can
125be used anywhere. A good example is a global variable that passes a
126preference to a plugin. To avoid other scripts using the same name, use a
127prefix that is very unlikely to be used elsewhere. For example, if you have a
128"mytags" plugin, you could use: >
129
130 g:mytags_location = '$HOME/project'
131 g:mytags_style = 'fast'
Bram Moolenaar65e0d772020-06-14 17:29:55 +0200132
133==============================================================================
Bram Moolenaarcfa8f9a2022-06-03 21:59:47 +0100134*52.2* Autoloading
Bram Moolenaar65e0d772020-06-14 17:29:55 +0200135
Bram Moolenaarcfa8f9a2022-06-03 21:59:47 +0100136After splitting your large script into pieces, all the lines will still be
137loaded and executed the moment the script is used. Every `import` loads the
138imported script to find the items defined there. Although that is good for
139finding errors early, it also takes time. Which is wasted if the
140functionality is not often used.
Bram Moolenaar65e0d772020-06-14 17:29:55 +0200141
Bram Moolenaarcfa8f9a2022-06-03 21:59:47 +0100142Instead of having `import` load the script immediately, it can be postponed
Bram Moolenaar016188f2022-06-06 20:52:59 +0100143until needed. Using the example above, only one change needs to be made in
144the plugin/theplugin.vim script: >
145 import autoload "../lib/getmessage.vim"
Bram Moolenaar65e0d772020-06-14 17:29:55 +0200146
Bram Moolenaar016188f2022-06-06 20:52:59 +0100147Nothing in the rest of the script needs to change. However, the types will
148not be checked. Not even the existence of the GetMessage() function is
149checked until it is used. You will have to decide what is more important for
150your script: fast startup or getting errors early. You can also add the
151"autoload" argument later, after you have checked everything works.
Bram Moolenaar65e0d772020-06-14 17:29:55 +0200152
Bram Moolenaar016188f2022-06-06 20:52:59 +0100153
154AUTOLOAD DIRECTORY
155
156Another form is to use autoload with a script name that is not an absolute or
157relative path: >
Bram Moolenaarcfa8f9a2022-06-03 21:59:47 +0100158 import autload "monthlib.vim"
Bram Moolenaar65e0d772020-06-14 17:29:55 +0200159
Bram Moolenaarcfa8f9a2022-06-03 21:59:47 +0100160This will search for the script "monthlib.vim" in the autoload directories of
Bram Moolenaar016188f2022-06-06 20:52:59 +0100161'runtimepath'. With Unix one of the directories often is "~/.vim/autoload".
Bram Moolenaarcfa8f9a2022-06-03 21:59:47 +0100162
Bram Moolenaar016188f2022-06-06 20:52:59 +0100163The main advantage of this is that this script can be easily shared with other
Bram Moolenaarcfa8f9a2022-06-03 21:59:47 +0100164scripts. You do need to make sure that the script name is unique, since Vim
165will search all the "autoload" directories in 'runtimepath', and if you are
Bram Moolenaar016188f2022-06-06 20:52:59 +0100166using several plugins with a plugin manager, it may add a directory to
167'runtimepath', each of which might have an "autoload" directory.
168
169Without autoload: >
170 import "monthlib.vim"
171
172Vim will search for the script "monthlib.vim" in the import directories of
173'runtimepath'. Note that in this case adding or removing "autoload" changes
174where the script is found. With a relative or absolute path the location does
175not change.
Bram Moolenaarcfa8f9a2022-06-03 21:59:47 +0100176
177==============================================================================
178*52.3* Autoloading without import/export
179
180 *write-library-script*
181A mechanism from before import/export is still useful and some users may find
182it a bit simpler. The idea is that you call a function with a special name.
183That function is then in an autoload script. We will call that one script a
184library script.
185
186The autoload mechanism is based on a funtion name that has "#" characters: >
187
188 mylib#myfunction(arg)
189
190Vim will recognize the function name by the embedded "#" character and when
191it is not defined yet search for the script "autoload/mylib.vim" in
192'runtimepath'. That script must define the "mylib#myfunction()" function.
193Obviously the name "mylib" is the part before the "#" and is used as the name
194of the script, adding ".vim".
195
196You can put many other functions in the mylib.vim script, you are free to
197organize your functions in library scripts. But you must use function names
198where the part before the '#' matches the script name. Otherwise Vim would
199not know what script to load. This is where it differs from the import/export
200mechanism.
201
202If you get really enthusiastic and write lots of library scripts, you may
203want to use subdirectories. Example: >
204
205 netlib#ftp#read('somefile')
206
207Here the script name is taken from the function name up to the last "#". The
208"#" in the middle are replaced by a slash, the last one by ".vim". Thus you
209get "netlib/ftp.vim". For Unix the library script used for this could be:
210
211 ~/.vim/autoload/netlib/ftp.vim
212
213Where the function is defined like this: >
214
215 def netlib#ftp#read(fname: string)
216 # Read the file fname through ftp
217 enddef
218
219Notice that the name the function is defined with is exactly the same as the
220name used for calling the function. And the part before the last '#'
221exactly matches the subdirectory and script name.
222
223You can use the same mechanism for variables: >
224
225 var weekdays = dutch#weekdays
226
227This will load the script "autoload/dutch.vim", which should contain something
228like: >
229
230 var dutch#weekdays = ['zondag', 'maandag', 'dinsdag', 'woensdag',
231 \ 'donderdag', 'vrijdag', 'zaterdag']
232
233Further reading: |autoload|.
234
235==============================================================================
236*52.4* Other mechanisms to use
237
238Some may find the use of several files a hassle and prefer to keep everything
239together in one script. To avoid this resulting in slow startup there is a
240mechanism that only defines a small part and postpones the rest to when it is
241actually used. *write-plugin-quickload*
242
243The basic idea is that the plugin is loaded twice. The first time user
244commands and mappings are defined that offer the functionality. The second
245time the functions that implement the functionality are defined.
246
247It may sound surprising that quickload means loading a script twice. What we
248mean is that it loads quickly the first time, postponing the bulk of the
249script to the second time, which only happens when you actually use it. When
250you always use the functionality it actually gets slower!
251
252This uses a FuncUndefined autocommand. This works differently from the
253|autoload| functionality explained above.
254
255The following example shows how it's done: >
256
257 " Vim global plugin for demonstrating quick loading
258 " Last Change: 2005 Feb 25
259 " Maintainer: Bram Moolenaar <Bram@vim.org>
260 " License: This file is placed in the public domain.
261
262 if !exists("s:did_load")
263 command -nargs=* BNRead call BufNetRead(<f-args>)
264 map <F19> :call BufNetWrite('something')<CR>
265
266 let s:did_load = 1
267 exe 'au FuncUndefined BufNet* source ' .. expand('<sfile>')
268 finish
Bram Moolenaar65e0d772020-06-14 17:29:55 +0200269 endif
270
Bram Moolenaarcfa8f9a2022-06-03 21:59:47 +0100271 function BufNetRead(...)
272 echo 'BufNetRead(' .. string(a:000) .. ')'
273 " read functionality here
274 endfunction
275
276 function BufNetWrite(...)
277 echo 'BufNetWrite(' .. string(a:000) .. ')'
278 " write functionality here
279 endfunction
280
281When the script is first loaded "s:did_load" is not set. The commands between
282the "if" and "endif" will be executed. This ends in a |:finish| command, thus
283the rest of the script is not executed.
284
285The second time the script is loaded "s:did_load" exists and the commands
286after the "endif" are executed. This defines the (possible long)
287BufNetRead() and BufNetWrite() functions.
288
289If you drop this script in your plugin directory Vim will execute it on
290startup. This is the sequence of events that happens:
291
2921. The "BNRead" command is defined and the <F19> key is mapped when the script
293 is sourced at startup. A |FuncUndefined| autocommand is defined. The
294 ":finish" command causes the script to terminate early.
295
2962. The user types the BNRead command or presses the <F19> key. The
297 BufNetRead() or BufNetWrite() function will be called.
298
2993. Vim can't find the function and triggers the |FuncUndefined| autocommand
300 event. Since the pattern "BufNet*" matches the invoked function, the
301 command "source fname" will be executed. "fname" will be equal to the name
302 of the script, no matter where it is located, because it comes from
303 expanding "<sfile>" (see |expand()|).
304
3054. The script is sourced again, the "s:did_load" variable exists and the
306 functions are defined.
307
308Notice that the functions that are loaded afterwards match the pattern in the
309|FuncUndefined| autocommand. You must make sure that no other plugin defines
310functions that match this pattern.
Bram Moolenaar65e0d772020-06-14 17:29:55 +0200311
312==============================================================================
Bram Moolenaarcfa8f9a2022-06-03 21:59:47 +0100313*52.5* Using a Vim9 script from legacy script *source-vim9-script*
Bram Moolenaar65e0d772020-06-14 17:29:55 +0200314
315In some cases you have a legacy Vim script where you want to use items from a
316Vim9 script. For example in your .vimrc you want to initialize a plugin. The
317best way to do this is to use `:import`. For example: >
318
Bram Moolenaar016188f2022-06-06 20:52:59 +0100319 import 'myNicePlugin.vim'
320 call myNicePlugin.NiceInit('today')
Bram Moolenaar65e0d772020-06-14 17:29:55 +0200321
Bram Moolenaar016188f2022-06-06 20:52:59 +0100322This finds the exported function "NiceInit" in the Vim9 script file and makes
323it available as script-local item "myNicePlugin.NiceInit". `:import` always
324uses the script namespace, even when "s:" is not given. If "myNicePlugin.vim"
325was already sourced it is not sourced again.
Bram Moolenaar65e0d772020-06-14 17:29:55 +0200326
327Besides avoiding putting any items in the global namespace (where name clashes
328can cause unexpected errors), this also means the script is sourced only once,
329no matter how many times items from it are imported.
330
331In some cases, e.g. for testing, you may just want to source the Vim9 script.
332That is OK, but then only global items will be available. The Vim9 script
333will have to make sure to use a unique name for these global items. Example: >
334 source ~/.vim/extra/myNicePlugin.vim
335 call g:NicePluginTest()
336
337==============================================================================
338
339Next chapter: |usr_90.txt| Installing Vim
340
Bram Moolenaarcfa8f9a2022-06-03 21:59:47 +0100341
Bram Moolenaar65e0d772020-06-14 17:29:55 +0200342Copyright: see |manual-copyright| vim:tw=78:ts=8:noet:ft=help:norl: