blob: 0461d8ec63b4085ec012230f221487efbc393ea8 [file] [log] [blame]
Bram Moolenaarcfa8f9a2022-06-03 21:59:47 +01001*usr_52.txt* For Vim version 8.2. Last change: 2022 Jun 03
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 +01007TODO: this file needs to be updated
Bram Moolenaar65e0d772020-06-14 17:29:55 +02008
Bram Moolenaarcfa8f9a2022-06-03 21:59:47 +01009When plugins do more than simple things, they tend to grow big. This file
10explains how to make sure they still load fast and how to split them up in
11smaller parts
Bram Moolenaar65e0d772020-06-14 17:29:55 +020012
Bram Moolenaarcfa8f9a2022-06-03 21:59:47 +010013|52.1| Export and import
14|52.2| Autoloading
15|52.3| Autoloading without import/export
16|52.4| Other mechanisms to use
17|52.5| Using a Vim9 script from legacy script
Bram Moolenaar65e0d772020-06-14 17:29:55 +020018
19 Next chapter: |usr_90.txt| Installing Vim
Bram Moolenaar30ab04e2022-05-14 13:33:50 +010020 Previous chapter: |usr_51.txt| Create a plugin
Bram Moolenaar65e0d772020-06-14 17:29:55 +020021Table of contents: |usr_toc.txt|
22
23==============================================================================
Bram Moolenaarcfa8f9a2022-06-03 21:59:47 +010024*52.1* Export and import
Bram Moolenaar65e0d772020-06-14 17:29:55 +020025
26Vim9 script was designed to make it easier to write large Vim scripts. It
27looks more like other script languages, especially Typescript. Also,
28functions are compiled into instructions that can be executed quickly. This
29makes Vim9 script a lot faster, up to a 100 times.
30
31The basic idea is that a script file has items that are private, only used
32inside the script file, and items that are exported, used outside of the
33script file. The exported items can then be used by scripts that import them.
34That makes very clear what is defined where.
35
36Let's start with an example, a script that exports one function and has one
37private function: >
38
Bram Moolenaare7b1ea02020-08-07 19:54:59 +020039 vim9script " This indicates a Vim9 script file.
Bram Moolenaar65e0d772020-06-14 17:29:55 +020040
41 export def GetMessage(): string
42 let result = ''
43 ...
44 result = GetPart(count)
45 ...
46 return result
47 enddef
48
49 def GetPart(nr: number): string
50 if nr == 4
51 return 'yes'
52 else
53 return 'no'
54 endif
55 enddef
56
57The `vim9script` command must be the very first command in the file. Without
58it Vim will assume legacy script syntax.
59
60The `export def GetMessage(): string` line starts with `export`, meaning that
61this function can be imported and called by other scripts. The line
62`def GetPart(...` does not start with `export`, this is a script-local
63function, it can only be used inside this script file.
64
65In the `export def GetMessage(): string` line you will notice the colon and
66the return type. Vim9 functions, defined with `def`, require specifying the
67type of arguments and the return type. That way Vim can compile the code
68efficiently. The GetPart function defines an argument "nr" of type "number".
69
Bram Moolenaarcfa8f9a2022-06-03 21:59:47 +010070TODO: import/export example
71
72USING GLOBALS
73
74Sometimes you will want to use global variables or functions, so that they can
75be used anywhere. A good example is a global variable that passes a
76preference to a plugin. To avoid other scripts using the same name, use a
77prefix that is very unlikely to be used elsewhere. For example, if you have a
78"mytags" plugin, you could use: >
79
80 g:mytags_location = '$HOME/project'
81 g:mytags_style = 'fast'
Bram Moolenaar65e0d772020-06-14 17:29:55 +020082
83==============================================================================
Bram Moolenaarcfa8f9a2022-06-03 21:59:47 +010084*52.2* Autoloading
Bram Moolenaar65e0d772020-06-14 17:29:55 +020085
Bram Moolenaarcfa8f9a2022-06-03 21:59:47 +010086TODO: autoloading with import/export
Bram Moolenaar65e0d772020-06-14 17:29:55 +020087
Bram Moolenaarcfa8f9a2022-06-03 21:59:47 +010088After splitting your large script into pieces, all the lines will still be
89loaded and executed the moment the script is used. Every `import` loads the
90imported script to find the items defined there. Although that is good for
91finding errors early, it also takes time. Which is wasted if the
92functionality is not often used.
Bram Moolenaar65e0d772020-06-14 17:29:55 +020093
Bram Moolenaarcfa8f9a2022-06-03 21:59:47 +010094Instead of having `import` load the script immediately, it can be postponed
95until needed. >
96 import autoload "./LoadLater.vim"
Bram Moolenaar65e0d772020-06-14 17:29:55 +020097
Bram Moolenaarcfa8f9a2022-06-03 21:59:47 +010098Now you can use exported items as usual: "LoadLater.GetMonth(4)".
99However, the type will not be checked. Not even the existence of the
100GetMonth() function is checked until it is used. You will have to decide what
101is more important for your script. You can also add the "autoload" argument
102later, after you have checked everything works.
Bram Moolenaar65e0d772020-06-14 17:29:55 +0200103
Bram Moolenaarcfa8f9a2022-06-03 21:59:47 +0100104Another form is to use a script name that is not an absolute or relative
105path: >
106 import autload "monthlib.vim"
Bram Moolenaar65e0d772020-06-14 17:29:55 +0200107
Bram Moolenaarcfa8f9a2022-06-03 21:59:47 +0100108This will search for the script "monthlib.vim" in the autoload directories of
109'runtimepath'. With Unix the directory often is "~/.vim/autoload".
110
111The main advantage of this is that this script can be shared with other
112scripts. You do need to make sure that the script name is unique, since Vim
113will search all the "autoload" directories in 'runtimepath', and if you are
114using several plugins, these may add several directories to 'runtimepath',
115each of which might have an "autoload" directory.
116
117==============================================================================
118*52.3* Autoloading without import/export
119
120 *write-library-script*
121A mechanism from before import/export is still useful and some users may find
122it a bit simpler. The idea is that you call a function with a special name.
123That function is then in an autoload script. We will call that one script a
124library script.
125
126The autoload mechanism is based on a funtion name that has "#" characters: >
127
128 mylib#myfunction(arg)
129
130Vim will recognize the function name by the embedded "#" character and when
131it is not defined yet search for the script "autoload/mylib.vim" in
132'runtimepath'. That script must define the "mylib#myfunction()" function.
133Obviously the name "mylib" is the part before the "#" and is used as the name
134of the script, adding ".vim".
135
136You can put many other functions in the mylib.vim script, you are free to
137organize your functions in library scripts. But you must use function names
138where the part before the '#' matches the script name. Otherwise Vim would
139not know what script to load. This is where it differs from the import/export
140mechanism.
141
142If you get really enthusiastic and write lots of library scripts, you may
143want to use subdirectories. Example: >
144
145 netlib#ftp#read('somefile')
146
147Here the script name is taken from the function name up to the last "#". The
148"#" in the middle are replaced by a slash, the last one by ".vim". Thus you
149get "netlib/ftp.vim". For Unix the library script used for this could be:
150
151 ~/.vim/autoload/netlib/ftp.vim
152
153Where the function is defined like this: >
154
155 def netlib#ftp#read(fname: string)
156 # Read the file fname through ftp
157 enddef
158
159Notice that the name the function is defined with is exactly the same as the
160name used for calling the function. And the part before the last '#'
161exactly matches the subdirectory and script name.
162
163You can use the same mechanism for variables: >
164
165 var weekdays = dutch#weekdays
166
167This will load the script "autoload/dutch.vim", which should contain something
168like: >
169
170 var dutch#weekdays = ['zondag', 'maandag', 'dinsdag', 'woensdag',
171 \ 'donderdag', 'vrijdag', 'zaterdag']
172
173Further reading: |autoload|.
174
175==============================================================================
176*52.4* Other mechanisms to use
177
178Some may find the use of several files a hassle and prefer to keep everything
179together in one script. To avoid this resulting in slow startup there is a
180mechanism that only defines a small part and postpones the rest to when it is
181actually used. *write-plugin-quickload*
182
183The basic idea is that the plugin is loaded twice. The first time user
184commands and mappings are defined that offer the functionality. The second
185time the functions that implement the functionality are defined.
186
187It may sound surprising that quickload means loading a script twice. What we
188mean is that it loads quickly the first time, postponing the bulk of the
189script to the second time, which only happens when you actually use it. When
190you always use the functionality it actually gets slower!
191
192This uses a FuncUndefined autocommand. This works differently from the
193|autoload| functionality explained above.
194
195The following example shows how it's done: >
196
197 " Vim global plugin for demonstrating quick loading
198 " Last Change: 2005 Feb 25
199 " Maintainer: Bram Moolenaar <Bram@vim.org>
200 " License: This file is placed in the public domain.
201
202 if !exists("s:did_load")
203 command -nargs=* BNRead call BufNetRead(<f-args>)
204 map <F19> :call BufNetWrite('something')<CR>
205
206 let s:did_load = 1
207 exe 'au FuncUndefined BufNet* source ' .. expand('<sfile>')
208 finish
Bram Moolenaar65e0d772020-06-14 17:29:55 +0200209 endif
210
Bram Moolenaarcfa8f9a2022-06-03 21:59:47 +0100211 function BufNetRead(...)
212 echo 'BufNetRead(' .. string(a:000) .. ')'
213 " read functionality here
214 endfunction
215
216 function BufNetWrite(...)
217 echo 'BufNetWrite(' .. string(a:000) .. ')'
218 " write functionality here
219 endfunction
220
221When the script is first loaded "s:did_load" is not set. The commands between
222the "if" and "endif" will be executed. This ends in a |:finish| command, thus
223the rest of the script is not executed.
224
225The second time the script is loaded "s:did_load" exists and the commands
226after the "endif" are executed. This defines the (possible long)
227BufNetRead() and BufNetWrite() functions.
228
229If you drop this script in your plugin directory Vim will execute it on
230startup. This is the sequence of events that happens:
231
2321. The "BNRead" command is defined and the <F19> key is mapped when the script
233 is sourced at startup. A |FuncUndefined| autocommand is defined. The
234 ":finish" command causes the script to terminate early.
235
2362. The user types the BNRead command or presses the <F19> key. The
237 BufNetRead() or BufNetWrite() function will be called.
238
2393. Vim can't find the function and triggers the |FuncUndefined| autocommand
240 event. Since the pattern "BufNet*" matches the invoked function, the
241 command "source fname" will be executed. "fname" will be equal to the name
242 of the script, no matter where it is located, because it comes from
243 expanding "<sfile>" (see |expand()|).
244
2454. The script is sourced again, the "s:did_load" variable exists and the
246 functions are defined.
247
248Notice that the functions that are loaded afterwards match the pattern in the
249|FuncUndefined| autocommand. You must make sure that no other plugin defines
250functions that match this pattern.
Bram Moolenaar65e0d772020-06-14 17:29:55 +0200251
252==============================================================================
Bram Moolenaarcfa8f9a2022-06-03 21:59:47 +0100253*52.5* Using a Vim9 script from legacy script *source-vim9-script*
Bram Moolenaar65e0d772020-06-14 17:29:55 +0200254
255In some cases you have a legacy Vim script where you want to use items from a
256Vim9 script. For example in your .vimrc you want to initialize a plugin. The
257best way to do this is to use `:import`. For example: >
258
259 import Init as NiceInit from 'myNicePlugin.vim'
260 call NiceInit('today')
261
262This finds the exported function "Init" in the Vim9 script file and makes it
263available as script-local item "NiceInit". `:import` always uses the script
264namespace, even when "s:" is not given. If "myNicePlugin.vim" was already
265sourced it is not sourced again.
266
267Besides avoiding putting any items in the global namespace (where name clashes
268can cause unexpected errors), this also means the script is sourced only once,
269no matter how many times items from it are imported.
270
271In some cases, e.g. for testing, you may just want to source the Vim9 script.
272That is OK, but then only global items will be available. The Vim9 script
273will have to make sure to use a unique name for these global items. Example: >
274 source ~/.vim/extra/myNicePlugin.vim
275 call g:NicePluginTest()
276
277==============================================================================
278
279Next chapter: |usr_90.txt| Installing Vim
280
Bram Moolenaarcfa8f9a2022-06-03 21:59:47 +0100281
Bram Moolenaar65e0d772020-06-14 17:29:55 +0200282Copyright: see |manual-copyright| vim:tw=78:ts=8:noet:ft=help:norl: