diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/ex_docmd.c | 20 | ||||
-rw-r--r-- | src/nvim/ex_getln.c | 28 | ||||
-rw-r--r-- | src/nvim/memline.c | 1 | ||||
-rw-r--r-- | src/nvim/quickfix.c | 11 | ||||
-rw-r--r-- | src/nvim/regexp.c | 1 | ||||
-rw-r--r-- | src/nvim/search.c | 44 | ||||
-rw-r--r-- | src/nvim/testdir/test_quickfix.vim | 16 | ||||
-rw-r--r-- | src/nvim/testdir/test_search.vim | 77 | ||||
-rw-r--r-- | src/nvim/testdir/test_search_stat.vim | 30 |
9 files changed, 182 insertions, 46 deletions
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index dfebd13868..60b017be28 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -2228,17 +2228,19 @@ int parse_command_modifiers(exarg_T *eap, char_u **errormsg, bool skip_only) continue; case 't': if (checkforcmd(&p, "tab", 3)) { - long tabnr = get_address( - eap, &eap->cmd, ADDR_TABS, eap->skip, skip_only, false, 1); + if (!skip_only) { + long tabnr = get_address( + eap, &eap->cmd, ADDR_TABS, eap->skip, skip_only, false, 1); - if (tabnr == MAXLNUM) { - cmdmod.tab = tabpage_index(curtab) + 1; - } else { - if (tabnr < 0 || tabnr > LAST_TAB_NR) { - *errormsg = (char_u *)_(e_invrange); - return false; + if (tabnr == MAXLNUM) { + cmdmod.tab = tabpage_index(curtab) + 1; + } else { + if (tabnr < 0 || tabnr > LAST_TAB_NR) { + *errormsg = (char_u *)_(e_invrange); + return false; + } + cmdmod.tab = tabnr + 1; } - cmdmod.tab = tabnr + 1; } eap->cmd = p; continue; diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index c966c780a0..8f2d536e63 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -276,6 +276,7 @@ static void init_incsearch_state(incsearch_state_T *s) // Sets search_first_line and search_last_line to the address range. static bool do_incsearch_highlighting(int firstc, incsearch_state_T *s, int *skiplen, int *patlen) + FUNC_ATTR_NONNULL_ALL { char_u *cmd; cmdmod_T save_cmdmod = cmdmod; @@ -443,6 +444,10 @@ static void may_do_incsearch_highlighting(int firstc, long count, if (search_first_line == 0) { // start at the original cursor position curwin->w_cursor = s->search_start; + } else if (search_first_line > curbuf->b_ml.ml_line_count) { + // start after the last line + curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; + curwin->w_cursor.col = MAXCOL; } else { // start at the first line in the range curwin->w_cursor.lnum = search_first_line; @@ -563,6 +568,7 @@ static void may_do_incsearch_highlighting(int firstc, long count, // May set "*c" to the added character. // Return OK when calling command_line_not_changed. static int may_add_char_to_search(int firstc, int *c, incsearch_state_T *s) + FUNC_ATTR_NONNULL_ALL { int skiplen, patlen; @@ -579,8 +585,8 @@ static int may_add_char_to_search(int firstc, int *c, incsearch_state_T *s) if (s->did_incsearch) { curwin->w_cursor = s->match_end; - if (!equalpos(curwin->w_cursor, s->search_start)) { - *c = gchar_cursor(); + *c = gchar_cursor(); + if (*c != NUL) { // If 'ignorecase' and 'smartcase' are set and the // command line has no uppercase characters, convert // the character to lowercase @@ -588,16 +594,14 @@ static int may_add_char_to_search(int firstc, int *c, incsearch_state_T *s) && !pat_has_uppercase(ccline.cmdbuff + skiplen)) { *c = mb_tolower(*c); } - if (*c != NUL) { - if (*c == firstc - || vim_strchr((char_u *)(p_magic ? "\\~^$.*[" : "\\^$"), *c) - != NULL) { - // put a backslash before special characters - stuffcharReadbuff(*c); - *c = '\\'; - } - return FAIL; + if (*c == firstc + || vim_strchr((char_u *)(p_magic ? "\\~^$.*[" : "\\^$"), *c) + != NULL) { + // put a backslash before special characters + stuffcharReadbuff(*c); + *c = '\\'; } + return FAIL; } } return OK; @@ -1444,6 +1448,7 @@ static int command_line_execute(VimState *state, int key) static int may_do_command_line_next_incsearch(int firstc, long count, incsearch_state_T *s, bool next_match) + FUNC_ATTR_NONNULL_ALL { int skiplen, patlen; @@ -1537,6 +1542,7 @@ static int may_do_command_line_next_incsearch(int firstc, long count, save_viewstate(&s->old_viewstate); update_screen(NOT_VALID); redrawcmdline(); + curwin->w_cursor = s->match_end; } else { vim_beep(BO_ERROR); } diff --git a/src/nvim/memline.c b/src/nvim/memline.c index f9390bcb88..2a75f13cc2 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -1818,6 +1818,7 @@ ml_get_buf ( linenr_T lnum, bool will_change // line will be changed ) + FUNC_ATTR_NONNULL_ALL { bhdr_T *hp; DATA_BL *dp; diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index ddce1e922d..5754950745 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -901,6 +901,7 @@ static bool qf_list_has_valid_entries(qf_list_T *qfl) /// Return a pointer to a list in the specified quickfix stack static qf_list_T * qf_get_list(qf_info_T *qi, int idx) + FUNC_ATTR_NONNULL_ALL { return &qi->qf_lists[idx]; } @@ -1230,6 +1231,7 @@ static char_u * qf_cmdtitle(char_u *cmd) /// Return a pointer to the current list in the specified quickfix stack static qf_list_T * qf_get_curlist(qf_info_T *qi) + FUNC_ATTR_NONNULL_ALL { return qf_get_list(qi, qi->qf_curlist); } @@ -4825,12 +4827,13 @@ static bool vgr_qflist_valid(win_T *wp, qf_info_T *qi, unsigned qfid, /// Search for a pattern in all the lines in a buffer and add the matching lines /// to a quickfix list. static bool vgr_match_buflines(qf_info_T *qi, char_u *fname, buf_T *buf, - regmmatch_T *regmatch, long tomatch, + regmmatch_T *regmatch, long *tomatch, int duplicate_name, int flags) + FUNC_ATTR_NONNULL_ARG(1, 3, 4, 5) { bool found_match = false; - for (long lnum = 1; lnum <= buf->b_ml.ml_line_count && tomatch > 0; lnum++) { + for (long lnum = 1; lnum <= buf->b_ml.ml_line_count && *tomatch > 0; lnum++) { colnr_T col = 0; while (vim_regexec_multi(regmatch, curwin, buf, lnum, col, NULL, NULL) > 0) { @@ -4856,7 +4859,7 @@ static bool vgr_match_buflines(qf_info_T *qi, char_u *fname, buf_T *buf, break; } found_match = true; - if (--tomatch == 0) { + if (--*tomatch == 0) { break; } if ((flags & VGR_GLOBAL) == 0 || regmatch->endpos[0].lnum > 0) { @@ -5030,7 +5033,7 @@ void ex_vimgrep(exarg_T *eap) } else { // Try for a match in all lines of the buffer. // For ":1vimgrep" look for first match only. - found_match = vgr_match_buflines(qi, fname, buf, ®match, tomatch, + found_match = vgr_match_buflines(qi, fname, buf, ®match, &tomatch, duplicate_name, flags); if (using_dummy) { diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c index bcf02af4ef..a570328499 100644 --- a/src/nvim/regexp.c +++ b/src/nvim/regexp.c @@ -7387,6 +7387,7 @@ long vim_regexec_multi( proftime_T *tm, // timeout limit or NULL int *timed_out // flag is set when timeout limit reached ) + FUNC_ATTR_NONNULL_ARG(1) { regexec_T rex_save; bool rex_in_use_save = rex_in_use; diff --git a/src/nvim/search.c b/src/nvim/search.c index 23d84038d6..517db05a40 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -96,12 +96,8 @@ static int lastc_bytelen = 1; // >1 for multi-byte char // copy of spats[], for keeping the search patterns while executing autocmds static struct spat saved_spats[2]; -// copy of spats[RE_SEARCH], for keeping the search patterns while incremental -// searching -static struct spat saved_last_search_spat; -static int did_save_last_search_spat = 0; -static int saved_last_idx = 0; -static bool saved_no_hlsearch = false; +static int saved_spats_last_idx = 0; +static bool saved_spats_no_hlsearch = false; static char_u *mr_pattern = NULL; // pattern used by search_regcomp() static int mr_pattern_alloced = false; // mr_pattern was allocated @@ -268,8 +264,8 @@ void save_search_patterns(void) saved_spats[1] = spats[1]; if (spats[1].pat != NULL) saved_spats[1].pat = vim_strsave(spats[1].pat); - saved_last_idx = last_idx; - saved_no_hlsearch = no_hlsearch; + saved_spats_last_idx = last_idx; + saved_spats_no_hlsearch = no_hlsearch; } } @@ -281,8 +277,8 @@ void restore_search_patterns(void) set_vv_searchforward(); free_spat(&spats[1]); spats[1] = saved_spats[1]; - last_idx = saved_last_idx; - set_no_hlsearch(saved_no_hlsearch); + last_idx = saved_spats_last_idx; + set_no_hlsearch(saved_spats_no_hlsearch); } } @@ -309,6 +305,13 @@ void free_search_patterns(void) #endif +// copy of spats[RE_SEARCH], for keeping the search patterns while incremental +// searching +static struct spat saved_last_search_spat; +static int did_save_last_search_spat = 0; +static int saved_last_idx = 0; +static bool saved_no_hlsearch = false; + /// Save and restore the search pattern for incremental highlight search /// feature. /// @@ -317,10 +320,9 @@ void free_search_patterns(void) /// cancelling incremental searching even if it's called inside user functions. void save_last_search_pattern(void) { - if (did_save_last_search_spat != 0) { - IEMSG("did_save_last_search_spat is not zero"); - } else { - did_save_last_search_spat++; + if (++did_save_last_search_spat != 1) { + // nested call, nothing to do + return; } saved_last_search_spat = spats[RE_SEARCH]; @@ -333,11 +335,15 @@ void save_last_search_pattern(void) void restore_last_search_pattern(void) { - if (did_save_last_search_spat != 1) { - IEMSG("did_save_last_search_spat is not one"); + if (--did_save_last_search_spat > 0) { + // nested call, nothing to do + return; + } + if (did_save_last_search_spat != 0) { + iemsg("restore_last_search_pattern() called more often than" + " save_last_search_pattern()"); return; } - did_save_last_search_spat--; xfree(spats[RE_SEARCH].pat); spats[RE_SEARCH] = saved_last_search_spat; @@ -488,7 +494,7 @@ void set_last_search_pat(const char_u *s, int idx, int magic, int setlast) saved_spats[idx].pat = NULL; else saved_spats[idx].pat = vim_strsave(spats[idx].pat); - saved_last_idx = last_idx; + saved_spats_last_idx = last_idx; } /* If 'hlsearch' set and search pat changed: need redraw. */ if (p_hls && idx == last_idx && !no_hlsearch) @@ -1179,7 +1185,7 @@ int do_search( } if (*searchstr == NUL) { - p = spats[last_idx].pat; + p = spats[0].pat; } else { p = searchstr; } diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim index 926103b69f..eeec5bd2c3 100644 --- a/src/nvim/testdir/test_quickfix.vim +++ b/src/nvim/testdir/test_quickfix.vim @@ -2450,6 +2450,22 @@ func Test_vimgrep() call XvimgrepTests('l') endfunc +" Test for incsearch highlighting of the :vimgrep pattern +" This test used to cause "E315: ml_get: invalid lnum" errors. +func Test_vimgrep_incsearch() + throw 'skipped: Nvim does not support test_override()' + enew + set incsearch + call test_override("char_avail", 1) + + call feedkeys(":2vimgrep assert test_quickfix.vim test_cdo.vim\<CR>", "ntx") + let l = getqflist() + call assert_equal(2, len(l)) + + call test_override("ALL", 0) + set noincsearch +endfunc + func XfreeTests(cchar) call s:setup_commands(a:cchar) diff --git a/src/nvim/testdir/test_search.vim b/src/nvim/testdir/test_search.vim index 767cf99be3..e3a0fce5a6 100644 --- a/src/nvim/testdir/test_search.vim +++ b/src/nvim/testdir/test_search.vim @@ -244,6 +244,10 @@ func Test_search_cmdline2() " go to previous match (on line 2) call feedkeys("/the\<C-G>\<C-G>\<C-G>\<C-T>\<C-T>\<C-T>\<cr>", 'tx') call assert_equal(' 2 these', getline('.')) + 1 + " go to previous match (on line 2) + call feedkeys("/the\<C-G>\<C-R>\<C-W>\<cr>", 'tx') + call assert_equal('theother', @/) " Test 2: keep the view, " after deleting a character from the search cmd @@ -255,7 +259,7 @@ func Test_search_cmdline2() call assert_equal({'lnum': 10, 'leftcol': 0, 'col': 4, 'topfill': 0, 'topline': 6, 'coladd': 0, 'skipcol': 0, 'curswant': 4}, winsaveview()) " remove all history entries - for i in range(10) + for i in range(11) call histdel('/') endfor @@ -489,14 +493,14 @@ func Test_search_cmdline5() " Do not call test_override("char_avail", 1) so that <C-g> and <C-t> work " regardless char_avail. new - call setline(1, [' 1 the first', ' 2 the second', ' 3 the third']) + call setline(1, [' 1 the first', ' 2 the second', ' 3 the third', '']) set incsearch 1 call feedkeys("/the\<c-g>\<c-g>\<cr>", 'tx') call assert_equal(' 3 the third', getline('.')) $ call feedkeys("?the\<c-t>\<c-t>\<c-t>\<cr>", 'tx') - call assert_equal(' 2 the second', getline('.')) + call assert_equal(' 1 the first', getline('.')) " clean up set noincsearch bw! @@ -861,6 +865,21 @@ func Test_incsearch_with_change() call delete('Xis_change_script') endfunc +func Test_incsearch_cmdline_modifier() + throw 'skipped: Nvim does not support test_override()' + if !exists('+incsearch') + return + endif + call test_override("char_avail", 1) + new + call setline(1, ['foo']) + set incsearch + " Test that error E14 does not occur in parsing command modifier. + call feedkeys("V:tab", 'tx') + + call Incsearch_cleanup() +endfunc + func Test_incsearch_scrolling() if !CanRunVimInTerminal() return @@ -982,6 +1001,40 @@ func Test_search_sentence() / endfunc +" Test that there is no crash when there is a last search pattern but no last +" substitute pattern. +func Test_no_last_substitute_pat() + " Use viminfo to set the last search pattern to a string and make the last + " substitute pattern the most recent used and make it empty (NULL). + call writefile(['~MSle0/bar', '~MSle0~&'], 'Xviminfo') + rviminfo! Xviminfo + call assert_fails('normal n', 'E35:') + + call delete('Xviminfo') +endfunc + +func Test_search_Ctrl_L_combining() + " Make sure, that Ctrl-L works correctly with combining characters. + " It uses an artificial example of an 'a' with 4 combining chars: + " 'a' U+0061 Dec:97 LATIN SMALL LETTER A a /\%u61\Z "\u0061" + " ' ̀' U+0300 Dec:768 COMBINING GRAVE ACCENT ̀ /\%u300\Z "\u0300" + " ' ́' U+0301 Dec:769 COMBINING ACUTE ACCENT ́ /\%u301\Z "\u0301" + " ' ̇' U+0307 Dec:775 COMBINING DOT ABOVE ̇ /\%u307\Z "\u0307" + " ' ̣' U+0323 Dec:803 COMBINING DOT BELOW ̣ /\%u323 "\u0323" + " Those should also appear on the commandline + if !has('multi_byte') || !exists('+incsearch') + return + endif + call Cmdline3_prep() + 1 + let bufcontent = ['', 'Miạ̀́̇m'] + call append('$', bufcontent) + call feedkeys("/Mi\<c-l>\<c-l>\<cr>", 'tx') + call assert_equal(5, line('.')) + call assert_equal(bufcontent[1], @/) + call Incsearch_cleanup() +endfunc + func Test_large_hex_chars1() " This used to cause a crash, the character becomes an NFA state. try @@ -1019,6 +1072,24 @@ func Test_one_error_msg() call assert_fails('call search(" \\((\\v[[=P=]]){185}+ ")', 'E871:') endfunc +func Test_incsearch_add_char_under_cursor() + throw 'skipped: Nvim does not support test_override()' + if !exists('+incsearch') + return + endif + set incsearch + new + call setline(1, ['find match', 'anything']) + 1 + call test_override('char_avail', 1) + call feedkeys("fc/m\<C-L>\<C-L>\<C-L>\<C-L>\<C-L>\<CR>", 'tx') + call assert_equal('match', @/) + call test_override('char_avail', 0) + + set incsearch& + bwipe! +endfunc + " Test for the search() function with match at the cursor position func Test_search_match_at_curpos() new diff --git a/src/nvim/testdir/test_search_stat.vim b/src/nvim/testdir/test_search_stat.vim index cf36f3214a..fa620b4e00 100644 --- a/src/nvim/testdir/test_search_stat.vim +++ b/src/nvim/testdir/test_search_stat.vim @@ -4,6 +4,8 @@ " as test! source shared.vim +source screendump.vim +source check.vim func! Test_search_stat() new @@ -164,3 +166,31 @@ func! Test_search_stat() set shortmess+=S bwipe! endfunc + +func Test_searchcount_in_statusline() + CheckScreendump + + let lines =<< trim END + set shortmess-=S + call append(0, 'this is something') + function TestSearchCount() abort + let search_count = searchcount() + if !empty(search_count) + return '[' . search_count.current . '/' . search_count.total . ']' + else + return '' + endif + endfunction + set hlsearch + set laststatus=2 statusline+=%{TestSearchCount()} + END + call writefile(lines, 'Xsearchstatusline') + let buf = RunVimInTerminal('-S Xsearchstatusline', #{rows: 10}) + call TermWait(buf) + call term_sendkeys(buf, "/something") + call VerifyScreenDump(buf, 'Test_searchstat_4', {}) + + call term_sendkeys(buf, "\<Esc>") + call StopVimInTerminal(buf) + call delete('Xsearchstatusline') +endfunc |