Mercurial > vim
changeset 35609:78815577abdc v9.1.0548
patch 9.1.0548: it's not possible to get a unique id for some vars
Commit: https://github.com/vim/vim/commit/c8e158be0eb0f2f8d6c04ea5de64318a33fd3d02
Author: Ernie Rael <errael@raelity.com>
Date: Tue Jul 9 18:39:52 2024 +0200
patch 9.1.0548: it's not possible to get a unique id for some vars
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>
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Tue, 09 Jul 2024 18:45:09 +0200 |
parents | 6668a62a81c4 |
children | 67b988dc2646 |
files | runtime/doc/builtin.txt runtime/doc/tags runtime/doc/usr_41.txt runtime/doc/version9.txt src/evalfunc.c src/testdir/test_listdict.vim src/version.c |
diffstat | 7 files changed, 104 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/runtime/doc/builtin.txt +++ b/runtime/doc/builtin.txt @@ -309,6 +309,7 @@ hlget([{name} [, {resolve}]]) List get h 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
--- 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*
--- 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|)
--- 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
--- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -82,6 +82,7 @@ static void f_haslocaldir(typval_T *argv 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, typ } /* + * "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
--- 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