8 ":let Func().foo = value" should work, also when "foo" doesn't exist.
The idea is that when Func() returns a dict(), you should be able to
set its "foo" key's value. With the set(), we can now achieve the same
and even more (if set() returns the original list or dictionary for
call chaining). E.g.,
call set(set(Func(), 'foo', 'foovalue'), 'bar', 'barvalue')
I was planning for an API for one of my plugins that returns
dictionaries, and using this API and assembling the objects becomes
unwieldy with all the temporary variables and assignments that are
required without such a function.
Here is a patch that adds this function. Bram, please accept this
patch into official source if you don't see any issues with it.
Index: runtime/doc/eval.txt
===================================================================
--- runtime/doc/eval.txt (revision 1622)
+++ runtime/doc/eval.txt (working copy)
@@ -1861,6 +1861,8 @@
server2client( {clientid}, {string})
Number send reply string
serverlist() String get a list of available servers
+set( {list}, {idx}, {item}) any set {item} in {list} at {idx}
+set( {dict}, {key}, {item}) any set {key} in {dict} to {item}
setbufvar( {expr}, {varname}, {val}) set {varname} in buffer {expr} to {val}
setcmdpos( {pos}) Number set cursor position in command-line
setline( {lnum}, {line}) Number set line {lnum} to {line}
@@ -2946,6 +2948,24 @@
item is not available return {default}. Return zero when
{default} is omitted.
+set({list}, {idx}, {item}) *set()*
+ Set at {idx} in |List| {list} to specified {item}. You can't
+ extend the list using this function, so specifying a non
+ existing {idx} results in |E684| error.
+ Returns the {list} such that it can be used for method
+ chaining. Useful for setting indices returned by function
+ calls. >
+ :call set(GetHLColors(), HEADLINE_IDX, 'red')
+>
+set({dict}, {key}, {item})
+ Set the {key} in {dict} to specified {item}. When {key} is
+ non-existent, a new key is creaeted. When {key} is existing,
+ its value is overwritten with {item}.
+ Returns the {dict} such that it can be used for method
+ chaining. Useful for changing keys of dictionaries returned by
+ function calls. >
+ :call set(GetData(), 'maxlength', 100)
+>
*getbufline()*
getbufline({expr}, {lnum} [, {end}])
Return a |List| with the lines starting from {lnum} to {end}
Index: src/eval.c
===================================================================
--- src/eval.c (revision 1622)
+++ src/eval.c (working copy)
@@ -661,6 +661,7 @@
static void f_searchpos __ARGS((typval_T *argvars, typval_T *rettv));
static void f_server2client __ARGS((typval_T *argvars, typval_T *rettv));
static void f_serverlist __ARGS((typval_T *argvars, typval_T *rettv));
+static void f_set __ARGS((typval_T *argvars, typval_T *rettv));
static void f_setbufvar __ARGS((typval_T *argvars, typval_T *rettv));
static void f_setcmdpos __ARGS((typval_T *argvars, typval_T *rettv));
static void f_setline __ARGS((typval_T *argvars, typval_T *rettv));
@@ -7716,6 +7717,7 @@
#ifdef FEAT_FLOAT
{"round", 1, 1, f_round},
#endif
+ {"set", 3, 3, f_set},
{"search", 1, 4, f_search},
{"searchdecl", 1, 3, f_searchdecl},
{"searchpair", 3, 7, f_searchpair},
@@ -10444,6 +10446,59 @@
copy_tv(tv, rettv);
}
+/*
+ * "set()" function
+ */
+ static void
+f_set(argvars, rettv)
+ typval_T *argvars;
+ typval_T *rettv;
+{
+ listitem_T *li;
+ list_T *l;
+ dictitem_T *di;
+ dict_T *d;
+ typval_T tmp;
+ char_u *key;
+
+ if (argvars[0].v_type == VAR_LIST)
+ {
+ if ((l = argvars[0].vval.v_list) != NULL)
+ {
+ int error = FALSE;
+
+ li = list_find(l, get_tv_number_chk(&argvars[1], &error));
+ if (li == NULL)
+ EMSGN(_(e_listidx), get_tv_number_chk(&argvars[1], &error));
+ else
+ {
+ copy_tv(&argvars[2], &li->li_tv);
+ }
+ }
+ copy_tv(&argvars[0], rettv);
+ }
+ else if (argvars[0].v_type == VAR_DICT)
+ {
+ if ((d = argvars[0].vval.v_dict) != NULL)
+ {
+ key = get_tv_string(&argvars[1]);
+ di = dict_find(d, key, -1);
+ if (di != NULL)
+ copy_tv(&argvars[2], &di->di_tv);
+ else
+ {
+ di = dictitem_alloc(key);
+ copy_tv(&argvars[2], &di->di_tv);
+ if (dict_add(d, di) == FAIL)
+ dictitem_free(di);
+ }
+ }
+ copy_tv(&argvars[0], rettv);
+ }
+ else
+ EMSG2(_(e_listdictarg), "get()");
+}
+
static void get_buffer_lines __ARGS((buf_T *buf, linenr_T start,
linenr_T end, int retlist, typval_T *rettv));
/*
--
Thanks,
Hari
> I have been wanting this function for over 3years now, as a simpler
> workaround for the |todo| item:
>
> 8 ":let Func().foo = value" should work, also when "foo" doesn't exist.
>
> The idea is that when Func() returns a dict(), you should be able to
> set its "foo" key's value. With the set(), we can now achieve the same
> and even more (if set() returns the original list or dictionary for
> call chaining). E.g.,
>
> call set(set(Func(), 'foo', 'foovalue'), 'bar', 'barvalue')
>
> I was planning for an API for one of my plugins that returns
> dictionaries, and using this API and assembling the objects becomes
> unwieldy with all the temporary variables and assignments that are
> required without such a function.
>
> Here is a patch that adds this function. Bram, please accept this
> patch into official source if you don't see any issues with it.
Hmm, set() sounds very generic, setItem() might be better.
For the list situation, what does it add over the use of an index:
call set(list, idx, val)
let list[idx] = val
Don't these two commands do exactly the same?
Similarly, for at dict:
call set(dict, key, val)
let dict[key] = val
The problem is that using a function doesn't work:
let GetList()[idx] = val
let GetDict()[key] = val
Instead of implementing set(), wouldn't it be better to implement this?
--
Eight Megabytes And Continually Swapping.
/// Bram Moolenaar -- Br...@Moolenaar.net -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ download, build and distribute -- http://www.A-A-P.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///