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

📄 search.c

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