patch 9.1.1535: the maximum search count uses hard-coded value 99

Problem:  The maximum search count uses a hard-coded value of 99
          (Andres Monge, Joschua Kesper)
Solution: Make it configurable using the 'maxsearchcount' option.

related: #8855
fixes: #17527
closes: #17695

Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
Christian Brabandt
2025-07-10 20:34:41 +02:00
parent bda2e4eb16
commit b7b7fa04bf
14 changed files with 259 additions and 45 deletions

View File

@ -4138,6 +4138,29 @@ did_set_scrollbind(optset_T *args UNUSED)
return NULL;
}
/*
* Process the new 'maxsearchcount' option value.
*/
char *
did_set_maxsearchcount(optset_T *args UNUSED)
{
char *errmsg = NULL;
// if you increase this, also increase SEARCH_STAT_BUF_LEN in search.c
#define MAX_SEARCH_COUNT 9999
if (p_msc <= 0)
errmsg = e_argument_must_be_positive;
else if (p_msc > MAX_SEARCH_COUNT)
errmsg = e_invalid_argument;
if (errmsg != NULL)
p_msc = 99;
return errmsg;
#undef MAX_SEARCH_COUNT
}
#if defined(BACKSLASH_IN_FILENAME) || defined(PROTO)
/*
* Process the updated 'shellslash' option value.

View File

@ -792,6 +792,7 @@ EXTERN long p_mmt; // 'maxmemtot'
EXTERN long p_mis; // 'menuitems'
#endif
EXTERN char_u *p_mopt; // 'messagesopt'
EXTERN long p_msc; // 'maxsearchcount'
#ifdef FEAT_SPELL
EXTERN char_u *p_msm; // 'mkspellmem'
#endif

View File

@ -1733,6 +1733,9 @@ static struct vimoption options[] =
(char_u *)&p_mmt, PV_NONE, NULL, NULL,
{(char_u *)DFLT_MAXMEMTOT, (char_u *)0L}
SCTX_INIT},
{"maxsearchcount", "msc", P_NUM|P_VI_DEF,
(char_u *)&p_msc, PV_NONE, did_set_maxsearchcount, NULL,
{(char_u *)99L, (char_u *)0L} SCTX_INIT},
{"menuitems", "mis", P_NUM|P_VI_DEF,
#ifdef FEAT_MENU
(char_u *)&p_mis, PV_NONE, NULL, NULL,

View File

@ -65,6 +65,7 @@ char *did_set_pyxversion(optset_T *args);
char *did_set_readonly(optset_T *args);
char *did_set_scrollbind(optset_T *args);
char *did_set_shellslash(optset_T *args);
char *did_set_maxsearchcount(optset_T *args);
char *did_set_shiftwidth_tabstop(optset_T *args);
char *did_set_showtabline(optset_T *args);
char *did_set_smoothscroll(optset_T *args);

View File

@ -55,8 +55,9 @@ static int fuzzy_match_func_compare(const void *s1, const void *s2);
static void fuzzy_match_func_sort(fuzmatch_str_T *fm, int sz);
#define SEARCH_STAT_DEF_TIMEOUT 40L
#define SEARCH_STAT_DEF_MAX_COUNT 99
#define SEARCH_STAT_BUF_LEN 12
// 'W ': 2 +
// '[>9999/>9999]': 13 + 1 (NUL)
#define SEARCH_STAT_BUF_LEN 16
/*
* This file contains various searching-related routines. These fall into
@ -1696,7 +1697,7 @@ do_search(
NULL, NULL))
#endif
),
SEARCH_STAT_DEF_MAX_COUNT,
p_msc,
SEARCH_STAT_DEF_TIMEOUT);
/*
@ -3265,7 +3266,7 @@ update_search_stat(
static int cnt = 0;
static int exact_match = FALSE;
static int incomplete = 0;
static int last_maxcount = SEARCH_STAT_DEF_MAX_COUNT;
static int last_maxcount = 0;
static int chgtick = 0;
static char_u *lastpat = NULL;
static size_t lastpatlen = 0;
@ -3282,7 +3283,7 @@ update_search_stat(
stat->cnt = cnt;
stat->exact_match = exact_match;
stat->incomplete = incomplete;
stat->last_maxcount = last_maxcount;
stat->last_maxcount = p_msc;
return;
}
last_maxcount = maxcount;
@ -4174,7 +4175,7 @@ f_searchcount(typval_T *argvars, typval_T *rettv)
{
pos_T pos = curwin->w_cursor;
char_u *pattern = NULL;
int maxcount = SEARCH_STAT_DEF_MAX_COUNT;
int maxcount = p_msc;
long timeout = SEARCH_STAT_DEF_TIMEOUT;
int recompute = TRUE;
searchstat_T stat;

View File

@ -477,4 +477,166 @@ func Test_search_stat_smartcase_ignorecase()
call StopVimInTerminal(buf)
endfunc
func Test_search_stat_option_values()
call assert_fails(':set maxsearchcount=0', 'E487:')
call assert_fails(':set maxsearchcount=10000', 'E474:')
set maxsearchcount=9999
call assert_equal(9999, &msc)
set maxsearchcount=1
call assert_equal(1, &msc)
set maxsearchcount=999
call assert_equal(999, &msc)
set maxsearchcount&vim
endfunc
func Test_search_stat_option()
" Asan causes wrong results, because the search times out
CheckNotAsan
enew
set shortmess-=S
set maxsearchcount=999
" Append 1000 lines with text to search for, "foobar" appears 20 times
call append(0, repeat(['foobar', 'foo', 'fooooobar', 'foba', 'foobar'], 1000))
call cursor(1, 1)
call assert_equal(
\ #{exact_match: 1, current: 1, incomplete: 2, maxcount: 999, total: 1000},
\ searchcount(#{pattern: 'fooooobar', pos: [3, 1, 0]}))
" on last char of match
call assert_equal(
\ #{exact_match: 1, current: 1, incomplete: 2, maxcount: 999, total: 1000},
\ searchcount(#{pattern: 'fooooobar', pos: [3, 9, 0]}))
" on char after match
call assert_equal(
\ #{exact_match: 0, current: 1, incomplete: 2, maxcount: 999, total: 1000},
\ searchcount(#{pattern: 'fooooobar', pos: [3, 10, 0]}))
" match at second line
let messages_before = execute('messages')
let @/ = 'fo*\(bar\?\)\?'
let g:a = execute(':unsilent :norm! n')
let stat = '\[2/>999\]'
let pat = escape(@/, '()*?'). '\s\+'
call assert_match(pat .. stat, g:a)
call assert_equal(
\ #{exact_match: 1, current: 2, incomplete: 2, maxcount: 999, total: 1000},
\ searchcount(#{recompute: 0}))
" didn't get added to message history
call assert_equal(messages_before, execute('messages'))
" Many matches
call cursor(line('$')-2, 1)
let @/ = '.'
let pat = escape(@/, '()*?'). '\s\+'
let g:a = execute(':unsilent :norm! n')
let stat = '\[>999/>999\]'
call assert_match(pat .. stat, g:a)
call assert_equal(
\ #{exact_match: 0, current: 1000, incomplete: 2, maxcount: 999, total: 1000},
\ searchcount(#{recompute: 0}))
call assert_equal(
\ #{exact_match: 1, current: 27992, incomplete: 0, maxcount:0, total: 28000},
\ searchcount(#{recompute: v:true, maxcount: 0, timeout: 200}))
call assert_equal(
\ #{exact_match: 1, current: 1, incomplete: 0, maxcount: 0, total: 28000},
\ searchcount(#{recompute: 1, maxcount: 0, pos: [1, 1, 0], timeout: 200}))
call cursor(line('$'), 1)
let g:a = execute(':unsilent :norm! n')
let stat = 'W \[1/>999\]'
call assert_match(pat .. stat, g:a)
call assert_equal(
\ #{current: 1, exact_match: 1, total: 1000, incomplete: 2, maxcount: 999},
\ searchcount(#{recompute: 0}))
call assert_equal(
\ #{current: 1, exact_match: 1, total: 28000, incomplete: 0, maxcount: 0},
\ searchcount(#{recompute: 1, maxcount: 0, timeout: 200}))
call assert_equal(
\ #{current: 27991, exact_match: 1, total: 28000, incomplete: 0, maxcount: 0},
\ searchcount(#{recompute: 1, maxcount: 0, pos: [line('$')-2, 1, 0], timeout: 200}))
" Many matches
call cursor(1, 1)
let g:a = execute(':unsilent :norm! n')
let stat = '\[2/>999\]'
call assert_match(pat .. stat, g:a)
call cursor(1, 1)
let g:a = execute(':unsilent :norm! N')
let stat = '\[>999/>999\]'
call assert_match(pat .. stat, g:a)
set maxsearchcount=500
call cursor(1, 1)
let g:a = execute(':unsilent :norm! n')
let stat = '\[2/>500\]'
call assert_match(pat .. stat, g:a)
call cursor(1, 1)
let g:a = execute(':unsilent :norm! N')
let stat = '\[>500/>500\]'
call assert_match(pat .. stat, g:a)
set maxsearchcount=20
call cursor(1, 1)
let g:a = execute(':unsilent :norm! n')
let stat = '\[2/>20\]'
call assert_match(pat .. stat, g:a)
call cursor(1, 1)
let g:a = execute(':unsilent :norm! N')
let stat = '\[>20/>20\]'
call assert_match(pat .. stat, g:a)
set maxsearchcount=999
" right-left
if exists("+rightleft")
set rl
call cursor(1,1)
let @/ = 'foobar'
let pat = 'raboof/\s\+'
let g:a = execute(':unsilent :norm! n')
let stat = '\[>999/2\]'
call assert_match(pat .. stat, g:a)
" right-left bottom
call cursor('$',1)
let pat = 'raboof?\s\+'
let g:a = execute(':unsilent :norm! N')
let stat = '\[>999/>999\]'
call assert_match(pat .. stat, g:a)
" right-left back at top
call cursor('$',1)
let pat = 'raboof/\s\+'
let g:a = execute(':unsilent :norm! n')
let stat = 'W \[>999/1\]'
call assert_match(pat .. stat, g:a)
set norl
endif
" normal, back at bottom
call cursor(1,1)
let @/ = 'foobar'
let pat = '?foobar\s\+'
let g:a = execute(':unsilent :norm! N')
let stat = 'W \[>999/>999\]'
call assert_match(pat .. stat, g:a)
call assert_match('W \[>999/>999\]', Screenline(&lines))
" normal, no match
call cursor(1,1)
let @/ = 'zzzzzz'
let g:a = ''
try
let g:a = execute(':unsilent :norm! n')
catch /^Vim\%((\a\+)\)\=:E486/
let stat = ''
" error message is not redir'ed to g:a, it is empty
call assert_true(empty(g:a))
catch
call assert_false(1)
endtry
" Clean up
set shortmess+=S
set maxsearchcount&vim
" close the window
bwipe!
endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

@ -279,6 +279,7 @@ let test_values = {
\ 'renderoptions': [[''], ['xxx']],
\ 'rightleftcmd': [['search'], ['xxx']],
\ 'rulerformat': [['', 'xxx'], ['%-', '%(', '%15(%%']],
\ 'maxsearchcount': [[1, 10, 100, 1000], [0, -1, 10000]],
\ 'selection': [['old', 'inclusive', 'exclusive'], ['', 'xxx']],
\ 'selectmode': [['', 'mouse', 'key', 'cmd', 'key,cmd'], ['xxx']],
\ 'sessionoptions': [['', 'blank', 'curdir', 'sesdir',

View File

@ -719,6 +719,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
1535,
/**/
1534,
/**/