📄 search.c
字号:
return &pos;
}
return (FPOS *)NULL; /* never found it */
}
/*
* Check if line[] contains a / / comment.
* Return MAXCOL if not, otherwise return the column.
* TODO: skip strings.
*/
static int
check_linecomment(line)
char_u *line;
{
char_u *p;
p = line;
while ((p = vim_strchr(p, '/')) != NULL)
{
if (p[1] == '/')
break;
++p;
}
if (p == NULL)
return MAXCOL;
return (int)(p - line);
}
/*
* Move cursor briefly to character matching the one under the cursor.
* Show the match only if it is visible on the screen.
*/
void
showmatch()
{
FPOS *lpos, save_cursor;
FPOS mpos;
colnr_t vcol;
long save_so;
#ifdef CURSOR_SHAPE
int save_state;
#endif
if ((lpos = findmatch(NULL, NUL)) == NULL) /* no match, so beep */
vim_beep();
else if (lpos->lnum >= curwin->w_topline)
{
if (!curwin->w_p_wrap)
getvcol(curwin, lpos, NULL, &vcol, NULL);
if (curwin->w_p_wrap || (vcol >= curwin->w_leftcol &&
vcol < curwin->w_leftcol + Columns))
{
mpos = *lpos; /* save the pos, update_screen() may change it */
update_screen(VALID_TO_CURSCHAR); /* show the new char first */
save_cursor = curwin->w_cursor;
save_so = p_so;
#ifdef CURSOR_SHAPE
save_state = State;
State = SHOWMATCH;
ui_cursor_shape(); /* may show different cursor shape */
#endif
curwin->w_cursor = mpos; /* move to matching char */
p_so = 0; /* don't use 'scrolloff' here */
showruler(FALSE);
setcursor();
cursor_on(); /* make sure that the cursor is shown */
out_flush();
/*
* brief pause, unless 'm' is present in 'cpo' and a character is
* available.
*/
if (vim_strchr(p_cpo, CPO_SHOWMATCH) != NULL)
ui_delay(p_mat * 100L, TRUE);
else if (!char_avail())
ui_delay(p_mat * 100L, FALSE);
curwin->w_cursor = save_cursor; /* restore cursor position */
p_so = save_so;
#ifdef CURSOR_SHAPE
State = save_state;
ui_cursor_shape(); /* may show different cursor shape */
#endif
}
}
}
/*
* findsent(dir, count) - Find the start of the next sentence in direction
* 'dir' Sentences are supposed to end in ".", "!" or "?" followed by white
* space or a line break. Also stop at an empty line.
* Return OK if the next sentence was found.
*/
int
findsent(dir, count)
int dir;
long count;
{
FPOS pos, tpos;
int c;
int (*func) __ARGS((FPOS *));
int startlnum;
int noskip = FALSE; /* do not skip blanks */
pos = curwin->w_cursor;
if (dir == FORWARD)
func = incl;
else
func = decl;
while (count--)
{
/*
* if on an empty line, skip upto a non-empty line
*/
if (gchar(&pos) == NUL)
{
do
if ((*func)(&pos) == -1)
break;
while (gchar(&pos) == NUL);
if (dir == FORWARD)
goto found;
}
/*
* if on the start of a paragraph or a section and searching forward,
* go to the next line
*/
else if (dir == FORWARD && pos.col == 0 &&
startPS(pos.lnum, NUL, FALSE))
{
if (pos.lnum == curbuf->b_ml.ml_line_count)
return FAIL;
++pos.lnum;
goto found;
}
else if (dir == BACKWARD)
decl(&pos);
/* go back to the previous non-blank char */
while ((c = gchar(&pos)) == ' ' || c == '\t' ||
(dir == BACKWARD && vim_strchr((char_u *)".!?)]\"'", c) != NULL))
{
if (decl(&pos) == -1)
break;
/* when going forward: Stop in front of empty line */
if (lineempty(pos.lnum) && dir == FORWARD)
{
incl(&pos);
goto found;
}
}
/* remember the line where the search started */
startlnum = pos.lnum;
for (;;) /* find end of sentence */
{
c = gchar(&pos);
if (c == NUL || (pos.col == 0 && startPS(pos.lnum, NUL, FALSE)))
{
if (dir == BACKWARD && pos.lnum != startlnum)
++pos.lnum;
break;
}
if (c == '.' || c == '!' || c == '?')
{
tpos = pos;
do
if ((c = inc(&tpos)) == -1)
break;
while (vim_strchr((char_u *)")]\"'", c = gchar(&tpos)) != NULL);
if (c == -1 || c == ' ' || c == '\t' || c == NUL)
{
pos = tpos;
if (gchar(&pos) == NUL) /* skip NUL at EOL */
inc(&pos);
break;
}
}
if ((*func)(&pos) == -1)
{
if (count)
return FAIL;
noskip = TRUE;
break;
}
}
found:
/* skip white space */
while (!noskip && ((c = gchar(&pos)) == ' ' || c == '\t'))
if (incl(&pos) == -1)
break;
}
setpcmark();
curwin->w_cursor = pos;
return OK;
}
/*
* findpar(dir, count, what) - Find the next paragraph in direction 'dir'
* Paragraphs are currently supposed to be separated by empty lines.
* Return TRUE if the next paragraph was found.
* If 'what' is '{' or '}' we go to the next section.
* If 'both' is TRUE also stop at '}'.
*/
int
findpar(oap, dir, count, what, both)
OPARG *oap;
int dir;
long count;
int what;
int both;
{
linenr_t curr;
int did_skip; /* TRUE after separating lines have been skipped */
int first; /* TRUE on first line */
curr = curwin->w_cursor.lnum;
while (count--)
{
did_skip = FALSE;
for (first = TRUE; ; first = FALSE)
{
if (*ml_get(curr) != NUL)
did_skip = TRUE;
if (!first && did_skip && startPS(curr, what, both))
break;
if ((curr += dir) < 1 || curr > curbuf->b_ml.ml_line_count)
{
if (count)
return FALSE;
curr -= dir;
break;
}
}
}
setpcmark();
if (both && *ml_get(curr) == '}') /* include line with '}' */
++curr;
curwin->w_cursor.lnum = curr;
if (curr == curbuf->b_ml.ml_line_count)
{
if ((curwin->w_cursor.col = STRLEN(ml_get(curr))) != 0)
{
--curwin->w_cursor.col;
oap->inclusive = TRUE;
}
}
else
curwin->w_cursor.col = 0;
return TRUE;
}
/*
* check if the string 's' is a nroff macro that is in option 'opt'
*/
static int
inmacro(opt, s)
char_u *opt;
char_u *s;
{
char_u *macro;
for (macro = opt; macro[0]; ++macro)
{
if (macro[0] == s[0] && (((s[1] == NUL || s[1] == ' ') &&
(macro[1] == NUL || macro[1] == ' ')) || macro[1] == s[1]))
break;
++macro;
if (macro[0] == NUL)
break;
}
return (macro[0] != NUL);
}
/*
* startPS: return TRUE if line 'lnum' is the start of a section or paragraph.
* If 'para' is '{' or '}' only check for sections.
* If 'both' is TRUE also stop at '}'
*/
int
startPS(lnum, para, both)
linenr_t lnum;
int para;
int both;
{
char_u *s;
s = ml_get(lnum);
if (*s == para || *s == '\f' || (both && *s == '}'))
return TRUE;
if (*s == '.' && (inmacro(p_sections, s + 1) ||
(!para && inmacro(p_para, s + 1))))
return TRUE;
return FALSE;
}
/*
* The following routines do the word searches performed by the 'w', 'W',
* 'b', 'B', 'e', and 'E' commands.
*/
/*
* To perform these searches, characters are placed into one of three
* classes, and transitions between classes determine word boundaries.
*
* The classes are:
*
* 0 - white space
* 1 - keyword charactes (letters, digits and underscore)
* 2 - everything else
*/
static int stype; /* type of the word motion being performed */
/*
* cls() - returns the class of character at curwin->w_cursor
*
* The 'type' of the current search modifies the classes of characters if a
* 'W', 'B', or 'E' motion is being done. In this case, chars. from class 2
* are reported as class 1 since only white space boundaries are of interest.
*/
static int
cls()
{
int c;
c = gchar_cursor();
#ifdef FKMAP /* when 'akm' (Farsi mode), take care of Farsi blank */
if (p_altkeymap && c == F_BLANK)
return 0;
#endif
if (c == ' ' || c == '\t' || c == NUL)
return 0;
#ifdef MULTI_BYTE
if (is_dbcs && IsLeadByte(c))
return 3;
#endif
if (vim_iswordc(c))
return 1;
/*
* If stype is non-zero, report these as class 1.
*/
return (stype == 0) ? 2 : 1;
}
/*
* fwd_word(count, type, eol) - move forward one word
*
* Returns FAIL if the cursor was already at the end of the file.
* If eol is TRUE, last word stops at end of line (for operators).
*/
int
fwd_word(count, type, eol)
long count;
int type;
int eol;
{
int sclass; /* starting class */
int i;
int last_line;
stype = type;
while (--count >= 0)
{
sclass = cls();
/*
* We always move at least one character, unless on the last character
* in the buffer.
*/
last_line = (curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count);
i = inc_cursor();
if (i == -1 || (i == 1 && last_line)) /* started at last char in file */
return FAIL;
if (i == 1 && eol && count == 0) /* started at last char in line */
return OK;
/*
* Go one char past end of current word (if any)
*/
if (sclass != 0)
while (cls() == sclass)
{
i = inc_cursor();
if (i == -1 || (i == 1 && eol && count == 0))
return OK;
}
/*
* go to next non-white
*/
while (cls() == 0)
{
/*
* We'll stop if we land on a blank line
*/
if (curwin->w_cursor.col == 0 && *ml_get_curline() == NUL)
break;
i = inc_cursor();
if (i == -1 || (i == 1 && eol && count == 0))
return OK;
}
}
return OK;
}
/*
* bck_word() - move backward 'count' words
*
* If stop is TRUE and we are already on the start of a word, move one less.
*
* Returns FAIL if top of the file was reached.
*/
int
bck_word(count, type, stop)
long count;
int type;
int stop;
{
int sclass; /* starting class */
stype = type;
while (--count >= 0)
{
sclass = cls();
if (dec_cursor() == -1) /* started at start of file */
return FAIL;
if (!stop || sclass == cls() || sclass == 0)
{
/*
* Skip white space before the word.
* Stop on an empty line.
*/
while (cls() == 0)
{
if (curwin->w_cursor.col == 0 &&
lineempty(curwin->w_cursor.lnum))
goto finished;
if (dec_cursor() == -1) /* hit start of file, stop here */
return OK;
}
/*
* Move backward to start of this word.
*/
if (skip_chars(cls(), BACKWARD))
return OK;
}
inc_cursor(); /* overshot - forward one */
finished:
stop = FALSE;
}
return OK;
}
/*
* end_word() - move to the end of the word
*
* There is an apparent bug in the 'e' motion of the real vi. At least on the
* System V Release 3 version for the 80386. Unlike 'b' and 'w', the 'e'
* motion crosses blank lines. When the real vi crosses a blank line in an
* 'e' motion, the cursor is placed on the FIRST character of the next
* non-blank line. The 'E' command, however, works correctly. Since this
* appears to be a bug, I have not duplicated it here.
*
* Returns FAIL if end of the file was reached.
*
* If stop is TRUE and we are already on the end of a word, move one less.
* If empty is TRUE stop on an empty line.
*/
int
end_word(count, type, stop, empty)
long count;
int type;
int stop;
int empty;
{
int sclass; /* starting class */
stype = type;
while (--count >= 0)
{
sclass = cls();
if (inc_cursor() == -1)
return FAIL;
/*
* If we're in the middle of a word, we just have to move to the end
* of it.
*/
if (cls() == sclass && sclass != 0)
{
/*
* Move forward to end of the current word
*/
if (skip_chars(sclass, FORWARD))
return FAIL;
}
else if (!stop || sclass == 0)
{
/*
* We were at the end of a word. Go to the end of the next word.
* First skip white space, if 'empty' is TRUE, stop at empty line.
*/
while (cls() == 0)
{
if (empty && curwin->w_cursor.col == 0 &&
lineempty(curwin->w_cursor.lnum))
goto finished;
if (inc_cursor() == -1) /* hit end of file, stop here */
return FAIL;
}
/*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -