aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/eval/funcs.c21
-rw-r--r--src/nvim/eval/userfunc.c24
2 files changed, 34 insertions, 11 deletions
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 99e511a7a4..66fd663e5e 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -9296,6 +9296,7 @@ static void f_writefile(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
bool binary = false;
bool append = false;
+ bool defer = false;
bool do_fsync = !!p_fs;
bool mkdir_p = false;
if (argvars[2].v_type != VAR_UNKNOWN) {
@@ -9309,6 +9310,8 @@ static void f_writefile(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
binary = true; break;
case 'a':
append = true; break;
+ case 'D':
+ defer = true; break;
case 's':
do_fsync = true; break;
case 'S':
@@ -9328,6 +9331,12 @@ static void f_writefile(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
if (fname == NULL) {
return;
}
+
+ if (defer && get_current_funccal() == NULL) {
+ semsg(_(e_str_not_inside_function), "defer");
+ return;
+ }
+
FileDescriptor fp;
int error;
if (*fname == NUL) {
@@ -9336,9 +9345,17 @@ static void f_writefile(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
((append ? kFileAppend : kFileTruncate)
| (mkdir_p ? kFileMkDir : kFileCreate)
| kFileCreate), 0666)) != 0) {
- semsg(_("E482: Can't open file %s for writing: %s"),
- fname, os_strerror(error));
+ semsg(_("E482: Can't open file %s for writing: %s"), fname, os_strerror(error));
} else {
+ if (defer) {
+ typval_T tv = {
+ .v_type = VAR_STRING,
+ .v_lock = VAR_UNLOCKED,
+ .vval.v_string = xstrdup(fname),
+ };
+ add_defer("delete", 1, &tv);
+ }
+
bool write_ok;
if (argvars[0].v_type == VAR_BLOB) {
write_ok = write_blob(&fp, argvars[0].vval.v_blob);
diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c
index 9853622ee0..4b9bc1fdec 100644
--- a/src/nvim/eval/userfunc.c
+++ b/src/nvim/eval/userfunc.c
@@ -478,6 +478,7 @@ void emsg_funcname(const char *errmsg, const char *name)
/// Get function arguments at "*arg" and advance it.
/// Return them in "*argvars[MAX_FUNC_ARGS + 1]" and the count in "argcount".
+/// On failure FAIL is returned but the "argvars[argcount]" are still set.
static int get_func_arguments(char **arg, evalarg_T *const evalarg, int partial_argc,
typval_T *argvars, int *argcount)
{
@@ -3119,16 +3120,28 @@ static int ex_defer_inner(char *name, char **arg, evalarg_T *const evalarg)
{
typval_T argvars[MAX_FUNC_ARGS + 1]; // vars for arguments
int argcount = 0; // number of arguments found
- int ret = FAIL;
if (current_funccal == NULL) {
semsg(_(e_str_not_inside_function), "defer");
return FAIL;
}
if (get_func_arguments(arg, evalarg, false, argvars, &argcount) == FAIL) {
- goto theend;
+ while (--argcount >= 0) {
+ tv_clear(&argvars[argcount]);
+ }
+ return FAIL;
}
+ add_defer(name, argcount, argvars);
+ return OK;
+}
+
+/// Add a deferred call for "name" with arguments "argvars[argcount]".
+/// Consumes "argvars[]".
+/// Caller must check that current_funccal is not NULL.
+void add_defer(char *name, int argcount_arg, typval_T *argvars)
+{
char *saved_name = xstrdup(name);
+ int argcount = argcount_arg;
if (current_funccal->fc_defer.ga_itemsize == 0) {
ga_init(&current_funccal->fc_defer, sizeof(defer_T), 10);
@@ -3140,13 +3153,6 @@ static int ex_defer_inner(char *name, char **arg, evalarg_T *const evalarg)
argcount--;
dr->dr_argvars[argcount] = argvars[argcount];
}
- ret = OK;
-
-theend:
- while (--argcount >= 0) {
- tv_clear(&argvars[argcount]);
- }
- return ret;
}
/// Invoked after a function has finished: invoke ":defer" functions.