Home Explore Blog CI



neovim

5th chunk of `runtime/doc/userfunc.txt`
2b7acd3b41dd55aa8b09ac915a34eb45f96e81d7e0e3657e0000000100000d52
 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.

								*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
or altering execution outside

Title: Function Recursiveness, Cleaning Up with `:defer`
Summary
This section explains how functions are executed within a range, with the cursor moving to each line. It presents examples of functions using `a:firstline` and `a:lastline` to handle ranges and a function that inserts continuation characters. The passage also discusses the restriction of user function recursiveness using the `'maxfuncdepth'` option and alternative methods like `:eval` and method chaining for calling functions. Additionally, it introduces the `:defer` command for scheduling function calls upon function return to ensure cleanup, even in case of errors, with examples of deleting temporary files.