diff options
author | zeertzjq <zeertzjq@outlook.com> | 2023-04-16 07:50:18 +0800 |
---|---|---|
committer | zeertzjq <zeertzjq@outlook.com> | 2023-04-16 15:04:40 +0800 |
commit | b75634e55ee4cdfee7917b29f39e3ca1307cb059 (patch) | |
tree | da8d1238434caa88c4db1b511b68d499be4809f0 /runtime | |
parent | 54dab9ed9e200f7c5bcac4a8f4901770fa15fa4f (diff) | |
download | rneovim-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.txt | 59 |
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 |