diff options
Diffstat (limited to 'runtime/doc/userfunc.txt')
-rw-r--r-- | runtime/doc/userfunc.txt | 546 |
1 files changed, 546 insertions, 0 deletions
diff --git a/runtime/doc/userfunc.txt b/runtime/doc/userfunc.txt new file mode 100644 index 0000000..210c2c5 --- /dev/null +++ b/runtime/doc/userfunc.txt @@ -0,0 +1,546 @@ +*userfunc.txt* For Vim version 9.0. Last change: 2023 Feb 02 + + + VIM REFERENCE MANUAL by Bram Moolenaar + + +Defining and using functions. + +This is introduced in section |41.7| of the user manual. + +1. Defining a function |define-function| +2. Calling a function |:call| +3. Cleaning up in a function |:defer| +4. Automatically loading functions |autoload-functions| + +============================================================================== + +1. Defining a function ~ + *define-function* +New functions can be defined. These can be called just like builtin +functions. The function executes a sequence of Ex commands. Normal mode +commands can be executed with the |:normal| command. + +The function name must start with an uppercase letter, to avoid confusion with +builtin functions. To prevent from using the same name in different scripts +make them script-local. If you do use a global function then avoid obvious, +short names. A good habit is to start the function name with the name of the +script, e.g., "HTMLcolor()". + +In legacy script it is also possible to use curly braces, see +|curly-braces-names|. + +The |autoload| facility is useful to define a function only when it's called. + + *local-function* +A function local to a legacy script must start with "s:". A local script +function can only be called from within the script and from functions, user +commands and autocommands defined in the script. It is also possible to call +the function from a mapping defined in the script, but then |<SID>| must be +used instead of "s:" when the mapping is expanded outside of the script. +There are only script-local functions, no buffer-local or window-local +functions. + +In |Vim9| script functions are local to the script by default, prefix "g:" to +define a global function. + + *:fu* *:function* *E128* *E129* *E123* *E454* +:fu[nction] List all functions and their arguments. + +:fu[nction] {name} List function {name}. + {name} can also be a |Dictionary| entry that is a + |Funcref|: > + :function dict.init + +:fu[nction] /{pattern} List functions with a name matching {pattern}. + Example that lists all functions ending with "File": > + :function /File$ +< + *:function-verbose* +When 'verbose' is non-zero, listing a function will also display where it was +last defined. Example: > + + :verbose function SetFileTypeSH + function SetFileTypeSH(name) + Last set from /usr/share/vim/vim-7.0/filetype.vim +< +See |:verbose-cmd| for more information. + + *E124* *E125* *E853* *E884* +:fu[nction][!] {name}([arguments]) [range] [abort] [dict] [closure] + Define a new function by the name {name}. The body of + the function follows in the next lines, until the + matching |:endfunction|. + *E1267* + The name must be made of alphanumeric characters and + '_', and must start with a capital or "s:" (see + above). Note that using "b:" or "g:" is not allowed. + (since patch 7.4.260 E884 is given if the function + name has a colon in the name, e.g. for "foo:bar()". + Before that patch no error was given). + + {name} can also be a |Dictionary| entry that is a + |Funcref|: > + :function dict.init(arg) +< "dict" must be an existing dictionary. The entry + "init" is added if it didn't exist yet. Otherwise [!] + is required to overwrite an existing function. The + result is a |Funcref| to a numbered function. The + function can only be used with a |Funcref| and will be + deleted if there are no more references to it. + *E127* *E122* + When a function by this name already exists and [!] is + not used an error message is given. There is one + exception: When sourcing a script again, a function + that was previously defined in that script will be + silently replaced. + When [!] is used, an existing function is silently + replaced. Unless it is currently being executed, that + is an error. + NOTE: Use ! wisely. If used without care it can cause + an existing function to be replaced unexpectedly, + which is hard to debug. + NOTE: In Vim9 script script-local functions cannot be + deleted or redefined. + + For the {arguments} see |function-argument|. + + *:func-range* *a:firstline* *a:lastline* + When the [range] argument is added, the function is + expected to take care of a range itself. The range is + passed as "a:firstline" and "a:lastline". If [range] + is excluded, ":{range}call" will call the function for + each line in the range, with the cursor on the start + of each line. See |function-range-example|. + The cursor is still moved to the first line of the + range, as is the case with all Ex commands. + *:func-abort* + When the [abort] argument is added, the function will + abort as soon as an error is detected. + *:func-dict* + When the [dict] argument is added, the function must + be invoked through an entry in a |Dictionary|. The + local variable "self" will then be set to the + dictionary. See |Dictionary-function|. + *:func-closure* *E932* + When the [closure] argument is added, the function + can access variables and arguments from the outer + scope. This is usually called a closure. In this + example Bar() uses "x" from the scope of Foo(). It + remains referenced even after Foo() returns: > + :function! Foo() + : let x = 0 + : function! Bar() closure + : let x += 1 + : return x + : endfunction + : return funcref('Bar') + :endfunction + + :let F = Foo() + :echo F() +< 1 > + :echo F() +< 2 > + :echo F() +< 3 + + *function-search-undo* + The last used search pattern and the redo command "." + will not be changed by the function. This also + implies that the effect of |:nohlsearch| is undone + when the function returns. + + *:endf* *:endfunction* *E126* *E193* *W22* *E1151* +:endf[unction] [argument] + The end of a function definition. Best is to put it + on a line by its own, without [argument]. + + [argument] can be: + | command command to execute next + \n command command to execute next + " comment always ignored + anything else ignored, warning given when + 'verbose' is non-zero + The support for a following command was added in Vim + 8.0.0654, before that any argument was silently + ignored. + + To be able to define a function inside an `:execute` + command, use line breaks instead of |:bar|: > + :exe "func Foo()\necho 'foo'\nendfunc" +< + *:delf* *:delfunction* *E131* *E933* *E1084* +:delf[unction][!] {name} + Delete function {name}. + {name} can also be a |Dictionary| entry that is a + |Funcref|: > + :delfunc dict.init +< This will remove the "init" entry from "dict". The + function is deleted if there are no more references to + it. + With the ! there is no error if the function does not + exist. + *:retu* *:return* *E133* +:retu[rn] [expr] Return from a function. When "[expr]" is given, it is + evaluated and returned as the result of the function. + If "[expr]" is not given, the number 0 is returned. + When a function ends without an explicit ":return", + the number 0 is returned. + + In a :def function *E1095* is given if unreachable + code follows after the `:return`. + In legacy script there is no check for unreachable + lines, thus there is no warning if commands follow + `:return`. Also, there is no check if the following + line contains a valid command. Forgetting the line + continuation backslash may go unnoticed: > + return 'some text' + .. ' some more text' +< Will happily return "some text" without an error. It + should have been: > + return 'some text' + \ .. ' some more text' +< + If the ":return" is used after a |:try| but before the + matching |:finally| (if present), the commands + following the ":finally" up to the matching |:endtry| + are executed first. This process applies to all + nested ":try"s inside the function. The function + returns at the outermost ":endtry". + + *function-argument* *a:var* +An argument can be defined by giving its name. In the function this can then +be used as "a:name" ("a:" for argument) (in a `:def` function "a:" is not +used). + *a:0* *a:1* *a:000* *E740* *...* +Up to 20 arguments can be given, separated by commas. After the named +arguments an argument "..." can be specified, which means that more arguments +may optionally be following. In the function the extra arguments can be used +as "a:1", "a:2", etc. "a:0" is set to the number of extra arguments (which +can be 0). "a:000" is set to a |List| that contains these arguments. Note +that "a:1" is the same as "a:000[0]". + *E742* *E1090* +The a: scope and the variables in it cannot be changed, they are fixed. +However, if a composite type is used, such as |List| or |Dictionary| , you can +change their contents. Thus you can pass a |List| to a function and have the +function add an item to it. If you want to make sure the function cannot +change a |List| or |Dictionary| use |:lockvar|. + +It is also possible to define a function without any arguments. You must +still supply the () then. + +It is allowed to define another function inside a function body. + + *optional-function-argument* +You can provide default values for positional named arguments. This makes +them optional for function calls. When a positional argument is not +specified at a call, the default expression is used to initialize it. +This only works for functions declared with `:function` or `:def`, not for +lambda expressions |expr-lambda|. + +Example: > + function Something(key, value = 10) + echo a:key .. ": " .. a:value + endfunction + call Something('empty') "empty: 10" + call Something('key', 20) "key: 20" + +The argument default expressions are evaluated at the time of the function +call, not when the function is defined. Thus it is possible to use an +expression which is invalid the moment the function is defined. The +expressions are also only evaluated when arguments are not specified during a +call. + *none-function_argument* +You can pass |v:none| to use the default expression. Note that this means you +cannot pass v:none as an ordinary value when an argument has a default +expression. + +Example: > + function Something(a = 10, b = 20, c = 30) + endfunction + call Something(1, v:none, 3) " b = 20 +< + *E989* +Optional arguments with default expressions must occur after any mandatory +arguments. You can use "..." after all optional named arguments. + +It is possible for later argument defaults to refer to prior arguments, +but not the other way around. They must be prefixed with "a:", as with all +arguments. + +Example that works: > + :function Okay(mandatory, optional = a:mandatory) + :endfunction +Example that does NOT work: > + :function NoGood(first = a:second, second = 10) + :endfunction +< +When not using "...", the number of arguments in a function call must be at +least equal to the number of mandatory named arguments. When using "...", the +number of arguments may be larger than the total of mandatory and optional +arguments. + + *local-variables* +Inside a function local variables can be used. These will disappear when the +function returns. Global variables need to be accessed with "g:". +Inside functions local variables are accessed without prepending anything. +But you can also prepend "l:" if you like. This is required for some reserved +names, such as "count". + +Example: > + :function Table(title, ...) + : echohl Title + : echo a:title + : echohl None + : echo a:0 .. " items:" + : for s in a:000 + : echon ' ' .. s + : endfor + :endfunction + +This function can then be called with: > + call Table("Table", "line1", "line2") + call Table("Empty Table") + +To return more than one value, return a |List|: > + :function Compute(n1, n2) + : if a:n2 == 0 + : return ["fail", 0] + : endif + : return ["ok", a:n1 / a:n2] + :endfunction + +This function can then be called with: > + :let [success, div] = Compute(102, 6) + :if success == "ok" + : echo div + :endif +< +============================================================================== + +2. Calling a function ~ + *:cal* *:call* *E107* +:[range]cal[l] {name}([arguments]) + Call a function. The name of the function and its arguments + are as specified with `:function`. Up to 20 arguments can be + used. The returned value is discarded. + In |Vim9| script using `:call` is optional, these two lines do + the same thing: > + call SomeFunc(arg) + SomeFunc(arg) +< Without a range and for functions that accept a range, the + function is called once. When a range is given the cursor is + positioned at the start of the first line before executing the + function. + When a range is given and the function doesn't handle it + itself, the function is executed for each line in the range, + with the cursor in the first column of that line. The cursor + is left at the last line (possibly moved by the last function + call). The arguments are re-evaluated for each line. Thus + this works: + *function-range-example* > + :function Mynumber(arg) + : echo line(".") .. " " .. a:arg + :endfunction + :1,5call Mynumber(getline(".")) +< + The "a:firstline" and "a:lastline" are defined anyway, they + can be used to do something different at the start or end of + the range. + + Example of a function that handles the range itself: > + + :function Cont() range + : execute (a:firstline + 1) .. "," .. a:lastline .. 's/^/\t\\ ' + :endfunction + :4,8call Cont() +< + This function inserts the continuation character "\" in front + of all the lines in the range, except the first one. + + When the function returns a composite value it can be further + dereferenced, but the range will not be used then. Example: > + :4,8call GetDict().method() +< Here GetDict() gets the range but method() does not. + + *E117* +When a function cannot be found the error "E117: Unknown function" will be +given. If the function was using an autoload path or an autoload import and +the script is a |Vim9| script, this may also be caused by the function not +being exported. + + *E132* +The recursiveness of user functions is restricted with the |'maxfuncdepth'| +option. + +It is also possible to use `:eval`. It does not support a range, but does +allow for method chaining, e.g.: > + eval GetList()->Filter()->append('$') + +A function can also be called as part of evaluating an expression or when it +is used as a method: > + let x = GetList() + let y = GetList()->Filter() + +============================================================================== + +3. Cleaning up in a function ~ + *:defer* +:defer {func}({args}) Call {func} when the current function is done. + {args} are evaluated here. + +Quite often a command in a function has a global effect, which must be undone +when the function finishes. Handling this in all kinds of situations can be a +hassle. Especially when an unexpected error is encountered. This can be done +with `try` / `finally` blocks, but this gets complicated when there is more +than one. + +A much simpler solution is using `defer`. It schedules a function call when +the function is returning, no matter if there is an error. Example: > + func Filter(text) abort + call writefile(a:text, 'Tempfile') + call system('filter < Tempfile > Outfile') + call Handle('Outfile') + call delete('Tempfile') + call delete('Outfile') + endfunc + +Here 'Tempfile' and 'Outfile' will not be deleted if something causes the +function to abort. `:defer` can be used to avoid that: > + func Filter(text) abort + call writefile(a:text, 'Tempfile') + defer delete('Tempfile') + defer delete('Outfile') + call system('filter < Tempfile > Outfile') + call Handle('Outfile') + endfunc + +Note that deleting "Outfile" is scheduled before calling `system()`, since it +can be created even when `system()` fails. + +The deferred functions are called in reverse order, the last one added is +executed first. A useless example: > + func Useless() abort + for s in range(3) + defer execute('echomsg "number ' .. s .. '"') + endfor + endfunc + +Now `:messages` shows: + number 2 + number 1 + number 0 + +Any return value of the deferred function is discarded. The function cannot +be followed by anything, such as "->func" or ".member". Currently `:defer +GetArg()->TheFunc()` does not work, it may work in a later version. + +Errors are reported but do not cause aborting execution of deferred functions. + +No range is accepted. The function can be a partial with extra arguments, but +not with a dictionary. *E1300* + +============================================================================== + +4. Automatically loading functions ~ + *autoload-functions* +When using many or large functions, it's possible to automatically define them +only when they are used. There are two methods: with an autocommand and with +the "autoload" directory in 'runtimepath'. + +In |Vim9| script there is also an autoload mechanism for imported scripts, see +|import-autoload|. + + +Using an autocommand ~ + +This is introduced in the user manual, section |51.4|. + +The autocommand is useful if you have a plugin that is a long Vim script file. +You can define the autocommand and quickly quit the script with `:finish`. +That makes Vim startup faster. The autocommand should then load the same file +again, setting a variable to skip the `:finish` command. + +Use the FuncUndefined autocommand event with a pattern that matches the +function(s) to be defined. Example: > + + :au FuncUndefined BufNet* source ~/vim/bufnetfuncs.vim + +The file "~/vim/bufnetfuncs.vim" should then define functions that start with +"BufNet". Also see |FuncUndefined|. + + +Using an autoload script ~ + *autoload* *E746* +This is introduced in the user manual, section |52.2|. + +Using a script in the "autoload" directory is simpler, but requires using +exactly the right file name. A function that can be autoloaded has a name +like this: > + + :call filename#funcname() + +These functions are always global, in Vim9 script "g:" needs to be used: > + :call g:filename#funcname() + +When such a function is called, and it is not defined yet, Vim will search the +"autoload" directories in 'runtimepath' for a script file called +"filename.vim". For example "~/.vim/autoload/filename.vim". That file should +then define the function like this: > + + function filename#funcname() + echo "Done!" + endfunction + +If the file doesn't exist, Vim will also search in 'packpath' (under "start") +to allow calling packages' functions from your .vimrc when the packages have +not been added to 'runtimepath' yet (see |packages|). + +The file name and the name used before the # in the function must match +exactly, and the defined function must have the name exactly as it will be +called. In Vim9 script the "g:" prefix must be used: > + function g:filename#funcname() + +or for a compiled function: > + def g:filename#funcname() + +It is possible to use subdirectories. Every # in the function name works like +a path separator. Thus when calling a function: > + + :call foo#bar#func() + +Vim will look for the file "autoload/foo/bar.vim" in 'runtimepath'. + +This also works when reading a variable that has not been set yet: > + + :let l = foo#bar#lvar + +However, when the autoload script was already loaded it won't be loaded again +for an unknown variable. + +When assigning a value to such a variable nothing special happens. This can +be used to pass settings to the autoload script before it's loaded: > + + :let foo#bar#toggle = 1 + :call foo#bar#func() + +Note that when you make a mistake and call a function that is supposed to be +defined in an autoload script, but the script doesn't actually define the +function, you will get an error message for the missing function. If you fix +the autoload script it won't be automatically loaded again. Either restart +Vim or manually source the script. + +Also note that if you have two script files, and one calls a function in the +other and vice versa, before the used function is defined, it won't work. +Avoid using the autoload functionality at the toplevel. + +In |Vim9| script you will get error *E1263* if you define a function with +a "#" character in the name. You should use a name without "#" and use +`:export`. + +Hint: If you distribute a bunch of scripts you can pack them together with the +|vimball| utility. Also read the user manual |distribute-script|. + + + vim:tw=78:ts=8:noet:ft=help:norl: |