📄 search.c
字号:
{
lnum = 1;
if (!shortmess(SHM_SEARCH) && (options & SEARCH_MSG))
give_warning(bot_top_msg, TRUE);
}
}
if (got_int)
break;
}
while (--count > 0 && found); /* stop after count matches or no match */
vim_free(prog);
if (!found) /* did not find it */
{
if (got_int)
emsg(e_interr);
else if ((options & SEARCH_MSG) == SEARCH_MSG)
{
if (p_ws)
emsg2(e_patnotf2, mr_pattern);
else if (lnum == 0)
EMSG2("search hit TOP without match for: %s", mr_pattern);
else
EMSG2("search hit BOTTOM without match for: %s", mr_pattern);
}
return FAIL;
}
search_match_len = matchend - match;
return OK;
}
/*
* Highest level string search function.
* Search for the 'count'th occurence of string 'str' in direction 'dirc'
* If 'dirc' is 0: use previous dir.
* If 'str' is NULL or empty : use previous string.
* If 'options & SEARCH_REV' : go in reverse of previous dir.
* If 'options & SEARCH_ECHO': echo the search command and handle options
* If 'options & SEARCH_MSG' : may give error message
* If 'options & SEARCH_OPT' : interpret optional flags
* If 'options & SEARCH_HIS' : put search pattern in history
* If 'options & SEARCH_NOOF': don't add offset to position
* If 'options & SEARCH_MARK': set previous context mark
* If 'options & SEARCH_KEEP': keep previous search pattern
* If 'options & SEARCH_START': accept match at curpos itself
*
* Careful: If spats[0].off.line == TRUE and spats[0].off.off == 0 this
* makes the movement linewise without moving the match position.
*
* return 0 for failure, 1 for found, 2 for found and line offset added
*/
int
do_search(oap, dirc, str, count, options)
OPARG *oap;
int dirc;
char_u *str;
long count;
int options;
{
FPOS pos; /* position of the last match */
char_u *searchstr;
struct soffset old_off;
int retval; /* Return value */
char_u *p;
long c;
char_u *dircp;
/*
* A line offset is not remembered, this is vi compatible.
*/
if (spats[0].off.line && vim_strchr(p_cpo, CPO_LINEOFF) != NULL)
{
spats[0].off.line = FALSE;
spats[0].off.off = 0;
}
/*
* Save the values for when (options & SEARCH_KEEP) is used.
* (there is no "if ()" around this because gcc wants them initialized)
*/
old_off = spats[0].off;
pos = curwin->w_cursor; /* start searching at the cursor position */
/*
* Find out the direction of the search.
*/
if (dirc == 0)
dirc = spats[0].off.dir;
else
spats[0].off.dir = dirc;
if (options & SEARCH_REV)
{
#ifdef WIN32
/* There is a bug in the Visual C++ 2.2 compiler which means that
* dirc always ends up being '/' */
dirc = (dirc == '/') ? '?' : '/';
#else
if (dirc == '/')
dirc = '?';
else
dirc = '/';
#endif
}
#ifdef EXTRA_SEARCH
if (no_hlsearch)
{
redraw_all_later(NOT_VALID);
no_hlsearch = FALSE;
}
#endif
/*
* Repeat the search when pattern followed by ';', e.g. "/foo/;?bar".
*/
for (;;)
{
searchstr = str;
dircp = NULL;
/* use previous pattern */
if (str == NULL || *str == NUL || *str == dirc)
{
if (spats[RE_SEARCH].pat == NULL) /* no previous pattern */
{
emsg(e_noprevre);
retval = 0;
goto end_do_search;
}
/* make search_regcomp() use spats[RE_SEARCH].pat */
searchstr = (char_u *)"";
}
if (str != NULL && *str != NUL) /* look for (new) offset */
{
/*
* Find end of regular expression.
* If there is a matching '/' or '?', toss it.
*/
p = skip_regexp(str, dirc, (int)p_magic);
if (*p == dirc)
{
dircp = p; /* remember where we put the NUL */
*p++ = NUL;
}
spats[0].off.line = FALSE;
spats[0].off.end = FALSE;
spats[0].off.off = 0;
/*
* Check for a line offset or a character offset.
* For get_address (echo off) we don't check for a character
* offset, because it is meaningless and the 's' could be a
* substitute command.
*/
if (*p == '+' || *p == '-' || isdigit(*p))
spats[0].off.line = TRUE;
else if ((options & SEARCH_OPT) &&
(*p == 'e' || *p == 's' || *p == 'b'))
{
if (*p == 'e') /* end */
spats[0].off.end = SEARCH_END;
++p;
}
if (isdigit(*p) || *p == '+' || *p == '-') /* got an offset */
{
/* 'nr' or '+nr' or '-nr' */
if (isdigit(*p) || isdigit(*(p + 1)))
spats[0].off.off = atol((char *)p);
else if (*p == '-') /* single '-' */
spats[0].off.off = -1;
else /* single '+' */
spats[0].off.off = 1;
++p;
while (isdigit(*p)) /* skip number */
++p;
}
searchcmdlen = p - str; /* compute length of search command
for get_address() */
str = p; /* put str after search command */
}
if ((options & SEARCH_ECHO) && messaging())
{
msg_start();
msg_putchar(dirc);
msg_outtrans(*searchstr == NUL ? spats[RE_SEARCH].pat : searchstr);
if (spats[0].off.line || spats[0].off.end || spats[0].off.off)
{
msg_putchar(dirc);
if (spats[0].off.end)
msg_putchar('e');
else if (!spats[0].off.line)
msg_putchar('s');
if (spats[0].off.off < 0)
msg_outnum((long)spats[0].off.off);
else if (spats[0].off.off > 0 || spats[0].off.line)
{
msg_putchar('+');
msg_outnum((long)spats[0].off.off);
}
}
msg_clr_eos();
(void)msg_check();
gotocmdline(FALSE);
out_flush();
msg_nowait = TRUE; /* don't wait for this message */
}
/*
* If there is a character offset, subtract it from the current
* position, so we don't get stuck at "?pat?e+2" or "/pat/s-2".
* This is not done for a line offset, because then we would not be vi
* compatible.
*/
if (!spats[0].off.line && spats[0].off.off)
{
if (spats[0].off.off > 0)
{
for (c = spats[0].off.off; c; --c)
if (decl(&pos) == -1)
break;
if (c) /* at start of buffer */
{
pos.lnum = 0; /* allow lnum == 0 here */
pos.col = MAXCOL;
}
}
else
{
for (c = spats[0].off.off; c; ++c)
if (incl(&pos) == -1)
break;
if (c) /* at end of buffer */
{
pos.lnum = curbuf->b_ml.ml_line_count + 1;
pos.col = 0;
}
}
}
#ifdef FKMAP /* when in Farsi mode, reverse the character flow */
if (p_altkeymap && curwin->w_p_rl)
lrFswap(searchstr,0);
#endif
c = searchit(curbuf, &pos, dirc == '/' ? FORWARD : BACKWARD,
searchstr, count, spats[0].off.end + (options &
(SEARCH_KEEP + SEARCH_HIS + SEARCH_MSG + SEARCH_START +
((str != NULL && *str == ';') ? 0 : SEARCH_NOOF))),
2);
if (dircp != NULL)
*dircp = dirc; /* restore second '/' or '?' for normal_cmd() */
if (c == FAIL)
{
retval = 0;
goto end_do_search;
}
if (spats[0].off.end && oap != NULL)
oap->inclusive = TRUE; /* 'e' includes last character */
retval = 1; /* pattern found */
/*
* Add character and/or line offset
*/
if (!(options & SEARCH_NOOF) || *str == ';')
{
if (spats[0].off.line) /* Add the offset to the line number. */
{
c = pos.lnum + spats[0].off.off;
if (c < 1)
pos.lnum = 1;
else if (c > curbuf->b_ml.ml_line_count)
pos.lnum = curbuf->b_ml.ml_line_count;
else
pos.lnum = c;
pos.col = 0;
retval = 2; /* pattern found, line offset added */
}
else
{
/* to the right, check for end of file */
if (spats[0].off.off > 0)
{
for (c = spats[0].off.off; c; --c)
if (incl(&pos) == -1)
break;
}
/* to the left, check for start of file */
else
{
if ((c = pos.col + spats[0].off.off) >= 0)
pos.col = c;
else
for (c = spats[0].off.off; c; ++c)
if (decl(&pos) == -1)
break;
}
}
}
/*
* 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) || str == NULL || *str != ';')
break;
dirc = *++str;
if (dirc != '?' && dirc != '/')
{
retval = 0;
EMSG("Expected '?' or '/' after ';'");
goto end_do_search;
}
++str;
}
if (options & SEARCH_MARK)
setpcmark();
curwin->w_cursor = pos;
curwin->w_set_curswant = TRUE;
end_do_search:
if (options & SEARCH_KEEP)
spats[0].off = old_off;
return retval;
}
#if defined(INSERT_EXPAND) || defined(PROTO)
/*
* search_for_exact_line(buf, pos, dir, pat)
*
* Search for a line starting with the given pattern (ignoring leading
* white-space), starting from pos and going in direction dir. pos will
* contain the position of the match found. Blank lines match only if
* ADDING is set. if p_ic is set then the pattern must be in lowercase.
* Return OK for success, or FAIL if no line found.
*/
int
search_for_exact_line(buf, pos, dir, pat)
BUF *buf;
FPOS *pos;
int dir;
char_u *pat;
{
linenr_t start = 0;
char_u *ptr;
char_u *p;
if (buf->b_ml.ml_line_count == 0)
return FAIL;
for (;;)
{
pos->lnum += dir;
if (pos->lnum < 1)
{
if (p_ws)
{
pos->lnum = buf->b_ml.ml_line_count;
if (!shortmess(SHM_SEARCH))
give_warning(top_bot_msg, TRUE);
}
else
{
pos->lnum = 1;
break;
}
}
else if (pos->lnum > buf->b_ml.ml_line_count)
{
if (p_ws)
{
pos->lnum = 1;
if (!shortmess(SHM_SEARCH))
give_warning(bot_top_msg, TRUE);
}
else
{
pos->lnum = 1;
break;
}
}
if (pos->lnum == start)
break;
if (start == 0)
start = pos->lnum;
ptr = ml_get_buf(buf, pos->lnum, FALSE);
p = skipwhite(ptr);
pos->col = p - ptr;
/* when adding lines the matching line may be empty but it is not
* ignored because we are interested in the next line -- Acevedo */
if ((continue_status & CONT_ADDING) && !(continue_status & CONT_SOL))
{
if (p_ic)
{
/*
if (STRICMP(p, pat) == 0)
*/
for (ptr = pat; TO_LOWER(*p) == *ptr && *p; p++, ptr++)
;
if (*p == *ptr) /* only possible if both NUL, exact match */
return OK;
}
else if (STRCMP(p, pat) == 0)
return OK;
}
else if (*p) /* ignore empty lines */
{ /* expanding lines or words */
if (p_ic)
{
/*
if (STRNICMP(p, pat, completion_length) == 0)
*/
for (ptr = pat; TO_LOWER(*p) == *ptr && *p; p++, ptr++)
;
if (*ptr == NUL)
return OK;
}
else if (STRNCMP(p, pat, completion_length) == 0)
return OK;
}
}
return FAIL;
}
#endif /* INSERT_EXPAND */
/*
* Character Searches
*/
/*
* searchc(c, dir, type, count)
*
* Search for character 'c', in direction 'dir'. If 'type' is 0, move to the
* position of the character, otherwise move to just before the char.
* Repeat this 'count' times.
*/
int
searchc(c, dir, type, count)
int c;
int dir;
int type;
long count;
{
static int lastc = NUL; /* last character searched for */
static int lastcdir; /* last direction of character search */
static int lastctype; /* last type of search ("find" or "to") */
int col;
char_u *p;
int len;
if (c != NUL) /* normal search: remember args for repeat */
{
if (!KeyStuffed) /* don't remember when redoing */
{
lastc = c;
lastcdir = dir;
lastctype = type;
}
}
else /* repeat previous search */
{
if (lastc == NUL)
return FALSE;
if (dir) /* repeat in opposite direction */
dir = -lastcdir;
else
dir = lastcdir;
type = lastctype;
c = lastc;
}
p = ml_get_curline();
col = curwin->w_cursor.col;
len = STRLEN(p);
while (count--)
{
for (;;)
{
if ((col += dir) < 0 || col >= len)
return FALSE;
if (p[col] == c)
break;
}
}
if (type)
col -= dir;
curwin->w_cursor.col = col;
return TRUE;
}
/*
* "Other" Searches
*/
/*
* findmatch - find the matching paren or brace
*
* Improvement over vi: Braces inside quotes are ignored.
*/
FPOS *
findmatch(oap, initc)
OPARG *oap;
int initc;
{
return findmatchlimit(oap, initc, 0, 0);
}
/*
* findmatchlimit -- find the matching paren or brace, if it exists within
* maxtravel lines of here. A maxtravel of 0 means search until falling off
* the edge of the file.
*
* "initc" is the character to find a match for. NUL means to find the
* character at or after the cursor.
*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -