Proposal for set() function (like get()) (and a patch)

1 view
Skip to first unread message

Hari Krishna Dara

unread,
Oct 2, 2009, 6:54:03 PM10/2/09
to vim...@googlegroups.com
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.

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

Bram Moolenaar

unread,
Oct 4, 2009, 10:56:33 AM10/4/09
to Hari Krishna Dara, vim...@googlegroups.com

Hari Krishna Dara wrote:

> 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 ///

Reply all
Reply to author
Forward
0 new messages