summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorErnie Rael <errael@raelity.com>2024-07-09 18:39:52 +0200
committerChristian Brabandt <cb@256bit.org>2024-07-09 18:39:52 +0200
commitc8e158be0eb0f2f8d6c04ea5de64318a33fd3d02 (patch)
tree1a802509e60933eaadc897b2f7193b1458dd522c
parent73a810817b9bea7ce31e625bf5519b6a02f53d41 (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.txt29
-rw-r--r--runtime/doc/tags1
-rw-r--r--runtime/doc/usr_41.txt2
-rw-r--r--runtime/doc/version9.txt4
-rw-r--r--src/evalfunc.c37
-rw-r--r--src/testdir/test_listdict.vim30
-rw-r--r--src/version.c2
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,