diff options
-rw-r--r-- | runtime/doc/eval.txt | 14 | ||||
-rw-r--r-- | src/nvim/eval.c | 49 | ||||
-rw-r--r-- | src/nvim/testdir/test_listdict.vim | 4 |
3 files changed, 56 insertions, 11 deletions
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 5127a9f390..e8c9233a1a 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -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: > diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 24192dfefa..70549b950d 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -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 != ':') { diff --git a/src/nvim/testdir/test_listdict.vim b/src/nvim/testdir/test_listdict.vim index bea62cb0ad..7b11885cc0 100644 --- a/src/nvim/testdir/test_listdict.vim +++ b/src/nvim/testdir/test_listdict.vim @@ -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} |