aboutsummaryrefslogtreecommitdiff
path: root/runtime
diff options
context:
space:
mode:
authorzeertzjq <zeertzjq@outlook.com>2023-04-16 07:50:18 +0800
committerzeertzjq <zeertzjq@outlook.com>2023-04-16 15:04:40 +0800
commitb75634e55ee4cdfee7917b29f39e3ca1307cb059 (patch)
treeda8d1238434caa88c4db1b511b68d499be4809f0 /runtime
parent54dab9ed9e200f7c5bcac4a8f4901770fa15fa4f (diff)
downloadrneovim-b75634e55ee4cdfee7917b29f39e3ca1307cb059.tar.gz
rneovim-b75634e55ee4cdfee7917b29f39e3ca1307cb059.tar.bz2
rneovim-b75634e55ee4cdfee7917b29f39e3ca1307cb059.zip
vim-patch:9.0.0370: cleaning up afterwards can make a function messy
Problem: Cleaning up afterwards can make a function messy. Solution: Add the :defer command. https://github.com/vim/vim/commit/1d84f7608f1e41dad03b8cc7925895437775f7c0 Omit EX_EXPR_ARG: Vim9 script only. Make :def throw E319 to avoid confusing behavior. Co-authored-by: Bram Moolenaar <Bram@vim.org>
Diffstat (limited to 'runtime')
-rw-r--r--runtime/doc/userfunc.txt59
1 files changed, 58 insertions, 1 deletions
diff --git a/runtime/doc/userfunc.txt b/runtime/doc/userfunc.txt
index ce6f2fc2e9..2c72f3d584 100644
--- a/runtime/doc/userfunc.txt
+++ b/runtime/doc/userfunc.txt
@@ -350,10 +350,67 @@ 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.
==============================================================================
-3. Automatically loading functions ~
+
+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