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

📄 misc1.c

📁 VIM文本编辑器
💻 C
📖 第 1 页 / 共 5 页
字号:
/* vi:set ts=8 sts=4 sw=4:
 *
 * VIM - Vi IMproved	by Bram Moolenaar
 *
 * Do ":help uganda"  in Vim to read copying and usage conditions.
 * Do ":help credits" in Vim to see a list of people who contributed.
 */

/*
 * misc1.c: functions that didn't seem to fit elsewhere
 */

#include "vim.h"

#ifdef HAVE_FCNTL_H
# include <fcntl.h>		/* for chdir() */
#endif

static int get_indent_str __ARGS((char_u *ptr));

/*
 * count the size of the indent in the current line
 */
    int
get_indent()
{
    return get_indent_str(ml_get_curline());
}

/*
 * count the size of the indent in line "lnum"
 */
    int
get_indent_lnum(lnum)
    linenr_t	lnum;
{
    return get_indent_str(ml_get(lnum));
}

/*
 * count the size of the indent in line "ptr"
 */
    static int
get_indent_str(ptr)
    char_u  *ptr;
{
    int	    count = 0;

    for ( ; *ptr; ++ptr)
    {
	if (*ptr == TAB)    /* count a tab for what it is worth */
	    count += (int)curbuf->b_p_ts - (count % (int)curbuf->b_p_ts);
	else if (*ptr == ' ')
	    ++count;		/* count a space for one */
	else
	    break;
    }
    return (count);
}

/*
 * set the indent of the current line
 * leaves the cursor on the first non-blank in the line
 */
    void
set_indent(size, del_first)
    int		size;
    int		del_first;
{
    int		oldstate = State;
    int		c;
#ifdef RIGHTLEFT
    int		old_p_ri = p_ri;

    p_ri = 0;			    /* don't want revins in ident */
#endif

    State = INSERT;		    /* don't want REPLACE for State */
    curwin->w_cursor.col = 0;
    if (del_first)		    /* delete old indent */
    {
				    /* vim_iswhite() is a define! */
	while ((c = gchar_cursor()), vim_iswhite(c))
	    (void)del_char(FALSE);
    }
    if (!curbuf->b_p_et)	    /* if 'expandtab' is set, don't use TABs */
	while (size >= (int)curbuf->b_p_ts)
	{
	    ins_char(TAB);
	    size -= (int)curbuf->b_p_ts;
	}
    while (size)
    {
	ins_char(' ');
	--size;
    }
    State = oldstate;
#ifdef RIGHTLEFT
    p_ri = old_p_ri;
#endif
}

#if defined(CINDENT) || defined(SMARTINDENT)

static int cin_is_cinword __ARGS((char_u *line));

/*
 * Return TRUE if the string "line" starts with a word from 'cinwords'.
 */
    static int
cin_is_cinword(line)
    char_u	*line;
{
    char_u  *cinw;
    char_u  *cinw_buf;
    int	    cinw_len;
    int	    retval = FALSE;
    int	    len;

    cinw_len = STRLEN(curbuf->b_p_cinw) + 1;
    cinw_buf = alloc((unsigned)cinw_len);
    if (cinw_buf != NULL)
    {
	line = skipwhite(line);
	for (cinw = curbuf->b_p_cinw; *cinw; )
	{
	    len = copy_option_part(&cinw, cinw_buf, cinw_len, ",");
	    if (STRNCMP(line, cinw_buf, len) == 0 &&
		     (!vim_iswordc(line[len]) || !vim_iswordc(line[len - 1])))
	    {
		retval = TRUE;
		break;
	    }
	}
	vim_free(cinw_buf);
    }
    return retval;
}
#endif

/*
 * open_line: Add a new line below or above the current line.
 *
 * Caller must take care of undo.
 *
 * Return TRUE for success, FALSE for failure
 */
    int
