diff --git a/src/nvim/eval.c b/src/nvim/eval.c index fd83bc846b..e08e129656 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -21742,22 +21742,31 @@ void ex_function(exarg_T *eap) } // Check for ":let v =<< [trim] EOF" + // and ":let [a, b] =<< [trim] EOF" arg = skipwhite(skiptowhite(p)); - arg = skipwhite(skiptowhite(arg)); - if (arg[0] == '=' && arg[1] == '<' && arg[2] =='<' - && ((p[0] == 'l' && p[1] == 'e' - && (!ASCII_ISALNUM(p[2]) - || (p[2] == 't' && !ASCII_ISALNUM(p[3])))))) { - p = skipwhite(arg + 3); - if (STRNCMP(p, "trim", 4) == 0) { - // Ignore leading white space. - p = skipwhite(p + 4); - heredoc_trimmed = vim_strnsave(theline, - (int)(skipwhite(theline) - theline)); + if (*arg == '[') { + arg = vim_strchr(arg, ']'); + } + if (arg != NULL) { + arg = skipwhite(skiptowhite(arg)); + if (arg[0] == '=' + && arg[1] == '<' + && arg[2] =='<' + && (p[0] == 'l' + && p[1] == 'e' + && (!ASCII_ISALNUM(p[2]) + || (p[2] == 't' && !ASCII_ISALNUM(p[3]))))) { + p = skipwhite(arg + 3); + if (STRNCMP(p, "trim", 4) == 0) { + // Ignore leading white space. + p = skipwhite(p + 4); + heredoc_trimmed = + vim_strnsave(theline, (int)(skipwhite(theline) - theline)); + } + skip_until = vim_strnsave(p, (int)(skiptowhite(p) - p)); + do_concat = false; + is_heredoc = true; } - skip_until = vim_strnsave(p, (int)(skiptowhite(p) - p)); - do_concat = false; - is_heredoc = true; } } diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index d3e2120721..7d02623d67 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -10156,7 +10156,7 @@ static void ex_folddo(exarg_T *eap) bool is_loclist_cmd(int cmdidx) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { - if (cmdidx < 0 || cmdidx > CMD_SIZE) { + if (cmdidx < 0 || cmdidx >= CMD_SIZE) { return false; } return cmdnames[cmdidx].cmd_name[0] == 'l'; diff --git a/src/nvim/misc1.c b/src/nvim/misc1.c index 1db8a1fa11..c1de7ab9a4 100644 --- a/src/nvim/misc1.c +++ b/src/nvim/misc1.c @@ -792,6 +792,8 @@ int prompt_for_number(int *mouse_used) cmdline_row = msg_row - 1; } need_wait_return = false; + msg_didany = false; + msg_didout = false; } else { cmdline_row = save_cmdline_row; } diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index cf5194d16f..da315252b5 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -1890,6 +1890,7 @@ static qf_info_T *qf_alloc_stack(qfltype_T qfltype) /// Return the location list stack for window 'wp'. /// If not present, allocate a location list stack static qf_info_T *ll_get_or_alloc_list(win_T *wp) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET { if (IS_LL_WINDOW(wp)) /* For a location list window, use the referenced location list */ @@ -1931,17 +1932,14 @@ static qf_info_T * qf_cmd_get_stack(exarg_T *eap, int print_emsg) /// Get the quickfix/location list stack to use for the specified Ex command. /// For a location list command, returns the stack for the current window. /// If the location list is not present, then allocates a new one. -/// Returns NULL if the allocation fails. For a location list command, sets -/// 'pwinp' to curwin. -static qf_info_T * qf_cmd_get_or_alloc_stack(exarg_T *eap, win_T **pwinp) +/// For a location list command, sets 'pwinp' to curwin. +static qf_info_T *qf_cmd_get_or_alloc_stack(const exarg_T *eap, win_T **pwinp) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET { qf_info_T *qi = &ql_info; if (is_loclist_cmd(eap->cmdidx)) { qi = ll_get_or_alloc_list(curwin); - if (qi == NULL) { - return NULL; - } *pwinp = curwin; } @@ -4968,7 +4966,6 @@ void ex_vimgrep(exarg_T *eap) char_u *s; char_u *p; int fi; - qf_info_T *qi; qf_list_T *qfl; win_T *wp = NULL; buf_T *buf; @@ -4994,10 +4991,7 @@ void ex_vimgrep(exarg_T *eap) } } - qi = qf_cmd_get_or_alloc_stack(eap, &wp); - if (qi == NULL) { - return; - } + qf_info_T *qi = qf_cmd_get_or_alloc_stack(eap, &wp); if (eap->addr_count > 0) tomatch = eap->line2; @@ -6304,7 +6298,6 @@ static int cbuffer_process_args(exarg_T *eap, void ex_cbuffer(exarg_T *eap) { buf_T *buf = NULL; - qf_info_T *qi; char_u *au_name = NULL; win_T *wp = NULL; char_u *qf_title; @@ -6320,10 +6313,7 @@ void ex_cbuffer(exarg_T *eap) } // Must come after autocommands. - qi = qf_cmd_get_or_alloc_stack(eap, &wp); - if (qi == NULL) { - return; - } + qf_info_T *qi = qf_cmd_get_or_alloc_stack(eap, &wp); if (cbuffer_process_args(eap, &buf, &line1, &line2) == FAIL) { return; @@ -6392,7 +6382,6 @@ static char_u * cexpr_get_auname(cmdidx_T cmdidx) /// ":lexpr {expr}", ":lgetexpr {expr}", ":laddexpr {expr}" command. void ex_cexpr(exarg_T *eap) { - qf_info_T *qi; char_u *au_name = NULL; win_T *wp = NULL; @@ -6404,10 +6393,7 @@ void ex_cexpr(exarg_T *eap) } } - qi = qf_cmd_get_or_alloc_stack(eap, &wp); - if (qi == NULL) { - return; - } + qf_info_T *qi = qf_cmd_get_or_alloc_stack(eap, &wp); /* Evaluate the expression. When the result is a string or a list we can * use it to fill the errorlist. */ diff --git a/src/nvim/search.c b/src/nvim/search.c index c4c8633ed9..d396e7551b 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -4037,9 +4037,6 @@ current_search( bool old_p_ws = p_ws; pos_T save_VIsual = VIsual; - /* wrapping should not occur */ - p_ws = false; - /* Correct cursor when 'selection' is exclusive */ if (VIsual_active && *p_sel == 'e' && lt(VIsual, curwin->w_cursor)) dec_cursor(); @@ -4063,8 +4060,7 @@ current_search( int zero_width = is_zero_width(spats[last_idx].pat, true, &curwin->w_cursor, FORWARD); if (zero_width == -1) { - p_ws = old_p_ws; - return FAIL; /* pattern not found */ + return FAIL; // pattern not found } /* @@ -4081,11 +4077,18 @@ current_search( } end_pos = pos; + // wrapping should not occur in the first round + if (i == 0) { + p_ws = false; + } + result = searchit(curwin, curbuf, &pos, &end_pos, (dir ? FORWARD : BACKWARD), spats[last_idx].pat, i ? count : 1, SEARCH_KEEP | flags, RE_SEARCH, NULL); + p_ws = old_p_ws; + // First search may fail, but then start searching from the // beginning of the file (cursor might be on the search match) // except when Visual mode is active, so that extending the visual @@ -4094,7 +4097,6 @@ current_search( curwin->w_cursor = orig_pos; if (VIsual_active) VIsual = save_VIsual; - p_ws = old_p_ws; return FAIL; } else if (i == 0 && !result) { if (forward) { // try again from start of buffer @@ -4110,8 +4112,6 @@ current_search( pos_T start_pos = pos; - p_ws = old_p_ws; - if (!VIsual_active) { VIsual = start_pos; } diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c index eeec5be120..4fac001bc5 100644 --- a/src/nvim/spellfile.c +++ b/src/nvim/spellfile.c @@ -265,6 +265,8 @@ // follow; never used in prefix tree #define BY_SPECIAL BY_FLAGS2 // highest special byte value +#define ZERO_FLAG 65009 // used when flag is zero: "0" + // Flags used in .spl file for soundsalike flags. #define SAL_F0LLOWUP 1 #define SAL_COLLAPSE 2 @@ -2783,6 +2785,7 @@ static unsigned affitem2flag(int flagtype, char_u *item, char_u *fname, int lnum } // Get one affix name from "*pp" and advance the pointer. +// Returns ZERO_FLAG for "0". // Returns zero for an error, still advances the pointer then. static unsigned get_affitem(int flagtype, char_u **pp) { @@ -2794,6 +2797,9 @@ static unsigned get_affitem(int flagtype, char_u **pp) return 0; } res = getdigits_int(pp, true, 0); + if (res == 0) { + res = ZERO_FLAG; + } } else { res = mb_ptr2char_adv((const char_u **)pp); if (flagtype == AFT_LONG || (flagtype == AFT_CAPLONG @@ -2915,10 +2921,15 @@ static bool flag_in_afflist(int flagtype, char_u *afflist, unsigned flag) int digits = getdigits_int(&p, true, 0); assert(digits >= 0); n = (unsigned int)digits; - if (n == flag) + if (n == 0) { + n = ZERO_FLAG; + } + if (n == flag) { return true; - if (*p != NUL) // skip over comma - ++p; + } + if (*p != NUL) { // skip over comma + p++; + } } break; } diff --git a/src/nvim/testdir/test_gf.vim b/src/nvim/testdir/test_gf.vim index accd21e9a3..d301874891 100644 --- a/src/nvim/testdir/test_gf.vim +++ b/src/nvim/testdir/test_gf.vim @@ -99,3 +99,28 @@ func Test_gf() call delete('Xtest1') call delete('Xtestgf') endfunc + +func Test_gf_visual() + call writefile([], "Xtest_gf_visual") + new + call setline(1, 'XXXtest_gf_visualXXX') + set hidden + + " Visually select Xtest_gf_visual and use gf to go to that file + norm! ttvtXgf + call assert_equal('Xtest_gf_visual', bufname('%')) + + bwipe! + call delete('Xtest_gf_visual') + set hidden& +endfunc + +func Test_gf_error() + new + call assert_fails('normal gf', 'E446:') + call assert_fails('normal gF', 'E446:') + call setline(1, '/doesnotexist') + call assert_fails('normal gf', 'E447:') + call assert_fails('normal gF', 'E447:') + bwipe! +endfunc diff --git a/src/nvim/testdir/test_gn.vim b/src/nvim/testdir/test_gn.vim index 834397126f..d41675be0c 100644 --- a/src/nvim/testdir/test_gn.vim +++ b/src/nvim/testdir/test_gn.vim @@ -136,8 +136,9 @@ func Test_gn_command() call assert_equal(['ABCDEFGHi'], getline(1,'$')) call setline('.', ['abcdefghi']) let @/ = 'b' + " this gn wraps around the end of the file exe "norm! 0fhvhhgngU" - call assert_equal(['abcdefghi'], getline(1,'$')) + call assert_equal(['aBCDEFGHi'], getline(1,'$')) sil! %d _ call setline('.', ['abcdefghi']) let @/ = 'f' diff --git a/src/nvim/testdir/test_let.vim b/src/nvim/testdir/test_let.vim index 1fce3d6937..3c0fefbd25 100644 --- a/src/nvim/testdir/test_let.vim +++ b/src/nvim/testdir/test_let.vim @@ -141,6 +141,11 @@ func Test_let_varg_fail() call s:set_varg8([0]) endfunction +func Test_let_utf8_environment() + let $a = 'ĀĒĪŌŪあいうえお' + call assert_equal('ĀĒĪŌŪあいうえお', $a) +endfunc + func Test_let_heredoc_fails() call assert_fails('let v =<< marker', 'E991:') @@ -284,4 +289,12 @@ E END endif call assert_equal([], check) + + " unpack assignment + let [a, b, c] =<< END + x + \y + z +END + call assert_equal([' x', ' \y', ' z'], [a, b, c]) endfunc diff --git a/src/nvim/testdir/test_spell.vim b/src/nvim/testdir/test_spell.vim index e49b5542fa..9dce87774b 100644 --- a/src/nvim/testdir/test_spell.vim +++ b/src/nvim/testdir/test_spell.vim @@ -283,9 +283,9 @@ func Test_zz_affix() \ ]) call LoadAffAndDic(g:test_data_aff7, g:test_data_dic7) - call RunGoodBad("meea1 meea\xE9 bar prebar barmeat prebarmeat leadprebar lead tail leadtail leadmiddletail", + call RunGoodBad("meea1 meezero meea\xE9 bar prebar barmeat prebarmeat leadprebar lead tail leadtail leadmiddletail", \ "bad: mee meea2 prabar probarmaat middle leadmiddle middletail taillead leadprobar", - \ ["bar", "barmeat", "lead", "meea1", "meea\xE9", "prebar", "prebarmeat", "tail"], + \ ["bar", "barmeat", "lead", "meea1", "meea\xE9", "meezero", "prebar", "prebarmeat", "tail"], \ [ \ ["bad", ["bar", "lead", "tail"]], \ ["mee", ["meea1", "meea\xE9", "bar"]], @@ -713,6 +713,9 @@ let g:test_data_aff7 = [ \"SFX 61003 Y 1", \"SFX 61003 0 meat .", \"", + \"SFX 0 Y 1", + \"SFX 0 0 zero .", + \"", \"SFX 391 Y 1", \"SFX 391 0 a1 .", \"", @@ -724,7 +727,7 @@ let g:test_data_aff7 = [ \ ] let g:test_data_dic7 = [ \"1234", - \"mee/391,111,9999", + \"mee/0,391,111,9999", \"bar/17,61003,123", \"lead/2", \"tail/123", diff --git a/src/nvim/testdir/test_vimscript.vim b/src/nvim/testdir/test_vimscript.vim index 3fcba4134e..d2f13ff072 100644 --- a/src/nvim/testdir/test_vimscript.vim +++ b/src/nvim/testdir/test_vimscript.vim @@ -1284,7 +1284,7 @@ func s:DoNothing() endfunc func Test_script_local_func() - set nocp viminfo+=nviminfo + set nocp nomore viminfo+=nviminfo new nnoremap _x :call DoNothing()call DoLast()delfunc DoNothingdelfunc DoLast