Merge pull request #13064 from janlazo/vim-8.1.2325

vim-patch:8.1.{1683,1686,1692,1705,2325},8.2.1599
This commit is contained in:
Jan Edmund Lazo 2020-10-07 17:58:38 -04:00 committed by GitHub
commit 8ba5f4d19c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 128 additions and 13 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 with #{}.
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

@ -3802,8 +3802,9 @@ static int eval6(char_u **arg, typval_T *rettv, int evaluate, int want_string)
*/ */
for (;; ) { for (;; ) {
op = **arg; op = **arg;
if (op != '*' && op != '/' && op != '%') if (op != '*' && op != '/' && op != '%') {
break; break;
}
if (evaluate) { if (evaluate) {
if (rettv->v_type == VAR_FLOAT) { if (rettv->v_type == VAR_FLOAT) {
@ -3905,6 +3906,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 +4014,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 +5359,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 +5417,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

@ -808,7 +808,7 @@ retry:
} }
break; break;
} }
if (STRLEN(IObuff) < IOSIZE - 1 || IObuff[IOSIZE - 1] == '\n') { if (STRLEN(IObuff) < IOSIZE - 1 || IObuff[IOSIZE - 2] == '\n') {
break; break;
} }
} }

View File

@ -280,6 +280,14 @@ 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},)
" why *{} cannot be used
let blue = 'blue'
call assert_equal('6', trim(execute('echo 2 *{blue: 3}.blue')))
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}

View File

@ -2,6 +2,7 @@
source shared.vim source shared.vim
source screendump.vim source screendump.vim
source check.vim
let g:months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'] let g:months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
let g:setting = '' let g:setting = ''
@ -755,6 +756,52 @@ func Test_popup_and_previewwindow_dump()
call delete('Xscript') call delete('Xscript')
endfunc endfunc
func Test_balloon_split()
CheckFunction balloon_split
call assert_equal([
\ 'tempname: 0x555555e380a0 "/home/mool/.viminfz.tmp"',
\ ], balloon_split(
\ 'tempname: 0x555555e380a0 "/home/mool/.viminfz.tmp"'))
call assert_equal([
\ 'one two three four one two three four one two thre',
\ 'e four',
\ ], balloon_split(
\ 'one two three four one two three four one two three four'))
eval 'struct = {one = 1, two = 2, three = 3}'
\ ->balloon_split()
\ ->assert_equal([
\ 'struct = {',
\ ' one = 1,',
\ ' two = 2,',
\ ' three = 3}',
\ ])
call assert_equal([
\ 'struct = {',
\ ' one = 1,',
\ ' nested = {',
\ ' n1 = "yes",',
\ ' n2 = "no"}',
\ ' two = 2}',
\ ], balloon_split(
\ 'struct = {one = 1, nested = {n1 = "yes", n2 = "no"} two = 2}'))
call assert_equal([
\ 'struct = 0x234 {',
\ ' long = 2343 "\\"some long string that will be wr',
\ 'apped in two\\"",',
\ ' next = 123}',
\ ], balloon_split(
\ 'struct = 0x234 {long = 2343 "\\"some long string that will be wrapped in two\\"", next = 123}'))
call assert_equal([
\ 'Some comment',
\ '',
\ 'typedef this that;',
\ ], balloon_split(
\ "Some comment\n\ntypedef this that;"))
endfunc
func Test_popup_position() func Test_popup_position()
if !CanRunVimInTerminal() if !CanRunVimInTerminal()
return return

View File

@ -1597,6 +1597,24 @@ func Test_long_lines()
call s:long_lines_tests('l') call s:long_lines_tests('l')
endfunc endfunc
func Test_cgetfile_on_long_lines()
" Problematic values if the line is longer than 4096 bytes. Then 1024 bytes
" are read at a time.
for len in [4078, 4079, 4080, 5102, 5103, 5104, 6126, 6127, 6128, 7150, 7151, 7152]
let lines = [
\ '/tmp/file1:1:1:aaa',
\ '/tmp/file2:1:1:%s',
\ '/tmp/file3:1:1:bbb',
\ '/tmp/file4:1:1:ccc',
\ ]
let lines[1] = substitute(lines[1], '%s', repeat('x', len), '')
call writefile(lines, 'Xcqetfile.txt')
cgetfile Xcqetfile.txt
call assert_equal(4, getqflist(#{size: v:true}).size, 'with length ' .. len)
endfor
call delete('Xcqetfile.txt')
endfunc
func s:create_test_file(filename) func s:create_test_file(filename)
let l = [] let l = []
for i in range(1, 20) for i in range(1, 20)