mirror of
https://github.com/neovim/neovim.git
synced 2026-08-29 18:41:48 +00:00
Merge pull request #12905 from janlazo/vim-8.1.0555
vim-patch:8.1.{499,555,556,584,640,1148,1704},8.2.0902
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user