Nvim :help pages, generated from source using the tree-sitter-vimdoc parser.

Defining and using functions.
This is introduced in section 41.7 of the user manual.

1. Defining a 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()".
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 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.
:fu :function E128 E129 E123 :fu[nction] List all functions and their arguments.
:fu[nction][!] {name} List function {name}, annotated with line numbers unless "!" is given. {name} may be a Dictionary Funcref entry:
:function dict.init
Note that {name} is not an expression, you cannot use a variable that is a function reference. You can use this dirty trick to list the function referred to with variable "Funcref":
let g:MyFuncref = Funcref
func g:MyFuncref
unlet g:MyFuncref
: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.
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} may be a Dictionary Funcref entry:
: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.
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')
:let F = Foo()
:echo F()
:echo F()
:echo F()
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 :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 :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. Note that 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). 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 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, not for lambda expressions expr-lambda.
function Something(key, value = 10)
   echo a:key .. ": " .. a:value
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.
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)
Example that does NOT work:
:function NoGood(first = a:second, second = 10)
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 "version".
:function Table(title, ...)
:  echohl Title
:  echo a:title
:  echohl None
:  echo a:0 .. " items:"
:  for s in a:000
:    echon ' ' .. s
:  endfor
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]
This function can then be called with:
:let [success, div] = Compute(102, 6)
:if success == "ok"
:  echo div

2. Calling a function
:cal :call E107 E117 :[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. 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
: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\\ '
: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.
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')
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')
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 .. '"')
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 or altering execution outside 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'.
Using an autocommand
This is introduced in the user manual, section 41.14.
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 41.15.
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()
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 "~/.config/nvim/autoload/filename.vim". That file should then define the function like this:
function filename#funcname()
   echo "Done!"
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.
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.
Hint: If you distribute a bunch of scripts read distribute-script.
Commands index
Quick reference