# Vim documentation: userfunc

main help file

    *userfunc.txt*	For Vim version 9.2.  Last change: 2026 Feb 14

    		  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
    			YXXYFuncref|:
    				: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|.

    								*E1267*
    			The name must be made of alphanumeric characters and
    			'_' and must start with a capital or "s:" (see above).
    			Note that using "b:", "l:", etc. is not allowed (since
    			patch 7.4.260 E884 is given if the function name has a
    			colon, e.g. for "foo:bar()"), while a leading "g:" is
    			skipped and still requires a following capital letter.

    			{name} can also be a |Dictionary| entry that is a
    			YXXYFuncref|:
    				: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 YXXY: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
    			YXXYFuncref|:
    				: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 YXXYList|:
      :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

    							*:defe* *:defer*
    :defe[r] {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
    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*

    In a |:def| function, a lambda can be used with |:defer|.  Example:

        def Fn()
          set lazyredraw
          defer () => {
            set lazyredraw&
          }()
        enddef

    ==============================================================================

    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|.

    top - main help file