diff options
author | Ernie Rael <errael@raelity.com> | 2024-07-09 18:39:52 +0200 |
---|---|---|
committer | Christian Brabandt <cb@256bit.org> | 2024-07-09 18:39:52 +0200 |
commit | c8e158be0eb0f2f8d6c04ea5de64318a33fd3d02 (patch) | |
tree | 1a802509e60933eaadc897b2f7193b1458dd522c | |
parent | 73a810817b9bea7ce31e625bf5519b6a02f53d41 (diff) |
patch 9.1.0548: it's not possible to get a unique id for some varsv9.1.0548
Problem: it's not possible to get a unique id for some vars
Solution: Add the id() Vim script function, which returns a unique
identifier for object, dict, list, job, blob or channel
variables (Ernie Rael)
fixes: #14374
closes: #15145
Signed-off-by: Ernie Rael <errael@raelity.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
-rw-r--r-- | runtime/doc/builtin.txt | 29 | ||||
-rw-r--r-- | runtime/doc/tags | 1 | ||||
-rw-r--r-- | runtime/doc/usr_41.txt | 2 | ||||
-rw-r--r-- | runtime/doc/version9.txt | 4 | ||||
-rw-r--r-- | src/evalfunc.c | 37 | ||||
-rw-r--r-- | src/testdir/test_listdict.vim | 30 | ||||
-rw-r--r-- | src/version.c | 2 |
7 files changed, 104 insertions, 1 deletions
diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt index 635b7b2218..9c3d7a91f8 100644 --- a/runtime/doc/builtin.txt +++ b/runtime/doc/builtin.txt @@ -309,6 +309,7 @@ hlget([{name} [, {resolve}]]) List get highlight group attributes hlset({list}) Number set highlight group attributes hostname() String name of the machine Vim is running on iconv({expr}, {from}, {to}) String convert encoding of {expr} +id({item}) String get address of item as a string indent({lnum}) Number indent of line {lnum} index({object}, {expr} [, {start} [, {ic}]]) Number index in {object} where {expr} appears @@ -5618,6 +5619,34 @@ iconv({string}, {from}, {to}) *iconv()* Return type: |String| +id({item}) *id()* + The result is a unique String associated with the {item} and + not with the {item}'s contents. It is only valid while the + {item} exists and is referenced. It is valid only in the + instance of vim that produces the result. The whole idea is + that `id({item})` does not change if the contents of {item} + changes. This is useful as a `key` for creating an identity + dictionary, rather than one based on equals. + + This operation does not reference {item} and there is no + function to convert the `id` to the {item}. It may be useful to + have a map of `id` to {item}. The following > + var referenceMap: dict<any> + var id = item->id() + referenceMap[id] = item +< prevents {item} from being garbage collected and provides a + way to get the {item} from the `id`. + + {item} may be a List, Dictionary, Object, Job, Channel or + Blob. If the item is not a permitted type, or it is a null + value, then an empty String is returned. + + Can also be used as a |method|: > + GetItem()->id() +< + Return type: |String| + + indent({lnum}) *indent()* The result is a Number, which is indent of line {lnum} in the current buffer. The indent is counted in spaces, the value diff --git a/runtime/doc/tags b/runtime/doc/tags index be71710bc4..adbc145859 100644 --- a/runtime/doc/tags +++ b/runtime/doc/tags @@ -8302,6 +8302,7 @@ iconise starting.txt /*iconise* iconize starting.txt /*iconize* iconv() builtin.txt /*iconv()* iconv-dynamic mbyte.txt /*iconv-dynamic* +id() builtin.txt /*id()* ident-search tips.txt /*ident-search* idl-syntax syntax.txt /*idl-syntax* idl.vim syntax.txt /*idl.vim* diff --git a/runtime/doc/usr_41.txt b/runtime/doc/usr_41.txt index 922e80a050..765eab5040 100644 --- a/runtime/doc/usr_41.txt +++ b/runtime/doc/usr_41.txt @@ -1408,6 +1408,8 @@ Various: *various-functions* wordcount() get byte/word/char count of buffer + id() get unique string for item to use as a key + luaeval() evaluate |Lua| expression mzeval() evaluate |MzScheme| expression perleval() evaluate Perl expression (|+perl|) diff --git a/runtime/doc/version9.txt b/runtime/doc/version9.txt index 43de2692fa..86ec0208ac 100644 --- a/runtime/doc/version9.txt +++ b/runtime/doc/version9.txt @@ -1,4 +1,4 @@ -*version9.txt* For Vim version 9.1. Last change: 2024 Jul 08 +*version9.txt* For Vim version 9.1. Last change: 2024 Jul 09 VIM REFERENCE MANUAL by Bram Moolenaar @@ -41593,6 +41593,8 @@ Functions: ~ |foreach()| apply function to List items |getregion()| get a region of text from a buffer |getregionpos()| get a list of positions for a region +|id()| get unique identifier for a Dict, List, Object, + Channel or Blob variable |matchbufline()| all the matches of a pattern in a buffer |matchstrlist()| all the matches of a pattern in a List of strings |popup_setbuf()| switch to a different buffer in a popup diff --git a/src/evalfunc.c b/src/evalfunc.c index 5e3122dd97..370b26bd89 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -82,6 +82,7 @@ static void f_haslocaldir(typval_T *argvars, typval_T *rettv); static void f_hlID(typval_T *argvars, typval_T *rettv); static void f_hlexists(typval_T *argvars, typval_T *rettv); static void f_hostname(typval_T *argvars, typval_T *rettv); +static void f_id(typval_T *argvars, typval_T *rettv); static void f_index(typval_T *argvars, typval_T *rettv); static void f_indexof(typval_T *argvars, typval_T *rettv); static void f_input(typval_T *argvars, typval_T *rettv); @@ -2207,6 +2208,8 @@ static funcentry_T global_functions[] = ret_string, f_hostname}, {"iconv", 3, 3, FEARG_1, arg3_string, ret_string, f_iconv}, + {"id", 1, 1, FEARG_1, NULL, + ret_string, f_id}, {"indent", 1, 1, FEARG_1, arg1_lnum, ret_number, f_indent}, {"index", 2, 4, FEARG_1, arg24_index, @@ -7517,6 +7520,40 @@ f_hostname(typval_T *argvars UNUSED, typval_T *rettv) } /* + * "id()" function + * Identity. Return address of item as a hex string, %p format. + * Currently only valid for object/container types. + * Return empty string if not an object. + */ + void +f_id(typval_T *argvars, typval_T *rettv) +{ + char_u numbuf[NUMBUFLEN]; + + switch (argvars[0].v_type) + { + case VAR_LIST: + case VAR_DICT: + case VAR_OBJECT: + case VAR_JOB: + case VAR_CHANNEL: + case VAR_BLOB: + // Assume pointer value in typval_T vval union at common location. + if (argvars[0].vval.v_object != NULL) + vim_snprintf((char*)numbuf, sizeof(numbuf), "%p", + (void *)argvars[0].vval.v_object); + else + numbuf[0] = NUL; + break; + default: + numbuf[0] = NUL; + } + + rettv->v_type = VAR_STRING; + rettv->vval.v_string = vim_strsave(numbuf); +} + +/* * "index()" function */ static void diff --git a/src/testdir/test_listdict.vim b/src/testdir/test_listdict.vim index 0a4f88c4e5..48217cf33e 100644 --- a/src/testdir/test_listdict.vim +++ b/src/testdir/test_listdict.vim @@ -1619,4 +1619,34 @@ func Test_deep_nested_listdict_compare() call v9.CheckLegacyAndVim9Success(lines) endfunc +" Test for using id() +def Test_id_with_dict() + # demonstate a way that "id(item)" differs from "string(item)" + var d1 = {one: 1} + var d2 = {one: 1} + var d3 = {one: 1} + var idDict: dict<any> + idDict[id(d1)] = d1 + idDict[id(d2)] = d2 + idDict[id(d3)] = d3 + assert_equal(3, idDict->len()) + + var stringDict: dict<any> + stringDict[string(d1)] = d1 + stringDict[string(d2)] = d2 + stringDict[string(d3)] = d3 + assert_equal(1, stringDict->len()) + + assert_equal('', id(3)) + + assert_equal('', id(null)) + assert_equal('', id(null_blob)) + assert_equal('', id(null_dict)) + assert_equal('', id(null_function)) + assert_equal('', id(null_list)) + assert_equal('', id(null_partial)) + assert_equal('', id(null_string)) + assert_equal('', id(null_channel)) + assert_equal('', id(null_job)) +enddef " vim: shiftwidth=2 sts=2 expandtab diff --git a/src/version.c b/src/version.c index ce6b8d60ab..1f334caba2 100644 --- a/src/version.c +++ b/src/version.c @@ -705,6 +705,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 548, +/**/ 547, /**/ 546, |