Merge #10114 from erw7/vim-8.1.1270

vim-patch:8.1.{0629,1270,1271,1283,1288,1289,1350,1375,1390,1475}
This commit is contained in:
Justin M. Keyes 2019-06-07 21:28:53 +02:00 committed by GitHub
commit f6f9e4a231
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 518 additions and 116 deletions

View File

@ -5254,7 +5254,7 @@ 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 "filnxtToOF", Vi default: "") 'shortmess' 'shm' string (Vim default "filnxtToOFS", Vi default: "S")
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.
@ -5294,6 +5294,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

@ -141,6 +141,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

View File

@ -4045,13 +4045,15 @@ static int ins_compl_get_exp(pos_T *ini)
if (CTRL_X_MODE_LINE_OR_EVAL(l_ctrl_x_mode) if (CTRL_X_MODE_LINE_OR_EVAL(l_ctrl_x_mode)
|| (compl_cont_status & CONT_SOL)) { || (compl_cont_status & CONT_SOL)) {
found_new_match = search_for_exact_line(ins_buf, pos, found_new_match = search_for_exact_line(ins_buf, pos,
compl_direction, compl_pattern); compl_direction,
} else compl_pattern);
found_new_match = searchit(NULL, ins_buf, pos, } else {
found_new_match = searchit(NULL, ins_buf, pos, NULL,
compl_direction, compl_direction,
compl_pattern, 1L, compl_pattern, 1L,
SEARCH_KEEP + SEARCH_NFMSG, SEARCH_KEEP + SEARCH_NFMSG,
RE_LAST, (linenr_T)0, NULL, NULL); RE_LAST, (linenr_T)0, NULL, NULL);
}
msg_silent--; msg_silent--;
if (!compl_started || set_match_pos) { if (!compl_started || set_match_pos) {
/* set "compl_started" even on fail */ /* set "compl_started" even on fail */

View File

@ -14139,7 +14139,7 @@ static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
} }
pos = save_cursor = curwin->w_cursor; pos = save_cursor = curwin->w_cursor;
subpatnum = searchit(curwin, curbuf, &pos, dir, (char_u *)pat, 1, subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, (char_u *)pat, 1,
options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL); options, RE_SEARCH, (linenr_T)lnum_stop, &tm, NULL);
if (subpatnum != FAIL) { if (subpatnum != FAIL) {
if (flags & SP_SUBPAT) if (flags & SP_SUBPAT)
@ -14657,7 +14657,7 @@ do_searchpair(
clearpos(&foundpos); clearpos(&foundpos);
pat = pat3; pat = pat3;
for (;; ) { for (;; ) {
n = searchit(curwin, curbuf, &pos, dir, pat, 1L, n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
options, RE_SEARCH, lnum_stop, &tm, NULL); options, RE_SEARCH, lnum_stop, &tm, NULL);
if (n == FAIL || (firstpos.lnum != 0 && equalpos(pos, firstpos))) { if (n == FAIL || (firstpos.lnum != 0 && equalpos(pos, firstpos))) {
// didn't find it or found the first match again: FAIL // didn't find it or found the first match again: FAIL

View File

@ -3758,12 +3758,12 @@ static linenr_T get_address(exarg_T *eap,
// Start the search just like for the above do_search(). // Start the search just like for the above do_search().
pos.col = (*cmd != '?') ? MAXCOL : 0; pos.col = (*cmd != '?') ? MAXCOL : 0;
pos.coladd = 0; pos.coladd = 0;
if (searchit(curwin, curbuf, &pos, if (searchit(curwin, curbuf, &pos, NULL,
*cmd == '?' ? BACKWARD : FORWARD, *cmd == '?' ? BACKWARD : FORWARD,
(char_u *)"", 1L, SEARCH_MSG, (char_u *)"", 1L, SEARCH_MSG,
i, (linenr_T)0, NULL, NULL) != FAIL) i, (linenr_T)0, NULL, NULL) != FAIL) {
lnum = pos.lnum; lnum = pos.lnum;
else { } else {
cmd = NULL; cmd = NULL;
goto error; goto error;
} }

View File

@ -1069,7 +1069,7 @@ static void command_line_next_incsearch(CommandLineState *s, bool next_match)
search_flags += SEARCH_KEEP; search_flags += SEARCH_KEEP;
} }
emsg_off++; emsg_off++;
s->i = searchit(curwin, curbuf, &t, s->i = searchit(curwin, curbuf, &t, NULL,
next_match ? FORWARD : BACKWARD, next_match ? FORWARD : BACKWARD,
pat, s->count, search_flags, pat, s->count, search_flags,
RE_SEARCH, 0, NULL, NULL); RE_SEARCH, 0, NULL, NULL);

View File

@ -3782,7 +3782,7 @@ find_decl (
for (;; ) { for (;; ) {
valid = false; valid = false;
(void)valid; // Avoid "dead assignment" warning. (void)valid; // Avoid "dead assignment" warning.
t = searchit(curwin, curbuf, &curwin->w_cursor, FORWARD, t = searchit(curwin, curbuf, &curwin->w_cursor, NULL, FORWARD,
pat, 1L, searchflags, RE_LAST, (linenr_T)0, NULL, NULL); pat, 1L, searchflags, RE_LAST, (linenr_T)0, NULL, NULL);
if (curwin->w_cursor.lnum >= old_pos.lnum) { if (curwin->w_cursor.lnum >= old_pos.lnum) {
t = false; // match after start is failure too t = false; // match after start is failure too

View File

@ -315,7 +315,7 @@ static char_u SHM_ALL[] = {
SHM_RO, SHM_MOD, SHM_FILE, SHM_LAST, SHM_TEXT, SHM_LINES, SHM_NEW, SHM_WRI, SHM_RO, SHM_MOD, SHM_FILE, SHM_LAST, SHM_TEXT, SHM_LINES, SHM_NEW, SHM_WRI,
SHM_ABBREVIATIONS, SHM_WRITE, SHM_TRUNC, SHM_TRUNCALL, SHM_OVER, SHM_ABBREVIATIONS, SHM_WRITE, SHM_TRUNC, SHM_TRUNCALL, SHM_OVER,
SHM_OVERALL, SHM_SEARCH, SHM_ATTENTION, SHM_INTRO, SHM_COMPLETIONMENU, SHM_OVERALL, SHM_SEARCH, SHM_ATTENTION, SHM_INTRO, SHM_COMPLETIONMENU,
SHM_RECORDING, SHM_FILEINFO, SHM_RECORDING, SHM_FILEINFO, SHM_SEARCHCOUNT,
0, 0,
}; };

View File

@ -173,6 +173,7 @@ enum {
SHM_COMPLETIONMENU = 'c', ///< Completion menu messages. SHM_COMPLETIONMENU = 'c', ///< Completion menu messages.
SHM_RECORDING = 'q', ///< Short recording message. SHM_RECORDING = 'q', ///< Short recording message.
SHM_FILEINFO = 'F', ///< No file info messages. SHM_FILEINFO = 'F', ///< No file info messages.
SHM_SEARCHCOUNT = 'S', ///< Search sats: '[1/10]'
}; };
/// Represented by 'a' flag. /// Represented by 'a' flag.
#define SHM_ALL_ABBREVIATIONS ((char_u[]) { \ #define SHM_ALL_ABBREVIATIONS ((char_u[]) { \

View File

@ -2134,7 +2134,7 @@ return {
type='string', list='flags', scope={'global'}, type='string', list='flags', scope={'global'},
vim=true, vim=true,
varname='p_shm', varname='p_shm',
defaults={if_true={vi="", vim="filnxtToOF"}} defaults={if_true={vi="S", vim="filnxtToOFS"}}
}, },
{ {
full_name='showbreak', abbreviation='sbr', full_name='showbreak', abbreviation='sbr',

View File

@ -14,6 +14,7 @@
#include "nvim/ascii.h" #include "nvim/ascii.h"
#include "nvim/vim.h" #include "nvim/vim.h"
#include "nvim/search.h" #include "nvim/search.h"
#include "nvim/buffer.h"
#include "nvim/charset.h" #include "nvim/charset.h"
#include "nvim/cursor.h" #include "nvim/cursor.h"
#include "nvim/edit.h" #include "nvim/edit.h"
@ -497,8 +498,8 @@ void last_pat_prog(regmmatch_T *regmatch)
} }
/// lowest level search function. /// lowest level search function.
/// Search for 'count'th occurrence of pattern 'pat' in direction 'dir'. /// Search for 'count'th occurrence of pattern "pat" in direction "dir".
/// Start at position 'pos' and return the found position in 'pos'. /// Start at position "pos" and return the found position in "pos".
/// ///
/// if (options & SEARCH_MSG) == 0 don't give any messages /// if (options & SEARCH_MSG) == 0 don't give any messages
/// if (options & SEARCH_MSG) == SEARCH_NFMSG don't give 'notfound' messages /// if (options & SEARCH_MSG) == SEARCH_NFMSG don't give 'notfound' messages
@ -519,6 +520,7 @@ int searchit(
buffer without a window! */ buffer without a window! */
buf_T *buf, buf_T *buf,
pos_T *pos, pos_T *pos,
pos_T *end_pos, // set to end of the match, unless NULL
Direction dir, Direction dir,
char_u *pat, char_u *pat,
long count, long count,
@ -819,11 +821,22 @@ int searchit(
pos->col -= utf_head_off(ptr, ptr + pos->col); pos->col -= utf_head_off(ptr, ptr + pos->col);
} }
} }
if (end_pos != NULL) {
end_pos->lnum = lnum + matchpos.lnum;
end_pos->col = matchpos.col;
}
} else { } else {
pos->lnum = lnum + matchpos.lnum; pos->lnum = lnum + matchpos.lnum;
pos->col = matchpos.col; pos->col = matchpos.col;
if (end_pos != NULL) {
end_pos->lnum = lnum + endpos.lnum;
end_pos->col = endpos.col;
}
} }
pos->coladd = 0; pos->coladd = 0;
if (end_pos != NULL) {
end_pos->coladd = 0;
}
found = 1; found = 1;
first_match = false; first_match = false;
@ -985,6 +998,10 @@ int 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;
bool has_offset = false;
#define SEARCH_STAT_BUF_LEN 12
/* /*
* A line offset is not remembered, this is vi compatible. * A line offset is not remembered, this is vi compatible.
@ -1040,6 +1057,8 @@ int do_search(
* Repeat the search when pattern followed by ';', e.g. "/foo/;?bar". * Repeat the search when pattern followed by ';', e.g. "/foo/;?bar".
*/ */
for (;; ) { for (;; ) {
bool show_top_bot_msg = false;
searchstr = pat; searchstr = pat;
dircp = NULL; dircp = NULL;
/* use previous pattern */ /* use previous pattern */
@ -1111,61 +1130,110 @@ int 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;
char_u off_buf[40];
int off_len = 0;
if (*searchstr == NUL) // Compute msg_row early.
msg_start();
// Get the offset, so we know how long it is.
if (spats[0].off.line || spats[0].off.end || spats[0].off.off) {
p = off_buf;
*p++ = dirc;
if (spats[0].off.end) {
*p++ = 'e';
} else if (!spats[0].off.line) {
*p++ = 's';
}
if (spats[0].off.off > 0 || spats[0].off.line) {
*p++ = '+';
}
*p = NUL;
if (spats[0].off.off != 0 || spats[0].off.line) {
snprintf((char *)p, sizeof(off_buf) - 1 - (p - off_buf),
"%" PRId64, spats[0].off.off);
}
off_len = STRLEN(off_buf);
}
if (*searchstr == NUL) {
p = spats[last_idx].pat; p = spats[last_idx].pat;
else } else {
p = searchstr; p = searchstr;
msgbuf = xmalloc(STRLEN(p) + 40); }
if (!shortmess(SHM_SEARCHCOUNT)) {
// Reserve enough space for the search pattern + offset +
// search stat. Use all the space available, so that the
// search state is right aligned. If there is not enough space
// msg_strtrunc() will shorten in the middle.
if (msg_scrolled != 0) {
// Use all the columns.
len = (int)(Rows - msg_row) * Columns - 1;
} else {
// Use up to 'showcmd' column.
len = (int)(Rows - msg_row - 1) * Columns + sc_col - 1;
}
if (len < STRLEN(p) + off_len + SEARCH_STAT_BUF_LEN + 3) {
len = STRLEN(p) + off_len + SEARCH_STAT_BUF_LEN + 3;
}
} else {
// Reserve enough space for the search pattern + offset.
len = STRLEN(p) + off_len + 3;
}
msgbuf = xmalloc((int)len);
{ {
memset(msgbuf, ' ', len);
msgbuf[0] = dirc; msgbuf[0] = dirc;
msgbuf[len - 1] = NUL;
if (utf_iscomposing(utf_ptr2char(p))) { if (utf_iscomposing(utf_ptr2char(p))) {
// Use a space to draw the composing char on. // Use a space to draw the composing char on.
msgbuf[1] = ' '; msgbuf[1] = ' ';
STRCPY(msgbuf + 2, p); memmove(msgbuf + 2, p, STRLEN(p));
} else } else {
STRCPY(msgbuf + 1, p); memmove(msgbuf + 1, p, STRLEN(p));
if (spats[0].off.line || spats[0].off.end || spats[0].off.off) { }
p = msgbuf + STRLEN(msgbuf); if (off_len > 0) {
*p++ = dirc; memmove(msgbuf + STRLEN(p) + 1, off_buf, off_len);
if (spats[0].off.end)
*p++ = 'e';
else if (!spats[0].off.line)
*p++ = 's';
if (spats[0].off.off > 0 || spats[0].off.line)
*p++ = '+';
if (spats[0].off.off != 0 || spats[0].off.line)
sprintf((char *)p, "%" PRId64, (int64_t)spats[0].off.off);
else
*p = NUL;
} }
msg_start(); trunc = msg_strtrunc(msgbuf, true);
trunc = msg_strtrunc(msgbuf, FALSE); if (trunc != NULL) {
xfree(msgbuf);
msgbuf = trunc;
}
/* 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 = reverse_text(trunc != NULL ? trunc : msgbuf); char_u *r = reverse_text(trunc != NULL ? trunc : msgbuf);
xfree(trunc); xfree(msgbuf);
trunc = r; msgbuf = r;
// move reversed text to beginning of buffer
while (*r != NUL && *r == ' ') {
r++;
}
size_t pat_len = msgbuf + STRLEN(msgbuf) - r;
memmove(msgbuf, r, pat_len);
// overwrite old text
if ((size_t)(r - msgbuf) >= pat_len) {
memset(r, ' ', pat_len);
} else {
memset(msgbuf + pat_len, ' ', r - msgbuf);
}
} }
if (trunc != NULL) { msg_outtrans(msgbuf);
msg_outtrans(trunc);
xfree(trunc);
} else
msg_outtrans(msgbuf);
msg_clr_eos(); msg_clr_eos();
msg_check(); msg_check();
xfree(msgbuf);
gotocmdline(FALSE); gotocmdline(false);
ui_flush(); ui_flush();
msg_nowait = TRUE; /* don't wait for this message */ msg_nowait = true; // don't wait for this message
} }
} }
@ -1196,7 +1264,7 @@ int do_search(
} }
} }
c = searchit(curwin, curbuf, &pos, dirc == '/' ? FORWARD : BACKWARD, c = searchit(curwin, curbuf, &pos, NULL, dirc == '/' ? FORWARD : BACKWARD,
searchstr, count, searchstr, count,
(spats[0].off.end * SEARCH_END (spats[0].off.end * SEARCH_END
+ (options + (options
@ -1205,8 +1273,16 @@ int do_search(
+ ((pat != NULL && *pat == ';') ? 0 : SEARCH_NOOF)))), + ((pat != NULL && *pat == ';') ? 0 : SEARCH_NOOF)))),
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, curwin->w_cursor))
|| (dirc == '?' && lt(curwin->w_cursor, pos)))) {
show_top_bot_msg = true;
}
if (c == FAIL) { if (c == FAIL) {
retval = 0; retval = 0;
goto end_do_search; goto end_do_search;
@ -1220,7 +1296,9 @@ int do_search(
* Add character and/or line offset * Add character and/or line offset
*/ */
if (!(options & SEARCH_NOOF) || (pat != NULL && *pat == ';')) { if (!(options & SEARCH_NOOF) || (pat != NULL && *pat == ';')) {
if (spats[0].off.line) { /* Add the offset to the line number. */ pos_T org_pos = pos;
if (spats[0].off.line) { // Add the offset to the line number.
c = pos.lnum + spats[0].off.off; c = pos.lnum + spats[0].off.off;
if (c < 1) if (c < 1)
pos.lnum = 1; pos.lnum = 1;
@ -1246,18 +1324,31 @@ int do_search(
break; break;
} }
} }
if (!equalpos(pos, org_pos)) {
has_offset = true;
}
} }
/* // Show [1/15] if 'S' is not in 'shortmess'.
* The search command can be followed by a ';' to do another search. if ((options & SEARCH_ECHO)
* For example: "/pat/;/foo/+3;?bar" && messaging()
* This is like doing another search command, except: && !(cmd_silent + msg_silent)
* - The remembered direction '/' or '?' is from the first search. && c != FAIL
* - When an error happens the cursor isn't moved at all. && !shortmess(SHM_SEARCHCOUNT)
* Don't do this when called by get_address() (it handles ';' itself). && msgbuf != NULL) {
*/ search_stat(dirc, &pos, show_top_bot_msg, msgbuf,
if (!(options & SEARCH_OPT) || pat == NULL || *pat != ';') (count != 1 || has_offset));
}
// The search command can be followed by a ';' to do another search.
// For example: "/pat/;/foo/+3;?bar"
// This is like doing another search command, except:
// - The remembered direction '/' or '?' is from the first search.
// - When an error happens the cursor isn't moved at all.
// Don't do this when called by get_address() (it handles ';' itself).
if (!(options & SEARCH_OPT) || pat == NULL || *pat != ';') {
break; break;
}
dirc = *++pat; dirc = *++pat;
if (dirc != '?' && dirc != '/') { if (dirc != '?' && dirc != '/') {
@ -1276,7 +1367,7 @@ int do_search(
end_do_search: 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;
xfree(strcopy); xfree(msgbuf);
return retval; return retval;
} }
@ -3933,7 +4024,7 @@ abort_search:
int int
current_search( current_search(
long count, long count,
int forward /* move forward or backwards */ int forward // true for forward, false for backward
) )
{ {
bool old_p_ws = p_ws; bool old_p_ws = p_ws;
@ -3946,8 +4037,8 @@ current_search(
if (VIsual_active && *p_sel == 'e' && lt(VIsual, curwin->w_cursor)) if (VIsual_active && *p_sel == 'e' && lt(VIsual, curwin->w_cursor))
dec_cursor(); dec_cursor();
pos_T end_pos; // end position of the pattern match
pos_T orig_pos; // position of the cursor at beginning pos_T orig_pos; // position of the cursor at beginning
pos_T first_match; // position of first match
pos_T pos; // position after the pattern pos_T pos; // position after the pattern
int result; // result of various function calls int result; // result of various function calls
@ -3981,78 +4072,52 @@ current_search(
int dir = forward ? i : !i; int dir = forward ? i : !i;
int flags = 0; int flags = 0;
if (!dir && !one_char) if (!dir && !one_char) {
flags = SEARCH_END; flags = SEARCH_END;
}
end_pos = pos;
result = searchit(curwin, curbuf, &pos, (dir ? FORWARD : BACKWARD), result = searchit(curwin, curbuf, &pos, &end_pos,
(dir ? FORWARD : BACKWARD),
spats[last_idx].pat, i ? count : 1, spats[last_idx].pat, i ? count : 1,
SEARCH_KEEP | flags, RE_SEARCH, 0, NULL, NULL); SEARCH_KEEP | flags, RE_SEARCH, 0, NULL, NULL);
/* First search may fail, but then start searching from the // First search may fail, but then start searching from the
* beginning of the file (cursor might be on the search match) // beginning of the file (cursor might be on the search match)
* except when Visual mode is active, so that extending the visual // except when Visual mode is active, so that extending the visual
* selection works. */ // selection works.
if (!result && i) { /* not found, abort */ if (i == 1 && !result) { // not found, abort */
curwin->w_cursor = orig_pos; curwin->w_cursor = orig_pos;
if (VIsual_active) if (VIsual_active)
VIsual = save_VIsual; VIsual = save_VIsual;
p_ws = old_p_ws; p_ws = old_p_ws;
return FAIL; return FAIL;
} else if (!i && !result) { } else if (i == 0 && !result) {
if (forward) { /* try again from start of buffer */ if (forward) { // try again from start of buffer
clearpos(&pos); clearpos(&pos);
} else { /* try again from end of buffer */ } else { // try again from end of buffer
/* searching backwards, so set pos to last line and col */ // searching backwards, so set pos to last line and col
pos.lnum = curwin->w_buffer->b_ml.ml_line_count; pos.lnum = curwin->w_buffer->b_ml.ml_line_count;
pos.col = (colnr_T)STRLEN( pos.col = (colnr_T)STRLEN(
ml_get(curwin->w_buffer->b_ml.ml_line_count)); ml_get(curwin->w_buffer->b_ml.ml_line_count));
} }
} }
if (i == 0) {
first_match = pos;
}
p_ws = old_p_ws; p_ws = old_p_ws;
} }
const int flags = forward ? SEARCH_END : SEARCH_START;
pos_T start_pos = pos; pos_T start_pos = pos;
const Direction direction = forward ? FORWARD : BACKWARD;
// Check again from the current cursor position,
// since the next match might actually be only one char wide
one_char = is_one_char(spats[last_idx].pat, false, &pos, direction);
if (one_char < 0) {
// search failed, abort
return FAIL;
}
/* move to match, except for zero-width matches, in which case, we are
* already on the next match */
if (!one_char) {
p_ws = false;
for (int i = 0; i < 2; i++) {
result = searchit(curwin, curbuf, &pos, direction,
spats[last_idx].pat, 0L, flags | SEARCH_KEEP, RE_SEARCH,
0, NULL, NULL);
// Search successfull, break out from the loop
if (result) {
break;
}
// search failed, try again from the last search position match
pos = first_match;
}
}
p_ws = old_p_ws; p_ws = old_p_ws;
// not found
if (!result) { if (!VIsual_active) {
return FAIL; VIsual = start_pos;
} }
if (!VIsual_active) // put cursor on last character of match
VIsual = start_pos; curwin->w_cursor = end_pos;
if (lt(VIsual, end_pos)) {
curwin->w_cursor = pos; dec_cursor();
}
VIsual_active = true; VIsual_active = true;
VIsual_mode = 'v'; VIsual_mode = 'v';
@ -4111,7 +4176,7 @@ static int is_one_char(char_u *pattern, bool move, pos_T *cur,
// accept a match at the cursor position // accept a match at the cursor position
flag = SEARCH_START; flag = SEARCH_START;
} }
if (searchit(curwin, curbuf, &pos, direction, pattern, 1, if (searchit(curwin, curbuf, &pos, NULL, direction, pattern, 1,
SEARCH_KEEP + flag, RE_SEARCH, 0, NULL, NULL) != FAIL) { SEARCH_KEEP + flag, RE_SEARCH, 0, NULL, NULL) != FAIL) {
// Zero-width pattern should match somewhere, then we can check if // Zero-width pattern should match somewhere, then we can check if
// start and end are in the same position. // start and end are in the same position.
@ -4155,6 +4220,120 @@ int linewhite(linenr_T lnum)
return *p == NUL; return *p == NUL;
} }
// Add the search count "[3/19]" to "msgbuf".
// When "recompute" is true Always recompute the numbers.
static void search_stat(int dirc, pos_T *pos,
bool show_top_bot_msg, char_u *msgbuf, bool recompute)
{
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;
proftime_T start;
#define OUT_OF_TIME 999
wraparound = ((dirc == '?' && lt(lastpos, p))
|| (dirc == '/' && lt(p, lastpos)));
// If anything relevant changed the count has to be recomputed.
// STRNICMP ignores case, but we should not ignore case.
// Unfortunately, there is no STRNICMP function.
if (!(chgtick == buf_get_changedtick(curbuf)
&& STRNICMP(lastpat, spats[last_idx].pat, STRLEN(lastpat)) == 0
&& STRLEN(lastpat) == STRLEN(spats[last_idx].pat)
&& equalpos(lastpos, curwin->w_cursor)
&& lbuf == curbuf)
|| wraparound || cur < 0 || cur > 99 || recompute) {
cur = 0;
cnt = 0;
clearpos(&lastpos);
lbuf = curbuf;
}
if (equalpos(lastpos, curwin->w_cursor) && !wraparound
&& (dirc == '/' ? cur < cnt : cur > 0)) {
cur += dirc == '/' ? 1 : -1;
} else {
p_ws = false;
start = profile_setlimit(20L);
while (!got_int && searchit(curwin, curbuf, &lastpos, NULL,
FORWARD, NULL, 1, SEARCH_KEEP, RE_LAST,
(linenr_T)0, NULL, NULL) != FAIL) {
// Stop after passing the time limit.
if (profile_passed_limit(start)) {
cnt = OUT_OF_TIME;
cur = OUT_OF_TIME;
break;
}
cnt++;
if (ltoreq(lastpos, p)) {
cur++;
}
fast_breakcheck();
if (cnt > 99) {
break;
}
}
if (got_int) {
cur = -1; // abort
}
}
if (cur > 0) {
char t[SEARCH_STAT_BUF_LEN] = "";
int len;
if (curwin->w_p_rl && *curwin->w_p_rlc == 's') {
if (cur == OUT_OF_TIME) {
vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[?/??]");
} else if (cnt > 99 && cur > 99) {
vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[>99/>99]");
} else if (cnt > 99) {
vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[>99/%d]", cur);
} else {
vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[%d/%d]", cnt, cur);
}
} else {
if (cur == OUT_OF_TIME) {
vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[?/??]");
} else if (cnt > 99 && cur > 99) {
vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[>99/>99]");
} else if (cnt > 99) {
vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[%d/>99]", cur);
} else {
vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[%d/%d]", cur, cnt);
}
}
len = STRLEN(t);
if (show_top_bot_msg && len + 2 < SEARCH_STAT_BUF_LEN) {
STRCPY(t + len, " W");
len += 2;
}
memmove(msgbuf + STRLEN(msgbuf) - len, t, len);
if (dirc == '?' && cur == 100) {
cur = -1;
}
xfree(lastpat);
lastpat = vim_strsave(spats[last_idx].pat);
chgtick = buf_get_changedtick(curbuf);
lbuf = curbuf;
lastpos = p;
// keep the message even after redraw, but don't put in history
msg_hist_off = true;
give_warning(msgbuf, false);
msg_hist_off = false;
}
p_ws = save_ws;
}
/* /*
* Find identifiers or defines in included files. * Find identifiers or defines in included files.
* If p_ic && (compl_cont_status & CONT_SOL) then ptr must be in lowercase. * If p_ic && (compl_cont_status & CONT_SOL) then ptr must be in lowercase.

View File

@ -133,4 +133,23 @@ func Test_gn_command()
set belloff&vim set belloff&vim
endfu endfu
func Test_gn_multi_line()
new
call setline(1, [
\ 'func Tm1()',
\ ' echo "one"',
\ 'endfunc',
\ 'func Tm2()',
\ ' echo "two"',
\ 'endfunc',
\ 'func Tm3()',
\ ' echo "three"',
\ 'endfunc',
\])
/\v^func Tm\d\(\)\n.*\zs".*"\ze$
normal jgnrx
call assert_equal(' echo xxxxx', getline(5))
bwipe!
endfunc
" vim: shiftwidth=2 sts=2 expandtab " vim: shiftwidth=2 sts=2 expandtab

View File

@ -609,3 +609,25 @@ func Test_search_match_at_curpos()
close! close!
endfunc endfunc
func Test_search_display_pattern()
new
call setline(1, ['foo', 'bar', 'foobar'])
call cursor(1, 1)
let @/ = 'foo'
let pat = escape(@/, '()*?'. '\s\+')
let g:a = execute(':unsilent :norm! n')
call assert_match(pat, g:a)
" right-left
if exists("+rightleft")
set rl
call cursor(1, 1)
let @/ = 'foo'
let pat = 'oof/\s\+'
let g:a = execute(':unsilent :norm! n')
call assert_match(pat, g:a)
set norl
endif
endfunc

View File

@ -0,0 +1,166 @@
" 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!
source shared.vim
func! Test_search_stat()
new
set shortmess-=S
" Append 50 lines with text to search for, "foobar" appears 20 times
call append(0, repeat(['foobar', 'foo', 'fooooobar', 'foba', 'foobar'], 10))
" match at second line
call cursor(1, 1)
let messages_before = execute('messages')
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)
" didn't get added to message history
call assert_equal(messages_before, execute('messages'))
" 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)
" 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
" 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)
call cursor(line('$'), 1)
let g:a = execute(':unsilent :norm! n')
let stat = '\[1/>99\] W'
call assert_match(pat .. stat, g:a)
" Many matches
call cursor(1, 1)
let g:a = execute(':unsilent :norm! n')
let stat = '\[2/>99\]'
call assert_match(pat .. stat, g:a)
call cursor(1, 1)
let g:a = execute(':unsilent :norm! N')
let stat = '\[>99/>99\] W'
call assert_match(pat .. stat, g:a)
" 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
" 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
" 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
" normal, back at bottom
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)
call assert_match('\[20/20\] W', 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
" with count
call cursor(1, 1)
let @/ = 'fo*\(bar\?\)\?'
let g:a = execute(':unsilent :norm! 2n')
let stat = '\[3/50\]'
let pat = escape(@/, '()*?'). '\s\+'
call assert_match(pat .. stat, g:a)
let g:a = execute(':unsilent :norm! 2n')
let stat = '\[5/50\]'
call assert_match(pat .. stat, g:a)
" with offset
call cursor(1, 1)
call feedkeys("/fo*\\(bar\\?\\)\\?/+1\<cr>", 'tx')
let g:a = execute(':unsilent :norm! n')
let stat = '\[5/50\]'
let pat = escape(@/ .. '/+1', '()*?'). '\s\+'
call assert_match(pat .. stat, g:a)
" normal, n comes from a mapping
" Need to move over more than 64 lines to trigger char_avail(.
nnoremap n nzv
call cursor(1,1)
call append(50, repeat(['foobar', 'foo', 'fooooobar', 'foba', 'foobar'], 10))
call setline(2, 'find this')
call setline(70, 'find this')
let @/ = 'find this'
let pat = '/find this\s\+'
let g:a = execute(':unsilent :norm n')
" g:a will contain several lines
let g:b = split(g:a, "\n")[-1]
let stat = '\[1/2\]'
call assert_match(pat .. stat, g:b)
unmap n
" normal, but silent
call cursor(1,1)
let @/ = 'find this'
let pat = '/find this\s\+'
let g:a = execute(':norm! n')
let stat = '\[1/2\]'
call assert_notmatch(pat .. stat, g:a)
" close the window
set shortmess+=S
bwipe!
endfunc