0
0
mirror of https://github.com/vim/vim.git synced 2025-09-30 04:44:14 -04:00

patch 8.1.1270: cannot see current match position

Problem:    Cannot see current match position.
Solution:   Show "3/44" when using the "n" command and "S" is not in
            'shortmess'. (Christian Brabandt, closes #4317)
This commit is contained in:
Bram Moolenaar
2019-05-04 21:08:40 +02:00
parent ed5ab2a959
commit 9dfa313919
8 changed files with 353 additions and 53 deletions

View File

@@ -1789,7 +1789,7 @@ A jump table for the options with a short description can be found at |Q_op|.
'scrolloff' + 0 no scroll offset 'scrolloff' + 0 no scroll offset
'shelltemp' - {unchanged} {set vim default only on resetting 'cp'} 'shelltemp' - {unchanged} {set vim default only on resetting 'cp'}
'shiftround' + off indent not rounded to shiftwidth 'shiftround' + off indent not rounded to shiftwidth
'shortmess' & "" no shortening of messages 'shortmess' & "S" no shortening of messages
'showcmd' & off command characters not shown 'showcmd' & off command characters not shown
'showmode' & off current mode not shown 'showmode' & off current mode not shown
'sidescrolloff' + 0 cursor moves to edge of screen in scroll 'sidescrolloff' + 0 cursor moves to edge of screen in scroll
@@ -6563,8 +6563,8 @@ A jump table for the options with a short description can be found at |Q_op|.
function to get the effective shiftwidth value. function to get the effective shiftwidth value.
*'shortmess'* *'shm'* *'shortmess'* *'shm'*
'shortmess' 'shm' string (Vim default "filnxtToO", Vi default: "", 'shortmess' 'shm' string (Vim default "filnxtToOS", Vi default: "S",
POSIX default: "A") POSIX default: "AS")
global global
This option helps to avoid all the |hit-enter| prompts caused by file This option helps to avoid all the |hit-enter| prompts caused by file
messages, for example with CTRL-G, and to avoid some other messages. messages, for example with CTRL-G, and to avoid some other messages.
@@ -6604,6 +6604,8 @@ A jump table for the options with a short description can be found at |Q_op|.
q use "recording" instead of "recording @a" q use "recording" instead of "recording @a"
F don't give the file info when editing a file, like `:silent` F don't give the file info when editing a file, like `:silent`
was used for the command was used for the command
S do not show search count message when searching, e.g.
"[1/5]"
This gives you the opportunity to avoid that a change between buffers This gives you the opportunity to avoid that a change between buffers
requires you to hit <Enter>, but still gives as useful a message as requires you to hit <Enter>, but still gives as useful a message as

View File

@@ -152,6 +152,17 @@ use <Esc> to abandon the search.
All matches for the last used search pattern will be highlighted if you set All matches for the last used search pattern will be highlighted if you set
the 'hlsearch' option. This can be suspended with the |:nohlsearch| command. the 'hlsearch' option. This can be suspended with the |:nohlsearch| command.
When 'shortmess' does not include the "S" flag, Vim will automatically show an
index, on which the cursor is. This can look like this: >
[1/5] Cursor is on first of 5 matches.
[1/>99] Cursor is on first of more than 99 matches.
[>99/>99] Cursor is after 99 match of more than 99 matches.
[?/??] Unknown how many matches exists, generating the
statistics was aborted because of search timeout.
Note: the count does not take offset into account.
When no match is found you get the error: *E486* Pattern not found When no match is found you get the error: *E486* Pattern not found
Note that for the |:global| command this behaves like a normal message, for Vi Note that for the |:global| command this behaves like a normal message, for Vi
compatibility. For the |:s| command the "e" flag can be used to avoid the compatibility. For the |:s| command the "e" flag can be used to avoid the
@@ -299,6 +310,14 @@ when executing a pattern takes a long time and when checking for messages on
channels a callback is invoked that also uses a pattern or an autocommand is channels a callback is invoked that also uses a pattern or an autocommand is
triggered. In most cases this should be fine, but if a pattern is in use when triggered. In most cases this should be fine, but if a pattern is in use when
it's used again it fails. Usually this means there is something wrong with it's used again it fails. Usually this means there is something wrong with
the pattern.
*E956*
In very rare cases a regular expression is used recursively. This can happen
when executing a pattern takes a long time and when checking for messages on
channels a callback is invoked that also uses a pattern or an autocommand is
triggered. In most cases this should be fine, but if a pattern is in use when
it's used again it fails. Usually this means there is something wrong with
the pattern. the pattern.
============================================================================== ==============================================================================

View File

@@ -2449,7 +2449,7 @@ static struct vimoption options[] =
{(char_u *)8L, (char_u *)0L} SCTX_INIT}, {(char_u *)8L, (char_u *)0L} SCTX_INIT},
{"shortmess", "shm", P_STRING|P_VIM|P_FLAGLIST, {"shortmess", "shm", P_STRING|P_VIM|P_FLAGLIST,
(char_u *)&p_shm, PV_NONE, (char_u *)&p_shm, PV_NONE,
{(char_u *)"", (char_u *)"filnxtToO"} {(char_u *)"S", (char_u *)"filnxtToOS"}
SCTX_INIT}, SCTX_INIT},
{"shortname", "sn", P_BOOL|P_VI_DEF, {"shortname", "sn", P_BOOL|P_VI_DEF,
(char_u *)&p_sn, PV_SN, (char_u *)&p_sn, PV_SN,
@@ -3311,7 +3311,7 @@ set_init_1(int clean_arg)
if (mch_getenv((char_u *)"VIM_POSIX") != NULL) if (mch_getenv((char_u *)"VIM_POSIX") != NULL)
{ {
set_string_default("cpo", (char_u *)CPO_ALL); set_string_default("cpo", (char_u *)CPO_ALL);
set_string_default("shm", (char_u *)"A"); set_string_default("shm", (char_u *)SHM_POSIX);
} }
/* /*

View File

@@ -183,27 +183,29 @@
#define COCU_ALL "nvic" /* flags for 'concealcursor' */ #define COCU_ALL "nvic" /* flags for 'concealcursor' */
/* characters for p_shm option: */ /* characters for p_shm option: */
#define SHM_RO 'r' /* readonly */ #define SHM_RO 'r' // readonly
#define SHM_MOD 'm' /* modified */ #define SHM_MOD 'm' // modified
#define SHM_FILE 'f' /* (file 1 of 2) */ #define SHM_FILE 'f' // (file 1 of 2)
#define SHM_LAST 'i' /* last line incomplete */ #define SHM_LAST 'i' // last line incomplete
#define SHM_TEXT 'x' /* tx instead of textmode */ #define SHM_TEXT 'x' // tx instead of textmode
#define SHM_LINES 'l' /* "L" instead of "lines" */ #define SHM_LINES 'l' // "L" instead of "lines"
#define SHM_NEW 'n' /* "[New]" instead of "[New file]" */ #define SHM_NEW 'n' // "[New]" instead of "[New file]"
#define SHM_WRI 'w' /* "[w]" instead of "written" */ #define SHM_WRI 'w' // "[w]" instead of "written"
#define SHM_A "rmfixlnw" /* represented by 'a' flag */ #define SHM_A "rmfixlnw" // represented by 'a' flag
#define SHM_WRITE 'W' /* don't use "written" at all */ #define SHM_WRITE 'W' // don't use "written" at all
#define SHM_TRUNC 't' /* truncate file messages */ #define SHM_TRUNC 't' // truncate file messages
#define SHM_TRUNCALL 'T' /* truncate all messages */ #define SHM_TRUNCALL 'T' // truncate all messages
#define SHM_OVER 'o' /* overwrite file messages */ #define SHM_OVER 'o' // overwrite file messages
#define SHM_OVERALL 'O' /* overwrite more messages */ #define SHM_OVERALL 'O' // overwrite more messages
#define SHM_SEARCH 's' /* no search hit bottom messages */ #define SHM_SEARCH 's' // no search hit bottom messages
#define SHM_ATTENTION 'A' /* no ATTENTION messages */ #define SHM_ATTENTION 'A' // no ATTENTION messages
#define SHM_INTRO 'I' /* intro messages */ #define SHM_INTRO 'I' // intro messages
#define SHM_COMPLETIONMENU 'c' /* completion menu messages */ #define SHM_COMPLETIONMENU 'c' // completion menu messages
#define SHM_RECORDING 'q' /* short recording message */ #define SHM_RECORDING 'q' // short recording message
#define SHM_FILEINFO 'F' /* no file info messages */ #define SHM_FILEINFO 'F' // no file info messages
#define SHM_ALL "rmfixlnwaWtToOsAIcqF" /* all possible flags for 'shm' */ #define SHM_SEARCHCOUNT 'S' // search stats: '[1/10]'
#define SHM_POSIX "AS" // POSIX value
#define SHM_ALL "rmfixlnwaWtToOsAIcqFS" // all possible flags for 'shm'
/* characters for p_go: */ /* characters for p_go: */
#define GO_TERMINAL '!' /* use terminal for system commands */ #define GO_TERMINAL '!' /* use terminal for system commands */

View File

@@ -26,6 +26,7 @@ static void show_pat_in_path(char_u *, int,
#ifdef FEAT_VIMINFO #ifdef FEAT_VIMINFO
static void wvsp_one(FILE *fp, int idx, char *s, int sc); static void wvsp_one(FILE *fp, int idx, char *s, int sc);
#endif #endif
static void search_stat(int dirc, pos_T *pos, char_u *msgbuf);
/* /*
* This file contains various searching-related routines. These fall into * This file contains various searching-related routines. These fall into
@@ -1216,6 +1217,8 @@ do_search(
char_u *dircp; char_u *dircp;
char_u *strcopy = NULL; char_u *strcopy = NULL;
char_u *ps; char_u *ps;
char_u *msgbuf = NULL;
size_t len;
/* /*
* A line offset is not remembered, this is vi compatible. * A line offset is not remembered, this is vi compatible.
@@ -1374,28 +1377,51 @@ do_search(
if ((options & SEARCH_ECHO) && messaging() if ((options & SEARCH_ECHO) && messaging()
&& !cmd_silent && msg_silent == 0) && !cmd_silent && msg_silent == 0)
{ {
char_u *msgbuf;
char_u *trunc; char_u *trunc;
// Compute msg_row early.
msg_start();
if (*searchstr == NUL) if (*searchstr == NUL)
p = spats[0].pat; p = spats[0].pat;
else else
p = searchstr; p = searchstr;
msgbuf = alloc((unsigned)(STRLEN(p) + 40));
if (msgbuf != NULL) if (!shortmess(SHM_SEARCHCOUNT))
{ {
msgbuf[0] = dirc; // Reserve enough space for the search pattern + offset +
if (enc_utf8 && utf_iscomposing(utf_ptr2char(p))) // search stat.
{ if (msg_scrolled != 0)
/* Use a space to draw the composing char on. */ // Use all the columns.
msgbuf[1] = ' '; len = (int)(Rows - msg_row) * Columns - 1;
STRCPY(msgbuf + 2, p); else
// Use up to 'showcmd' column.
len = (int)(Rows - msg_row - 1) * Columns + sc_col - 1;
if (len < STRLEN(p) + 40 + 11)
len = STRLEN(p) + 40 + 11;
} }
else else
STRCPY(msgbuf + 1, p); // Reserve enough space for the search pattern + offset.
len = STRLEN(p) + 40;
msgbuf = alloc((int)len);
if (msgbuf != NULL)
{
vim_memset(msgbuf, ' ', len);
msgbuf[0] = dirc;
msgbuf[len - 1] = NUL;
if (enc_utf8 && utf_iscomposing(utf_ptr2char(p)))
{
// Use a space to draw the composing char on.
msgbuf[1] = ' ';
STRNCPY(msgbuf + 2, p, STRLEN(p));
}
else
STRNCPY(msgbuf + 1, p, STRLEN(p));
if (spats[0].off.line || spats[0].off.end || spats[0].off.off) if (spats[0].off.line || spats[0].off.end || spats[0].off.off)
{ {
p = msgbuf + STRLEN(msgbuf); p = msgbuf + STRLEN(p) + 1;
*p++ = dirc; *p++ = dirc;
if (spats[0].off.end) if (spats[0].off.end)
*p++ = 'e'; *p++ = 'e';
@@ -1404,45 +1430,50 @@ do_search(
if (spats[0].off.off > 0 || spats[0].off.line) if (spats[0].off.off > 0 || spats[0].off.line)
*p++ = '+'; *p++ = '+';
if (spats[0].off.off != 0 || spats[0].off.line) if (spats[0].off.off != 0 || spats[0].off.line)
sprintf((char *)p, "%ld", spats[0].off.off); {
else int l = 0;
*p = NUL; l = sprintf((char *)p, "%ld", spats[0].off.off);
p[l] = ' '; // remove NUL from sprintf
}
} }
msg_start();
trunc = msg_strtrunc(msgbuf, FALSE); trunc = msg_strtrunc(msgbuf, FALSE);
if (trunc != NULL)
{
vim_free(msgbuf);
msgbuf = trunc;
}
#ifdef FEAT_RIGHTLEFT #ifdef FEAT_RIGHTLEFT
/* The search pattern could be shown on the right in rightleft // The search pattern could be shown on the right in rightleft
* mode, but the 'ruler' and 'showcmd' area use it too, thus // mode, but the 'ruler' and 'showcmd' area use it too, thus
* it would be blanked out again very soon. Show it on the // it would be blanked out again very soon. Show it on the
* left, but do reverse the text. */ // left, but do reverse the text.
if (curwin->w_p_rl && *curwin->w_p_rlc == 's') if (curwin->w_p_rl && *curwin->w_p_rlc == 's')
{ {
char_u *r; char_u *r;
r = reverse_text(trunc != NULL ? trunc : msgbuf); r = reverse_text(msgbuf);
if (r != NULL) if (r != NULL)
{ {
vim_free(trunc); vim_free(msgbuf);
trunc = r; msgbuf = r;
// move reversed text to beginning of buffer
while (*r != NUL && *r == ' ')
r++;
mch_memmove(msgbuf, r, msgbuf + STRLEN(msgbuf) - r);
// overwrite old text
vim_memset(r, ' ', msgbuf + STRLEN(msgbuf) - r);
} }
} }
#endif #endif
if (trunc != NULL)
{
msg_outtrans(trunc);
vim_free(trunc);
}
else
msg_outtrans(msgbuf); msg_outtrans(msgbuf);
msg_clr_eos(); msg_clr_eos();
msg_check(); msg_check();
vim_free(msgbuf);
gotocmdline(FALSE); gotocmdline(FALSE);
out_flush(); out_flush();
msg_nowait = TRUE; /* don't wait for this message */ msg_nowait = TRUE; // don't wait for this message
} }
} }
@@ -1488,7 +1519,13 @@ do_search(
RE_LAST, (linenr_T)0, tm, timed_out); RE_LAST, (linenr_T)0, tm, timed_out);
if (dircp != NULL) if (dircp != NULL)
*dircp = dirc; /* restore second '/' or '?' for normal_cmd() */ *dircp = dirc; // restore second '/' or '?' for normal_cmd()
if (!shortmess(SHM_SEARCH)
&& ((dirc == '/' && LT_POS(pos, curwin->w_cursor))
|| (dirc == '?' && LT_POS(curwin->w_cursor, pos))))
ui_delay(500L, FALSE); // leave some time for top_bot_msg
if (c == FAIL) if (c == FAIL)
{ {
retval = 0; retval = 0;
@@ -1537,6 +1574,15 @@ do_search(
} }
} }
// Show [1/15] if 'S' is not in 'shortmess'.
if ((options & SEARCH_ECHO)
&& messaging()
&& !(cmd_silent + msg_silent)
&& c != FAIL
&& !shortmess(SHM_SEARCHCOUNT)
&& msgbuf != NULL)
search_stat(dirc, &pos, msgbuf);
/* /*
* The search command can be followed by a ';' to do another search. * The search command can be followed by a ';' to do another search.
* For example: "/pat/;/foo/+3;?bar" * For example: "/pat/;/foo/+3;?bar"
@@ -1567,6 +1613,7 @@ end_do_search:
if ((options & SEARCH_KEEP) || cmdmod.keeppatterns) if ((options & SEARCH_KEEP) || cmdmod.keeppatterns)
spats[0].off = old_off; spats[0].off = old_off;
vim_free(strcopy); vim_free(strcopy);
vim_free(msgbuf);
return retval; return retval;
} }
@@ -4857,6 +4904,124 @@ linewhite(linenr_T lnum)
} }
#endif #endif
/*
* Add the search count "[3/19]" to "msgbuf".
*/
static void
search_stat(
int dirc,
pos_T *pos,
char_u *msgbuf)
{
int save_ws = p_ws;
int wraparound = FALSE;
pos_T p = (*pos);
static pos_T lastpos = {0, 0, 0};
static int cur = 0;
static int cnt = 0;
static int chgtick = 0;
static char_u *lastpat = NULL;
static buf_T *lbuf = NULL;
#ifdef FEAT_RELTIME
proftime_T start;
#endif
#define OUT_OF_TIME 999
wraparound = ((dirc == '?' && LT_POS(lastpos, p))
|| (dirc == '/' && LT_POS(p, lastpos)));
// If anything relevant changed the count has to be recomputed.
// MB_STRNICMP ignores case, but we should not ignore case.
// Unfortunately, there is no MB_STRNICMP function.
if (!(chgtick == CHANGEDTICK(curbuf)
&& MB_STRNICMP(lastpat, spats[last_idx].pat, STRLEN(lastpat)) == 0
&& STRLEN(lastpat) == STRLEN(spats[last_idx].pat)
&& EQUAL_POS(lastpos, curwin->w_cursor)
&& lbuf == curbuf) || wraparound || cur < 0 || cur > 99)
{
cur = 0;
cnt = 0;
CLEAR_POS(&lastpos);
lbuf = curbuf;
}
if (EQUAL_POS(lastpos, curwin->w_cursor) && !wraparound
&& (dirc == '/' ? cur < cnt : cur > 0))
cur += dirc == '/' ? 1 : -1;
else
{
p_ws = FALSE;
#ifdef FEAT_RELTIME
profile_setlimit(20L, &start);
#endif
while (!got_int && searchit(curwin, curbuf, &lastpos, NULL,
FORWARD, NULL, 1, SEARCH_PEEK + SEARCH_KEEP,
RE_LAST, (linenr_T)0, NULL, NULL) != FAIL)
{
#ifdef FEAT_RELTIME
// Stop after passing the time limit.
if (profile_passed_limit(&start))
{
cnt = OUT_OF_TIME;
cur = OUT_OF_TIME;
break;
}
#endif
cnt++;
if (LTOREQ_POS(lastpos, p))
cur++;
fast_breakcheck();
if (cnt > 99)
break;
}
if (got_int)
cur = -1; // abort
}
if (cur > 0)
{
#define STAT_BUF_LEN 10
char t[STAT_BUF_LEN] = "";
#ifdef FEAT_RIGHTLEFT
if (curwin->w_p_rl && *curwin->w_p_rlc == 's')
{
if (cur == OUT_OF_TIME)
vim_snprintf(t, STAT_BUF_LEN, "[?/??]");
else if (cnt > 99 && cur > 99)
vim_snprintf(t, STAT_BUF_LEN, "[>99/>99]");
else if (cnt > 99)
vim_snprintf(t, STAT_BUF_LEN, "[>99/%d]", cur);
else
vim_snprintf(t, STAT_BUF_LEN, "[%d/%d]", cnt, cur);
}
else
#endif
{
if (cur == OUT_OF_TIME)
vim_snprintf(t, STAT_BUF_LEN, "[?/??]");
else if (cnt > 99 && cur > 99)
vim_snprintf(t, STAT_BUF_LEN, "[>99/>99]");
else if (cnt > 99)
vim_snprintf(t, STAT_BUF_LEN, "[%d/>99]", cur);
else
vim_snprintf(t, STAT_BUF_LEN, "[%d/%d]", cur, cnt);
}
STRNCPY(msgbuf + STRLEN(msgbuf) - STRLEN(t), t, STRLEN(t));
if (dirc == '?' && cur == 100)
cur = -1;
vim_free(lastpat);
lastpat = vim_strsave(spats[last_idx].pat);
chgtick = CHANGEDTICK(curbuf);
lbuf = curbuf;
lastpos = p;
// keep the message even after redraw
give_warning(msgbuf, FALSE);
}
p_ws = save_ws;
}
#if defined(FEAT_FIND_ID) || defined(PROTO) #if defined(FEAT_FIND_ID) || defined(PROTO)
/* /*
* Find identifiers or defines in included files. * Find identifiers or defines in included files.

View File

@@ -219,6 +219,7 @@ NEW_TESTS = \
test_scroll_opt \ test_scroll_opt \
test_scrollbind \ test_scrollbind \
test_search \ test_search \
test_search_stat \
test_searchpos \ test_searchpos \
test_set \ test_set \
test_sha256 \ test_sha256 \
@@ -388,6 +389,7 @@ NEW_TESTS_RES = \
test_scriptnames.res \ test_scriptnames.res \
test_scrollbind.res \ test_scrollbind.res \
test_search.res \ test_search.res \
test_search_stat.res \
test_shortpathname.res \ test_shortpathname.res \
test_signals.res \ test_signals.res \
test_signs.res \ test_signs.res \

View File

@@ -0,0 +1,108 @@
" Tests for search_stats, when "S" is not in 'shortmess'
"
" This test is fragile, it might not work interactively, but it works when run
" as test!
func! Test_search_stat()
new
set shortmess-=S
call append(0, repeat(['foobar', 'foo', 'fooooobar', 'foba', 'foobar'], 10))
" 1) match at second line
call cursor(1, 1)
let @/ = 'fo*\(bar\?\)\?'
let g:a = execute(':unsilent :norm! n')
let stat = '\[2/50\]'
let pat = escape(@/, '()*?'). '\s\+'
call assert_match(pat .. stat, g:a)
" 2) Match at last line
call cursor(line('$')-2, 1)
let g:a = execute(':unsilent :norm! n')
let stat = '\[50/50\]'
call assert_match(pat .. stat, g:a)
" 3) No search stat
set shortmess+=S
call cursor(1, 1)
let stat = '\[2/50\]'
let g:a = execute(':unsilent :norm! n')
call assert_notmatch(pat .. stat, g:a)
set shortmess-=S
" 4) Many matches
call cursor(line('$')-2, 1)
let @/ = '.'
let pat = escape(@/, '()*?'). '\s\+'
let g:a = execute(':unsilent :norm! n')
let stat = '\[>99/>99\]'
call assert_match(pat .. stat, g:a)
" 5) Many matches
call cursor(1, 1)
let g:a = execute(':unsilent :norm! n')
let stat = '\[2/>99\]'
call assert_match(pat .. stat, g:a)
" 6) 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 = '\[20/2\]'
call assert_match(pat .. stat, g:a)
set norl
endif
" 7) right-left bottom
if exists("+rightleft")
set rl
call cursor('$',1)
let pat = 'raboof?\s\+'
let g:a = execute(':unsilent :norm! N')
let stat = '\[20/20\]'
call assert_match(pat .. stat, g:a)
set norl
endif
" 8) right-left back at top
if exists("+rightleft")
set rl
call cursor('$',1)
let pat = 'raboof/\s\+'
let g:a = execute(':unsilent :norm! n')
let stat = '\[20/1\]'
call assert_match(pat .. stat, g:a)
call assert_match('search hit BOTTOM, continuing at TOP', g:a)
set norl
endif
" 9) normal, back at top
call cursor(1,1)
let @/ = 'foobar'
let pat = '?foobar\s\+'
let g:a = execute(':unsilent :norm! N')
let stat = '\[20/20\]'
call assert_match(pat .. stat, g:a)
call assert_match('search hit TOP, continuing at BOTTOM', g:a)
" 10) 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
" close the window
set shortmess+=S
bwipe!
endfunc

View File

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