open_line(dir, redraw, del_spaces, old_indent)
    int		dir;		/* FORWARD or BACKWARD */
    int		redraw;		/* > 0: redraw afterwards, < 0: insert lines*/
    int		del_spaces;	/* delete spaces after cursor */
    int		old_indent;	/* indent for after ^^D in Insert mode */
{
    char_u  *saved_line;	/* copy of the original line */
    char_u  *p_extra = NULL;	/* what goes to next line */
    int	    extra_len = 0;	/* length of p_extra string */
    FPOS    old_cursor;		/* old cursor position */
    int	    newcol = 0;		/* new cursor column */
    int	    newindent = 0;	/* auto-indent of the new line */
    int	    n;
    int	    trunc_line = FALSE;	/* truncate current line afterwards */
    int	    retval = FALSE;	/* return value, default is FAIL */
    int	    lead_len;		/* length of comment leader */
    char_u  *lead_flags;	/* position in 'comments' for comment leader */
    char_u  *leader = NULL;	/* copy of comment leader */
    char_u  *allocated = NULL;	/* allocated memory */
    char_u  *p;
    int	    saved_char = NUL;	/* init for GCC */
    FPOS    *pos;
    int	    old_plines = 0;	/* init for GCC */
    int	    new_plines = 0;	/* init for GCC */
#ifdef SMARTINDENT
    int	    no_si = FALSE;	/* reset did_si afterwards */
    int	    first_char = NUL;	/* init for GCC */
#endif

    /*
     * make a copy of the current line so we can mess with it
     */
    saved_line = vim_strsave(ml_get_curline());
    if (saved_line == NULL)	    /* out of memory! */
	return FALSE;

    if (State == INSERT || State == REPLACE)
    {
	p_extra = saved_line + curwin->w_cursor.col;
#ifdef SMARTINDENT
	if (curbuf->b_p_si)	    /* need first char after new line break */
	{
	    p = skipwhite(p_extra);
	    first_char = *p;
	}
#endif
	extra_len = STRLEN(p_extra);
	saved_char = *p_extra;
	*p_extra = NUL;
    }

    u_clearline();		/* cannot do "U" command when adding lines */
#ifdef SMARTINDENT
    did_si = FALSE;
#endif

    /*
     * If 'autoindent' and/or 'smartindent' is set, try to figure out what
     * indent to use for the new line.
     */
    if (curbuf->b_p_ai
#ifdef SMARTINDENT
			|| curbuf->b_p_si
#endif
					    )
    {
	/*
	 * count white space on current line
	 */
	newindent = get_indent();
	if (newindent == 0)
	    newindent = old_indent;	/* for ^^D command in insert mode */

	/*
	 * If we just did an auto-indent, then we didn't type anything on
	 * the prior line, and it should be truncated.
	 */
	if (dir == FORWARD && did_ai)
	    trunc_line = TRUE;

#ifdef SMARTINDENT
	/*
	 * Do smart indenting.
	 * In insert/replace mode (only when dir == FORWARD)
	 * we may move some text to the next line. If it starts with '{'
	 * don't add an indent. Fixes inserting a NL before '{' in line
	 *	"if (condition) {"
	 */
	else if (curbuf->b_p_si && *saved_line != NUL &&
				       (p_extra == NULL || first_char != '{'))
	{
	    char_u  *ptr;
	    char_u  last_char;

	    old_cursor = curwin->w_cursor;
	    ptr = saved_line;
	    lead_len = get_leader_len(ptr, NULL);
	    if (dir == FORWARD)
	    {
		/*
		 * Skip preprocessor directives, unless they are
		 * recognised as comments.
		 */
		if (lead_len == 0 && ptr[0] == '#')
		{
		    while (ptr[0] == '#' && curwin->w_cursor.lnum > 1)
			ptr = ml_get(--curwin->w_cursor.lnum);
		    newindent = get_indent();
		}
		lead_len = get_leader_len(ptr, NULL);
		if (lead_len > 0)
		{
		    /*
		     * This case gets the following right:
		     *	    \*
		     *	     * A comment (read '\' as '/').
		     *	     *\
		     * #define IN_THE_WAY
		     *	    This should line up here;
		     */
		    p = skipwhite(ptr);
		    if (p[0] == '/' && p[1] == '*')
			p++;
		    if (p[0] == '*')
		    {
			for (p++; *p; p++)
			{
			    if (p[0] == '/' && p[-1] == '*')
			    {
				/*
				 * End of C comment, indent should line up
				 * with the line containing the start of
				 * the comment
				 */
				curwin->w_cursor.col = p - ptr;
				if ((pos = findmatch(NULL, NUL)) != NULL)
				{
				    curwin->w_cursor.lnum = pos->lnum;
				    newindent = get_indent();
				}
			    }
			}
		    }
		}
		else	/* Not a comment line */
		{
		    /* Find last non-blank in line */
		    p = ptr + STRLEN(ptr) - 1;
		    while (p > ptr && vim_iswhite(*p))
			--p;
		    last_char = *p;

		    /*
		     * find the character just before the '{' or ';'
		     */
		    if (last_char == '{' || last_char == ';')
		    {
			if (p > ptr)
			    --p;
			while (p > ptr && vim_iswhite(*p))
			    --p;
		    }
		    /*
		     * Try to catch lines that are split over multiple
		     * lines.  eg:
		     *	    if (condition &&
		     *			condition) {
		     *		Should line up here!
		     *	    }
		     */
		    if (*p == ')')
		    {
			curwin->w_cursor.col = p - ptr;
			if ((pos = findmatch(NULL, '(')) != NULL)
			{
			    curwin->w_cursor.lnum = pos->lnum;
			    newindent = get_indent();
			    ptr = ml_get_curline();
			}
		    }
		    /*
		     * If last character is '{' do indent, without
		     * checking for "if" and the like.
		     */
		    if (last_char == '{')
		    {
			did_si = TRUE;	/* do indent */
			no_si = TRUE;	/* don't delete it when '{' typed */
		    }
		    /*
		     * Look for "if" and the like, use 'cinwords'.
		     * Don't do this if the previous line ended in ';' or
		     * '}'.
		     */
		    else if (last_char != ';' && last_char != '}'
						       && cin_is_cinword(ptr))
			did_si = TRUE;
		}
	    }
	    else /* dir == BACKWARD */
	    {
		/*
		 * Skip preprocessor directives, unless they are
		 * recognised as comments.
		 */
		if (lead_len == 0 && ptr[0] == '#')
		{
		    int was_backslashed = FALSE;

		    while ((ptr[0] == '#' || was_backslashed) &&
			 curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
		    {
			if (*ptr && ptr[STRLEN(ptr) - 1] == '\\')
			    was_backslashed = TRUE;
			else
			    was_backslashed = FALSE;
			ptr = ml_get(++curwin->w_cursor.lnum);
		    }
		    if (was_backslashed)
			newindent = 0;	    /* Got to end of file */
		    else
			newindent = get_indent();
		}
		p = skipwhite(ptr);
		if (*p == '}')	    /* if line starts with '}': do indent */
		    did_si = TRUE;
		else		    /* can delete indent when '{' typed */
		    can_si_back = TRUE;
	    }
	    curwin->w_cursor = old_cursor;
	}
	if (curbuf->b_p_si)
	    can_si = TRUE;
#endif /* SMARTINDENT */

	did_ai = TRUE;
    }

    /*
     * Find out if the current line starts with a comment leader.
     * This may then be inserted in front of the new line.
     */
    lead_len = get_leader_len(saved_line, &lead_flags);
    if (lead_len > 0)
    {
	char_u	*lead_repl = NULL;	    /* replaces comment leader */
	int	lead_repl_len = 0;	    /* length of *lead_repl */
	char_u	lead_middle[COM_MAX_LEN];   /* middle-comment string */
	char_u	lead_end[COM_MAX_LEN];	    /* end-comment string */
	char_u	*comment_end = NULL;	    /* where lead_end has been found */
	int	extra_space = FALSE;	    /* append extra space */
	int	current_flag;
	int	require_blank = FALSE;	    /* requires blank after middle */

	/*
	 * If the comment leader has the start, middle or end flag, it may not
	 * be used or may be replaced with the middle leader.
	 */
	for (p = lead_flags; *p && *p != ':'; ++p)
	{
	    if (*p == COM_BLANK)
	    {
		require_blank = TRUE;
		continue;
	    }
	    if (*p == COM_START || *p == COM_MIDDLE)
	    {
		current_flag = *p;
		if (*p == COM_START)
		{
		    /*
		     * Doing "O" on a start of comment does not insert leader.
		     */
		    if (dir == BACKWARD)
		    {
			lead_len = 0;
			break;
		    }

		    /* find start of middle part */
		    (void)copy_option_part(&p, lead_middle, COM_MAX_LEN, ",");
		    require_blank = FALSE;
		}

		/*
		 * Isolate the strings of the middle and end leader.
		 */
		while (*p && p[-1] != ':')	/* find end of middle flags */
		{
		    if (*p == COM_BLANK)
			require_blank = TRUE;
		    ++p;
		}
		(void)copy_option_part(&p, lead_middle, COM_MAX_LEN, ",");
		while (*p && p[-1] != ':')	/* find end of end flags */
		    ++p;
		(void)copy_option_part(&p, lead_end, COM_MAX_LEN, ",");

		/*
		 * If the end of the comment is in the same line, don't use
		 * the comment leader.
		 */
		if (dir == FORWARD)
		{
		    n = STRLEN(lead_end);
		    for (p = saved_line + lead_len; *p; ++p)
			if (STRNCMP(p, lead_end, n) == 0)
			{
			    comment_end = p;
			    lead_len = 0;
			    break;
			}
		}

		/*
		 * Doing "o" on a start of comment inserts the middle leader.
		 */
		if (lead_len)
		{
		    if (current_flag == COM_START)
		    {
			lead_repl = lead_middle;
			lead_repl_len = STRLEN(lead_middle);
		    }

		    /*
		     * If we have hit RETURN immediately after the start
		     * comment leader, then put a space after the middle
		     * comment leader on the next line.
		     */
		    if (!vim_iswhite(saved_line[lead_len - 1])
			    && ((p_extra != NULL
				    && (int)curwin->w_cursor.col == lead_len)
				|| (p_extra == NULL
				    && saved_line[lead_len] == NUL)
				|| require_blank))
			extra_space = TRUE;
		}
		break;
	    }
	    if (*p == COM_END)
	    {
		/*
		 * Doing "o" on the end of a comment does not insert leader.
		 * Remember where the end is, might want to use it to find the
		 * start (for C-comments).
		 */
		if (dir == FORWARD)
		{
		    comment_end = skipwhite(saved_line);
		    lead_len = 0;
		    break;
		}

		/*
		 * Doing "O" on the end of a comment inserts the middle leader.
		 * Find the string for the middle leader, searching backwards.
		 */
		while (p > curbuf->b_p_com && *p != ',')
		    --p;
		for (lead_repl = p; lead_repl > curbuf->b_p_com &&
					    lead_repl[-1] != ':'; --lead_repl)
		    ;
		lead_repl_len = p - lead_repl;
		break;
	    }
	    if (*p == COM_FIRST)
	    {
		/*
		 * Comment leader for first line only:	Don't repeat leader
		 * when using "O", blank out leader when using "o".
		 */
		if (dir == BACKWARD)
		    lead_len = 0;
		else
		{
		    lead_repl = (char_u *)"";
		    lead_repl_len = 0;
		}
		break;
	    }
	}
	if (lead_len)
	{
	    /* allocate buffer (may concatenate p_exta later) */
	    leader = alloc(lead_len + lead_repl_len + extra_space +
							      extra_len + 1);
	    allocated = leader;		    /* remember to free it later */

	    if (leader == NULL)
		lead_len = 0;
	    else

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -