Simplified the patch.
diff -r 18d84ed365a5 runtime/doc/eval.txt
--- a/runtime/doc/eval.txt Wed Apr 22 22:18:22 2015 +0200
+++ b/runtime/doc/eval.txt Sat May 02 14:37:50 2015 +0200
@@ -2929,7 +2929,7 @@ expand({expr} [, {nosuf} [, {list}]])
See |glob()| for finding existing files. See |system()| for
getting the raw output of an external command.
-extend({expr1}, {expr2} [, {expr3}]) *extend()*
+extend({expr1}, {expr2} [, {expr3} [, {expr4}]]) *extend()*
{expr1} and {expr2} must be both |Lists| or both
|Dictionaries|.
@@ -2958,6 +2958,12 @@ extend({expr1}, {expr2} [, {expr3}])
*
{expr3} = "error": give an error message *E737*
When {expr3} is omitted then "force" is assumed.
+ When errors occur, {expr4} is used to decide what to do:
+ {expr4} = "stop": keep partial changes and return
+ {expr4} = "cont": keep partial changes and continue
+ {expr4} = "rollback": roll back partial changes and return
+ When {expr4} is omitted then "stop" is assumed.
+
{expr1} is changed when {expr2} is not empty. If necessary
make a copy of {expr1} first.
{expr2} remains unchanged.
diff -r 18d84ed365a5 src/eval.c
--- a/src/eval.c Wed Apr 22 22:18:22 2015 +0200
+++ b/src/eval.c Sat May 02 14:37:50 2015 +0200
@@ -8108,7 +8108,7 @@ static struct fst
{"exp", 1, 1, f_exp},
#endif
{"expand", 1, 3, f_expand},
- {"extend", 2, 3, f_extend},
+ {"extend", 2, 4, f_extend},
{"feedkeys", 1, 2, f_feedkeys},
{"file_readable", 1, 1, f_filereadable}, /* obsolete */
{"filereadable", 1, 1, f_filereadable},
@@ -10490,21 +10490,35 @@ f_expand(argvars, rettv)
* When "action" is "error" then a duplicate key is an error.
* When "action" is "force" then a duplicate key is overwritten.
* Otherwise duplicate keys are ignored ("action" is "keep").
- */
- void
-dict_extend(d1, d2, action)
+ * When "err_act" is "cont" then continue after errors.
+ * When "err_act" is "rollback" then rollback changes and return after an
+ * error.
+ * Otherwise return on the first error ("err_act" is "stop").
+ */
+ void
+dict_extend(d1, d2, action, err_act)
dict_T *d1;
dict_T *d2;
char_u *action;
+ char_u *err_act;
{
dictitem_T *di1;
hashitem_T *hi2;
- int todo;
+ int todo, err;
char_u *arg_errmsg = (char_u *)N_("extend() argument");
todo = (int)d2->dv_hashtab.ht_used;
+ err = FALSE;
for (hi2 = d2->dv_hashtab.ht_array; todo > 0; ++hi2)
{
+ if (err)
+ {
+ if (*err_act == 's')
+ break;
+ else if (*err_act == 'r')
+ return;
+ }
+ err = TRUE;
if (!HASHITEM_EMPTY(hi2))
{
--todo;
@@ -10518,26 +10532,62 @@ dict_extend(d1, d2, action)
&& HI2DI(hi2)->di_tv.v_type == VAR_FUNC
&& var_check_func_name(hi2->hi_key,
di1 == NULL))
- break;
+ continue;
if (!valid_varname(hi2->hi_key))
- break;
- }
+ continue;
+ }
+ if (di1 == NULL)
+ {
+ if (tv_check_lock(d1->dv_lock, arg_errmsg, TRUE))
+ continue;
+ if (*err_act != 'r')
+ {
+ di1 = dictitem_copy(HI2DI(hi2));
+ if (di1 != NULL && dict_add(d1, di1) == FAIL)
+ dictitem_free(di1);
+ }
+ }
+ else if (*action == 'e')
+ {
+ EMSG2(_("E737: Key already exists: %s"), hi2->hi_key);
+ continue;
+ }
+ else if (*action == 'f' && HI2DI(hi2) != di1)
+ {
+ if (tv_check_lock(di1->di_tv.v_lock, arg_errmsg, TRUE)
+ || var_check_ro(di1->di_flags, arg_errmsg, TRUE))
+ continue;
+ if (*err_act != 'r')
+ {
+ clear_tv(&di1->di_tv);
+ copy_tv(&HI2DI(hi2)->di_tv, &di1->di_tv);
+ }
+ }
+ }
+ err = FALSE;
+ }
+
+ if (*err_act != 'r')
+ return;
+
+ /*
+ * For err_act "rollback": replace or add dict items.
+ */
+ todo = (int)d2->dv_hashtab.ht_used;
+ for (hi2 = d2->dv_hashtab.ht_array; todo > 0; ++hi2)
+ {
+ if (!HASHITEM_EMPTY(hi2))
+ {
+ --todo;
+ di1 = dict_find(d1, hi2->hi_key, -1);
if (di1 == NULL)
{
di1 = dictitem_copy(HI2DI(hi2));
if (di1 != NULL && dict_add(d1, di1) == FAIL)
dictitem_free(di1);
}
- else if (*action == 'e')
- {
- EMSG2(_("E737: Key already exists: %s"), hi2->hi_key);
- break;
- }
else if (*action == 'f' && HI2DI(hi2) != di1)
{
- if (tv_check_lock(di1->di_tv.v_lock, arg_errmsg, TRUE)
- || var_check_ro(di1->di_flags, arg_errmsg, TRUE))
- break;
clear_tv(&di1->di_tv);
copy_tv(&HI2DI(hi2)->di_tv, &di1->di_tv);
}
@@ -10546,8 +10596,8 @@ dict_extend(d1, d2, action)
}
/*
- * "extend(list, list [, idx])" function
- * "extend(dict, dict [, action])" function
+ * "extend(list, list [, idx [, err_action]])" function
+ * "extend(dict, dict [, action [, err_action]])" function
*/
static void
f_extend(argvars, rettv)
@@ -10596,13 +10646,12 @@ f_extend(argvars, rettv)
else if (argvars[0].v_type == VAR_DICT && argvars[1].v_type == VAR_DICT)
{
dict_T *d1, *d2;
- char_u *action;
+ char_u *action, *err_act;
int i;
d1 = argvars[0].vval.v_dict;
d2 = argvars[1].vval.v_dict;
- if (d1 != NULL && !tv_check_lock(d1->dv_lock, arg_errmsg, TRUE)
- && d2 != NULL)
+ if (d1 != NULL && d2 != NULL)
{
/* Check the third argument. */
if (argvars[2].v_type != VAR_UNKNOWN)
@@ -10624,7 +10673,28 @@ f_extend(argvars, rettv)
else
action = (char_u *)"force";
- dict_extend(d1, d2, action);
+ /* Check the fourth argument. */
+ if (argvars[2].v_type != VAR_UNKNOWN
+ && argvars[3].v_type != VAR_UNKNOWN)
+ {
+ static char *(av[]) = {"stop", "cont", "rollback"};
+
+ err_act = get_tv_string_chk(&argvars[3]);
+ if (err_act == NULL)
+ return; /* type error; errmsg already given */
+ for (i = 0; i < 3; ++i)
+ if (STRCMP(err_act, av[i]) == 0)
+ break;
+ if (i == 3)
+ {
+ EMSG2(_(e_invarg2), err_act);
+ return;
+ }
+ }
+ else
+ err_act = (char_u *)"stop";
+
+ dict_extend(d1, d2, action, err_act);
copy_tv(&argvars[0], rettv);
}
diff -r 18d84ed365a5 src/if_py_both.h
--- a/src/if_py_both.h Wed Apr 22 22:18:22 2015 +0200
+++ b/src/if_py_both.h Sat May 02 14:37:50 2015 +0200
@@ -1915,7 +1915,7 @@ DictionaryUpdate(DictionaryObject *self,
return NULL;
VimTryStart();
- dict_extend(self->dict, tv.vval.v_dict, (char_u *) "force");
+ dict_extend(self->dict, tv.vval.v_dict, (char_u *) "force", "rollback");
clear_tv(&tv);
if (VimTryEnd())
return NULL;
diff -r 18d84ed365a5 src/proto/eval.pro
--- a/src/proto/eval.pro Wed Apr 22 22:18:22 2015 +0200
+++ b/src/proto/eval.pro Sat May 02 14:37:50 2015 +0200
@@ -79,7 +79,7 @@ long get_dict_number __ARGS((dict_T *d,
char_u *get_function_name __ARGS((expand_T *xp, int idx));
char_u *get_expr_name __ARGS((expand_T *xp, int idx));
int func_call __ARGS((char_u *name, typval_T *args, dict_T *selfdict, typval_T
*rettv));
-void dict_extend __ARGS((dict_T *d1, dict_T *d2, char_u *action));
+void dict_extend __ARGS((dict_T *d1, dict_T *d2, char_u *action, char_u
*err_act));
void mzscheme_call_vim __ARGS((char_u *name, typval_T *args, typval_T *rettv));
float_T vim_round __ARGS((float_T f));
long do_searchpair __ARGS((char_u *spat, char_u *mpat, char_u *epat, int dir,
char_u *skip, int flags, pos_T *match_pos, linenr_T lnum_stop, long
time_limit));
diff -r 18d84ed365a5 src/testdir/test55.in
--- a/src/testdir/test55.in Wed Apr 22 22:18:22 2015 +0200
+++ b/src/testdir/test55.in Sat May 02 14:37:50 2015 +0200
@@ -408,6 +408,48 @@ let l = [0, 1, 2, 3]
:endtry
:$put =string(d)
:"
+:$put ='extend() after lock on dict:'
+:unlet! d
+:let d = {'a': 99, 'b': 100, 'd': 101}
+:lockvar 1 d
+:try
+: $put =string(extend(d, {'a': 123}))
+: $put ='ok: did extend() existing item'
+: $put =string(extend(d, {'x': 'new'}))
+: $put ='wrong: did extend() with new item'
+:catch
+: $put =v:exception[:14]
+:endtry
+:$put =string(d)
+:unlet! d2
+:let d2 = {'a': 789, 'b': 42, 'c': 'new', 'd': 52}
+:$put ='key order ok for all-or-nothing test: '.(keys(d2)[0] != 'c')
+:try
+: $put =string(extend(d, d2, 'force', 'rollback'))
+: $put ='wrong: did extend() with mixed-in new item on "rollback"'
+:catch
+: $put =v:exception[:14]
+:endtry
+:$put =string(d)
+:try
+: $put =string(extend(d, d2, 'force', 'stop'))
+: $put ='wrong: did extend() without error with mixed-in new item on "stop"'
+:catch
+: $put =v:exception[:14]
+:endtry
+:$put =string(d)
+:unlet! d
+:let d = {'a': 99, 'b': 100, 'd': 101}
+:lockvar 1 d
+:try
+: $put =string(extend(d, d2, 'force', 'cont'))
+: $put ='wrong: did extend() without error with mixed-in new item on "cont"'
+:catch
+: $put =v:exception[:14]
+:endtry
+:$put =string(d)
+:unlet d d2
+:"
:$put ='No remove() of write-protected scope-level variable:'
:fun! Tfunc(this_is_a_loooooooooong_parameter_name)
: try
diff -r 18d84ed365a5 src/testdir/test55.ok
--- a/src/testdir/test55.ok Wed Apr 22 22:18:22 2015 +0200
+++ b/src/testdir/test55.ok Sat May 02 14:37:50 2015 +0200
@@ -138,6 +138,18 @@ did map()
No extend() after lock on dict item:
Vim(put):E741:
{'a': 99, 'b': 100}
+extend() after lock on dict:
+{'a': 123, 'b': 100, 'd': 101}
+ok: did extend() existing item
+Vim(put):E741:
+{'a': 123, 'b': 100, 'd': 101}
+key order ok for all-or-nothing test: 1
+Vim(put):E741:
+{'a': 123, 'b': 100, 'd': 101}
+Vim(put):E741:
+{'a': 789, 'b': 42, 'd': 101}
+Vim(put):E741:
+{'a': 789, 'b': 42, 'd': 52}
No remove() of write-protected scope-level variable:
Vim(put):E795:
No extend() of write-protected scope-level variable:
--
Olaf Dabrunz (oda <at> fctrace.org)
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.