⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 search.c

📁 VIM文本编辑器
💻 C
📖 第 1 页 / 共 5 页
字号:
	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 + -