From fa1e740e60989134d5e6d623d687c1fd7c57909c Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Tue, 6 Oct 2020 23:45:06 -0400 Subject: [PATCH 1/6] vim-patch:8.1.2325: crash when using balloon with empty line Problem: Crash when using balloon with empty line. Solution: Handle empty lines. (Markus Braun) https://github.com/vim/vim/commit/9ae862ebba4a8962cb1c6811a2a46656fa672599 Port Test_balloon_split() from patch 8.0.1318 for merging only. It won't run because of the function check. --- src/nvim/testdir/test_popup.vim | 47 +++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/nvim/testdir/test_popup.vim b/src/nvim/testdir/test_popup.vim index bb0ed6e00c..fb464d95ea 100644 --- a/src/nvim/testdir/test_popup.vim +++ b/src/nvim/testdir/test_popup.vim @@ -2,6 +2,7 @@ source shared.vim source screendump.vim +source check.vim let g:months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'] let g:setting = '' @@ -755,6 +756,52 @@ func Test_popup_and_previewwindow_dump() call delete('Xscript') 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() if !CanRunVimInTerminal() return From 7ca5dc2519018c33def6bd6361d26099df04e7e2 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Wed, 7 Oct 2020 00:03:12 -0400 Subject: [PATCH 2/6] 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. https://github.com/vim/vim/commit/d5abb4c87727eecb71b0e8ffdda60fc9598272f3 Vim's popup,textprop features are N/A. Neovim has not polyfilled their APIs. Skip docs and tests for these features. --- runtime/doc/eval.txt | 14 +++++++-- src/nvim/eval.c | 49 +++++++++++++++++++++++++----- 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} From d109a331446a998671bf54655df99238e2f1b093 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Wed, 7 Oct 2020 00:40:33 -0400 Subject: [PATCH 3/6] vim-patch:8.1.1686: "*" of "*{" is recognized as multipy operator Problem: "*" of "*{" is recognized as multipy operator. (Yasuhiro Matsumoto) Solution: Check for the "{". https://github.com/vim/vim/commit/2898ebb44cee62a70a11b44a97bdad8cc00157b1 --- src/nvim/eval.c | 3 ++- src/nvim/testdir/test_listdict.vim | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 70549b950d..16d51d3a81 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -3802,8 +3802,9 @@ static int eval6(char_u **arg, typval_T *rettv, int evaluate, int want_string) */ for (;; ) { op = **arg; - if (op != '*' && op != '/' && op != '%') + if ((op != '*' || (*arg)[1] == '{') && op != '/' && op != '%') { break; + } if (evaluate) { if (rettv->v_type == VAR_FLOAT) { diff --git a/src/nvim/testdir/test_listdict.vim b/src/nvim/testdir/test_listdict.vim index 7b11885cc0..95f1d264ea 100644 --- a/src/nvim/testdir/test_listdict.vim +++ b/src/nvim/testdir/test_listdict.vim @@ -282,6 +282,7 @@ 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},) + call assert_equal('2 3', trim(execute('echo 2 *{blue: 3}.blue'))) endfunc " Nasty: deepcopy() dict that refers to itself (fails when noref used) From 20fc7ef161f3c40b957ba81a751af4639cce7776 Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Wed, 7 Oct 2020 00:45:05 -0400 Subject: [PATCH 4/6] vim-patch:8.1.1692: using *{} for literal dict is not backwards compatible Problem: Using *{} for literal dict is not backwards compatible. (Yasuhiro Matsumoto) Solution: Use ~{} instead. https://github.com/vim/vim/commit/b8be54dcc517c9d57b62409945b7d4b90b6c3071 --- runtime/doc/eval.txt | 6 +++--- src/nvim/eval.c | 8 ++++---- src/nvim/testdir/test_listdict.vim | 7 +++++-- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index e8c9233a1a..5b4c202215 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -40,7 +40,7 @@ Dictionary An associative, unordered array: Each entry has a key and a value. |Dictionary| Examples: {'blue': "#0000ff", 'red': "#ff0000"} - *{blue: "#0000ff", red: "#ff0000"} + ~{blue: "#0000ff", red: "#ff0000"} The Number and String types are converted automatically, depending on how they are used. @@ -441,10 +441,10 @@ 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 also be used as a key. *literal-Dict* -To avoid having to put quotes around every key the *{} form can be used. This +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} + 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 diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 16d51d3a81..a4594d9ac8 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -3802,7 +3802,7 @@ static int eval6(char_u **arg, typval_T *rettv, int evaluate, int want_string) */ for (;; ) { op = **arg; - if ((op != '*' || (*arg)[1] == '{') && op != '/' && op != '%') { + if (op != '*' && op != '/' && op != '%') { break; } @@ -3906,7 +3906,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 +// ~{key: val, key: val} Dictionary with literal keys // // Also handle: // ! in front logical NOT @@ -4014,8 +4014,8 @@ static int eval7( case '[': ret = get_list_tv(arg, rettv, evaluate); break; - // Dictionary: *{key: val, key: val} - case '*': + // Dictionary: ~{key: val, key: val} + case '~': if ((*arg)[1] == '{') { (*arg)++; ret = dict_get_tv(arg, rettv, evaluate, true); diff --git a/src/nvim/testdir/test_listdict.vim b/src/nvim/testdir/test_listdict.vim index 95f1d264ea..28cbceef9a 100644 --- a/src/nvim/testdir/test_listdict.vim +++ b/src/nvim/testdir/test_listdict.vim @@ -281,8 +281,11 @@ func Test_dict_func_remove_in_use() 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},) - call assert_equal('2 3', trim(execute('echo 2 *{blue: 3}.blue'))) + 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) From 4a6e201e37a9b08860cb823c528ea062002b7ebc Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Wed, 7 Oct 2020 01:00:11 -0400 Subject: [PATCH 5/6] vim-patch:8.1.1705: using ~{} for a literal dict is not nice Problem: Using ~{} for a literal dict is not nice. Solution: Use #{} instead. https://github.com/vim/vim/commit/4c6d90458baae843463f930fdc3fe4a7a2191d27 --- runtime/doc/eval.txt | 8 ++++---- src/nvim/eval.c | 6 +++--- src/nvim/testdir/test_listdict.vim | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 5b4c202215..0f848d0c27 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -40,7 +40,7 @@ Dictionary An associative, unordered array: Each entry has a key and a value. |Dictionary| Examples: {'blue': "#0000ff", 'red': "#ff0000"} - ~{blue: "#0000ff", red: "#ff0000"} + #{blue: "#0000ff", red: "#ff0000"} The Number and String types are converted automatically, depending on how they are used. @@ -441,11 +441,11 @@ 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 also be used as a key. *literal-Dict* -To avoid having to put quotes around every key the ~{} form can be used. This +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. + 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 nested Dictionary: > diff --git a/src/nvim/eval.c b/src/nvim/eval.c index a4594d9ac8..a2490be355 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -3906,7 +3906,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 +// #{key: val, key: val} Dictionary with literal keys // // Also handle: // ! in front logical NOT @@ -4014,8 +4014,8 @@ static int eval7( case '[': ret = get_list_tv(arg, rettv, evaluate); break; - // Dictionary: ~{key: val, key: val} - case '~': + // Dictionary: #{key: val, key: val} + case '#': if ((*arg)[1] == '{') { (*arg)++; ret = dict_get_tv(arg, rettv, evaluate, true); diff --git a/src/nvim/testdir/test_listdict.vim b/src/nvim/testdir/test_listdict.vim index 28cbceef9a..31a8b48d37 100644 --- a/src/nvim/testdir/test_listdict.vim +++ b/src/nvim/testdir/test_listdict.vim @@ -281,7 +281,7 @@ func Test_dict_func_remove_in_use() 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},) + 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' From 670a577c6b7b6f950c738261937c2b6d55a7faec Mon Sep 17 00:00:00 2001 From: Jan Edmund Lazo Date: Tue, 6 Oct 2020 23:14:41 -0400 Subject: [PATCH 6/6] vim-patch:8.2.1599: missing line end when skipping a long line with :cgetfile Problem: Missing line end when skipping a long line with :cgetfile. Solution: Fix off-by-one error. (closes vim/vim#6870) https://github.com/vim/vim/commit/59941cbd8035415d68683edc4e571306b10669ad --- src/nvim/quickfix.c | 2 +- src/nvim/testdir/test_quickfix.vim | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 7d4f52af34..1fe301b0d9 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -808,7 +808,7 @@ retry: } break; } - if (STRLEN(IObuff) < IOSIZE - 1 || IObuff[IOSIZE - 1] == '\n') { + if (STRLEN(IObuff) < IOSIZE - 1 || IObuff[IOSIZE - 2] == '\n') { break; } } diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim index 42ca0fe1d3..520007a993 100644 --- a/src/nvim/testdir/test_quickfix.vim +++ b/src/nvim/testdir/test_quickfix.vim @@ -1597,6 +1597,24 @@ func Test_long_lines() call s:long_lines_tests('l') 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) let l = [] for i in range(1, 20)