blob: 4aae5fe02d0766e5bd5a60b1228dd16819db484b [file] [log] [blame]
Christian Brabandtb7258732024-05-12 19:04:47 +02001*usr_52.txt* For Vim version 9.1. Last change: 2024 May 05
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: >
Christian Brabandtb7258732024-05-12 19:04:47 +0200158 import autoload "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 Moolenaar3c053a12022-10-16 13:11:12 +0100162It will also search under 'packpath', under "start".
Bram Moolenaarcfa8f9a2022-06-03 21:59:47 +0100163
Bram Moolenaar016188f2022-06-06 20:52:59 +0100164The main advantage of this is that this script can be easily shared with other
Bram Moolenaarcfa8f9a2022-06-03 21:59:47 +0100165scripts. You do need to make sure that the script name is unique, since Vim
166will search all the "autoload" directories in 'runtimepath', and if you are
Bram Moolenaar016188f2022-06-06 20:52:59 +0100167using several plugins with a plugin manager, it may add a directory to
168'runtimepath', each of which might have an "autoload" directory.
169
170Without autoload: >
171 import "monthlib.vim"
172
173Vim will search for the script "monthlib.vim" in the import directories of
174'runtimepath'. Note that in this case adding or removing "autoload" changes
175where the script is found. With a relative or absolute path the location does
176not change.
Bram Moolenaarcfa8f9a2022-06-03 21:59:47 +0100177
178==============================================================================
179*52.3* Autoloading without import/export
180
181 *write-library-script*
182A mechanism from before import/export is still useful and some users may find
183it a bit simpler. The idea is that you call a function with a special name.
184That function is then in an autoload script. We will call that one script a
185library script.
186
Bram Moolenaard592deb2022-06-17 15:42:40 +0100187The autoload mechanism is based on a function name that has "#" characters: >
Bram Moolenaarcfa8f9a2022-06-03 21:59:47 +0100188
189 mylib#myfunction(arg)
190
191Vim will recognize the function name by the embedded "#" character and when
192it is not defined yet search for the script "autoload/mylib.vim" in
193'runtimepath'. That script must define the "mylib#myfunction()" function.
194Obviously the name "mylib" is the part before the "#" and is used as the name
195of the script, adding ".vim".
196
197You can put many other functions in the mylib.vim script, you are free to
198organize your functions in library scripts. But you must use function names
199where the part before the '#' matches the script name. Otherwise Vim would
200not know what script to load. This is where it differs from the import/export
201mechanism.
202
203If you get really enthusiastic and write lots of library scripts, you may
204want to use subdirectories. Example: >
205
206 netlib#ftp#read('somefile')
207
208Here the script name is taken from the function name up to the last "#". The
209"#" in the middle are replaced by a slash, the last one by ".vim". Thus you
210get "netlib/ftp.vim". For Unix the library script used for this could be:
211
212 ~/.vim/autoload/netlib/ftp.vim
213
214Where the function is defined like this: >
215
216 def netlib#ftp#read(fname: string)
217 # Read the file fname through ftp
218 enddef
219
220Notice that the name the function is defined with is exactly the same as the
221name used for calling the function. And the part before the last '#'
222exactly matches the subdirectory and script name.
223
224You can use the same mechanism for variables: >
225
226 var weekdays = dutch#weekdays
227
228This will load the script "autoload/dutch.vim", which should contain something
229like: >
230
231 var dutch#weekdays = ['zondag', 'maandag', 'dinsdag', 'woensdag',
232 \ 'donderdag', 'vrijdag', 'zaterdag']
233
234Further reading: |autoload|.
235
236==============================================================================
237*52.4* Other mechanisms to use
238
239Some may find the use of several files a hassle and prefer to keep everything
240together in one script. To avoid this resulting in slow startup there is a
241mechanism that only defines a small part and postpones the rest to when it is
242actually used. *write-plugin-quickload*
243
244The basic idea is that the plugin is loaded twice. The first time user
245commands and mappings are defined that offer the functionality. The second
246time the functions that implement the functionality are defined.
247
248It may sound surprising that quickload means loading a script twice. What we
249mean is that it loads quickly the first time, postponing the bulk of the
250script to the second time, which only happens when you actually use it. When
251you always use the functionality it actually gets slower!
252
253This uses a FuncUndefined autocommand. This works differently from the
254|autoload| functionality explained above.
255
256The following example shows how it's done: >
257
258 " Vim global plugin for demonstrating quick loading
259 " Last Change: 2005 Feb 25
260 " Maintainer: Bram Moolenaar <Bram@vim.org>
261 " License: This file is placed in the public domain.
262
263 if !exists("s:did_load")
264 command -nargs=* BNRead call BufNetRead(<f-args>)
265 map <F19> :call BufNetWrite('something')<CR>
266
267 let s:did_load = 1
268 exe 'au FuncUndefined BufNet* source ' .. expand('<sfile>')
269 finish
Bram Moolenaar65e0d772020-06-14 17:29:55 +0200270 endif
271
Bram Moolenaarcfa8f9a2022-06-03 21:59:47 +0100272 function BufNetRead(...)
273 echo 'BufNetRead(' .. string(a:000) .. ')'
274 " read functionality here
275 endfunction
276
277 function BufNetWrite(...)
278 echo 'BufNetWrite(' .. string(a:000) .. ')'
279 " write functionality here
280 endfunction
281
282When the script is first loaded "s:did_load" is not set. The commands between
283the "if" and "endif" will be executed. This ends in a |:finish| command, thus
284the rest of the script is not executed.
285
286The second time the script is loaded "s:did_load" exists and the commands
287after the "endif" are executed. This defines the (possible long)
288BufNetRead() and BufNetWrite() functions.
289
290If you drop this script in your plugin directory Vim will execute it on
291startup. This is the sequence of events that happens:
292
2931. The "BNRead" command is defined and the <F19> key is mapped when the script
294 is sourced at startup. A |FuncUndefined| autocommand is defined. The
295 ":finish" command causes the script to terminate early.
296
2972. The user types the BNRead command or presses the <F19> key. The
298 BufNetRead() or BufNetWrite() function will be called.
299
3003. Vim can't find the function and triggers the |FuncUndefined| autocommand
301 event. Since the pattern "BufNet*" matches the invoked function, the
302 command "source fname" will be executed. "fname" will be equal to the name
303 of the script, no matter where it is located, because it comes from
304 expanding "<sfile>" (see |expand()|).
305
3064. The script is sourced again, the "s:did_load" variable exists and the
307 functions are defined.
308
309Notice that the functions that are loaded afterwards match the pattern in the
310|FuncUndefined| autocommand. You must make sure that no other plugin defines
311functions that match this pattern.
Bram Moolenaar65e0d772020-06-14 17:29:55 +0200312
313==============================================================================
Bram Moolenaarcfa8f9a2022-06-03 21:59:47 +0100314*52.5* Using a Vim9 script from legacy script *source-vim9-script*
Bram Moolenaar65e0d772020-06-14 17:29:55 +0200315
316In some cases you have a legacy Vim script where you want to use items from a
317Vim9 script. For example in your .vimrc you want to initialize a plugin. The
318best way to do this is to use `:import`. For example: >
319
Bram Moolenaar016188f2022-06-06 20:52:59 +0100320 import 'myNicePlugin.vim'
321 call myNicePlugin.NiceInit('today')
Bram Moolenaar65e0d772020-06-14 17:29:55 +0200322
Bram Moolenaar016188f2022-06-06 20:52:59 +0100323This finds the exported function "NiceInit" in the Vim9 script file and makes
324it available as script-local item "myNicePlugin.NiceInit". `:import` always
325uses the script namespace, even when "s:" is not given. If "myNicePlugin.vim"
326was already sourced it is not sourced again.
Bram Moolenaar65e0d772020-06-14 17:29:55 +0200327
328Besides avoiding putting any items in the global namespace (where name clashes
329can cause unexpected errors), this also means the script is sourced only once,
330no matter how many times items from it are imported.
331
332In some cases, e.g. for testing, you may just want to source the Vim9 script.
333That is OK, but then only global items will be available. The Vim9 script
334will have to make sure to use a unique name for these global items. Example: >
335 source ~/.vim/extra/myNicePlugin.vim
336 call g:NicePluginTest()
337
338==============================================================================
339
340Next chapter: |usr_90.txt| Installing Vim
341
Bram Moolenaarcfa8f9a2022-06-03 21:59:47 +0100342
Bram Moolenaar65e0d772020-06-14 17:29:55 +0200343Copyright: see |manual-copyright| vim:tw=78:ts=8:noet:ft=help:norl: