vim-patch:8.1.1683: dictionary with string keys is longer than needed

Problem:    Dictionary with string keys is longer than needed.
Solution:   Use *{key: val} for literaly keys.
d5abb4c877

Vim's popup,textprop features are N/A.
Neovim has not polyfilled their APIs.
Skip docs and tests for these features.
This commit is contained in:
Jan Edmund Lazo
2020-10-07 00:03:12 -04:00
parent fa1e740e60
commit 7ca5dc2519
3 changed files with 56 additions and 11 deletions

View File

@@ -38,7 +38,9 @@ List An ordered sequence of items |List|.
Dictionary An associative, unordered array: Each entry has a key and a
value. |Dictionary|
Example: {'blue': "#0000ff", 'red': "#ff0000"}
Examples:
{'blue': "#0000ff", 'red': "#ff0000"}
*{blue: "#0000ff", red: "#ff0000"}
The Number and String types are converted automatically, depending on how they
are used.
@@ -436,8 +438,14 @@ only appear once. Examples: >
A key is always a String. You can use a Number, it will be converted to a
String automatically. Thus the String '4' and the number 4 will find the same
entry. Note that the String '04' and the Number 04 are different, since the
Number will be converted to the String '4'. The empty string can be used as a
key.
Number will be converted to the String '4'. The empty string can also be used
as a key.
*literal-Dict*
To avoid having to put quotes around every key the *{} form can be used. This
does require the key to consist only of ASCII letters, digits, '-' and '_'.
Example: >
let mydict = *{zero: 0, one_key: 1, two-key: 2, 333: 3}
Note that 333 here is the string "333". Empty keys are not possible here.
A value can be any expression. Using a Dictionary for a value creates a
nested Dictionary: >

View File

@@ -3905,6 +3905,7 @@ static int eval6(char_u **arg, typval_T *rettv, int evaluate, int want_string)
// (expression) nested expression
// [expr, expr] List
// {key: val, key: val} Dictionary
// *{key: val, key: val} Dictionary with literal keys
//
// Also handle:
// ! in front logical NOT
@@ -4012,11 +4013,21 @@ static int eval7(
case '[': ret = get_list_tv(arg, rettv, evaluate);
break;
// Dictionary: *{key: val, key: val}
case '*':
if ((*arg)[1] == '{') {
(*arg)++;
ret = dict_get_tv(arg, rettv, evaluate, true);
} else {
ret = NOTDONE;
}
break;
// Lambda: {arg, arg -> expr}
// Dictionary: {key: val, key: val}
// Dictionary: {'key': val, 'key': val}
case '{': ret = get_lambda_tv(arg, rettv, evaluate);
if (ret == NOTDONE) {
ret = dict_get_tv(arg, rettv, evaluate);
ret = dict_get_tv(arg, rettv, evaluate, false);
}
break;
@@ -5347,11 +5358,31 @@ static inline bool set_ref_dict(dict_T *dict, int copyID)
return false;
}
/*
* Allocate a variable for a Dictionary and fill it from "*arg".
* Return OK or FAIL. Returns NOTDONE for {expr}.
*/
static int dict_get_tv(char_u **arg, typval_T *rettv, int evaluate)
// Get the key for *{key: val} into "tv" and advance "arg".
// Return FAIL when there is no valid key.
static int get_literal_key(char_u **arg, typval_T *tv)
FUNC_ATTR_NONNULL_ALL
{
char_u *p;
if (!ASCII_ISALNUM(**arg) && **arg != '_' && **arg != '-') {
return FAIL;
}
for (p = *arg; ASCII_ISALNUM(*p) || *p == '_' || *p == '-'; p++) {
}
tv->v_type = VAR_STRING;
tv->vval.v_string = vim_strnsave(*arg, (int)(p - *arg));
*arg = skipwhite(p);
return OK;
}
// Allocate a variable for a Dictionary and fill it from "*arg".
// "literal" is true for *{key: val}
// Return OK or FAIL. Returns NOTDONE for {expr}.
static int dict_get_tv(char_u **arg, typval_T *rettv, int evaluate,
bool literal)
{
dict_T *d = NULL;
typval_T tvkey;
@@ -5385,7 +5416,9 @@ static int dict_get_tv(char_u **arg, typval_T *rettv, int evaluate)
*arg = skipwhite(*arg + 1);
while (**arg != '}' && **arg != NUL) {
if (eval1(arg, &tvkey, evaluate) == FAIL) { // recursive!
if ((literal
? get_literal_key(arg, &tvkey)
: eval1(arg, &tvkey, evaluate)) == FAIL) { // recursive!
goto failret;
}
if (**arg != ':') {

View File

@@ -280,6 +280,10 @@ func Test_dict_func_remove_in_use()
call assert_equal(expected, d.func(string(remove(d, 'func'))))
endfunc
func Test_dict_literal_keys()
call assert_equal({'one': 1, 'two2': 2, '3three': 3, '44': 4}, *{one: 1, two2: 2, 3three: 3, 44: 4},)
endfunc
" Nasty: deepcopy() dict that refers to itself (fails when noref used)
func Test_dict_deepcopy()
let d = {1:1, 2:2}