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 Dictionary An associative, unordered array: Each entry has a key and a
value. |Dictionary| 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 The Number and String types are converted automatically, depending on how they
are used. 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 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 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 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 Number will be converted to the String '4'. The empty string can also be used
key. 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 A value can be any expression. Using a Dictionary for a value creates a
nested Dictionary: > 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 // (expression) nested expression
// [expr, expr] List // [expr, expr] List
// {key: val, key: val} Dictionary // {key: val, key: val} Dictionary
// *{key: val, key: val} Dictionary with literal keys
// //
// Also handle: // Also handle:
// ! in front logical NOT // ! in front logical NOT
@@ -4012,11 +4013,21 @@ static int eval7(
case '[': ret = get_list_tv(arg, rettv, evaluate); case '[': ret = get_list_tv(arg, rettv, evaluate);
break; 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} // Lambda: {arg, arg -> expr}
// Dictionary: {key: val, key: val} // Dictionary: {'key': val, 'key': val}
case '{': ret = get_lambda_tv(arg, rettv, evaluate); case '{': ret = get_lambda_tv(arg, rettv, evaluate);
if (ret == NOTDONE) { if (ret == NOTDONE) {
ret = dict_get_tv(arg, rettv, evaluate); ret = dict_get_tv(arg, rettv, evaluate, false);
} }
break; break;
@@ -5347,11 +5358,31 @@ static inline bool set_ref_dict(dict_T *dict, int copyID)
return false; return false;
} }
/*
* Allocate a variable for a Dictionary and fill it from "*arg". // Get the key for *{key: val} into "tv" and advance "arg".
* Return OK or FAIL. Returns NOTDONE for {expr}. // Return FAIL when there is no valid key.
*/ static int get_literal_key(char_u **arg, typval_T *tv)
static int dict_get_tv(char_u **arg, typval_T *rettv, int evaluate) 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; dict_T *d = NULL;
typval_T tvkey; typval_T tvkey;
@@ -5385,7 +5416,9 @@ static int dict_get_tv(char_u **arg, typval_T *rettv, int evaluate)
*arg = skipwhite(*arg + 1); *arg = skipwhite(*arg + 1);
while (**arg != '}' && **arg != NUL) { 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; goto failret;
} }
if (**arg != ':') { 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')))) call assert_equal(expected, d.func(string(remove(d, 'func'))))
endfunc 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) " Nasty: deepcopy() dict that refers to itself (fails when noref used)
func Test_dict_deepcopy() func Test_dict_deepcopy()
let d = {1:1, 2:2} let d = {1:1, 2:2}