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.

Raspunde prin e-mail lui