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

📄 ops.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.
 */

/*
 * ops.c: implementation of various operators: op_shift, op_delete, op_tilde,
 *	  op_change, op_yank, do_put, do_join
 */

#include "vim.h"

/*
 * Number of registers.
 *	0 = unnamed register, for normal yanks and puts
 *   1..9 = number registers, for deletes
 * 10..35 = named registers
 *     36 = delete register (-)
 *     37 = Clipboard register (*). Only if USE_CLIPBOARD defined
 */
#ifdef USE_CLIPBOARD
# define NUM_REGISTERS		38
#else
# define NUM_REGISTERS		37
#endif

/*
 * Symbolic names for some registers.
 */
#define DELETION_REGISTER	36
#ifdef USE_CLIPBOARD
# define CLIPBOARD_REGISTER	37
#endif

/*
 * Each yank register is an array of pointers to lines.
 */
static struct yankreg
{
    char_u	**y_array;	/* pointer to array of line pointers */
    linenr_t	y_size;		/* number of lines in y_array */
    char_u	y_type;		/* MLINE, MCHAR or MBLOCK */
} y_regs[NUM_REGISTERS];

static struct yankreg	*y_current;	    /* ptr to current yankreg */
static int		y_append;	    /* TRUE when appending */
static struct yankreg	*y_previous = NULL; /* ptr to last written yankreg */

/*
 * structure used by block_prep, op_delete and op_yank for blockwise operators
 */
struct block_def
{
    int		startspaces;
    int		endspaces;
    int		textlen;
    char_u	*textstart;
    colnr_t	textcol;
};

#ifdef WANT_EVAL
static char_u	*get_expr_line __ARGS((void));
#endif
static void	get_yank_register __ARGS((int regname, int writing));
static int	stuff_yank __ARGS((int, char_u *));
static int	put_in_typebuf __ARGS((char_u *s, int colon));
static void	stuffescaped __ARGS((char_u *arg));
static int	get_spec_reg __ARGS((int regname, char_u **argp, int *allocated, int errmsg));
static void	free_yank __ARGS((long));
static void	free_yank_all __ARGS((void));
static void	block_prep __ARGS((OPARG *oap, struct block_def *, linenr_t, int));
#if defined(USE_CLIPBOARD) || defined(WANT_EVAL)
static void	str_to_reg __ARGS((struct yankreg *y_ptr, int type, char_u *str, long len));
#endif
static int	same_leader __ARGS((int, char_u *, int, char_u *));
static int	fmt_check_par __ARGS((linenr_t, int *, char_u **));

/*
 * op_shift - handle a shift operation
 */
    void
op_shift(oap, curs_top, amount)
    OPARG	    *oap;
    int		    curs_top;
    int		    amount;
{
    long	    i;
    int		    first_char;

    if (u_save((linenr_t)(curwin->w_cursor.lnum - 1),
		 (linenr_t)(curwin->w_cursor.lnum + oap->line_count)) == FAIL)
	return;

#ifdef SYNTAX_HL
    /* recompute syntax hl., starting with current line */
    syn_changed(curwin->w_cursor.lnum);
#endif

    for (i = oap->line_count; --i >= 0; )
    {
	first_char = *ml_get_curline();
	if (first_char == NUL)				/* empty line */
	    curwin->w_cursor.col = 0;
	/*
	 * Don't move the line right if it starts with # and p_si is set.
	 */
	else
#if defined(SMARTINDENT) || defined(CINDENT)
	    if (first_char != '#' || (
# ifdef SMARTINDENT
			 !curbuf->b_p_si
# endif
# if defined(SMARTINDENT) && defined(CINDENT)
			    &&
# endif
# ifdef CINDENT
			 (!curbuf->b_p_cin || !in_cinkeys('#', ' ', TRUE))
# endif
					))
#endif
	{
	    /* if (oap->block_mode)
		    shift the block, not the whole line
	    else */
		shift_line(oap->op_type == OP_LSHIFT, p_sr, amount);
	}
	++curwin->w_cursor.lnum;
    }

    if (curs_top)	    /* put cursor on first line, for ">>" */
    {
	curwin->w_cursor.lnum -= oap->line_count;
	beginline(BL_SOL | BL_FIX);   /* shift_line() may have set cursor.col */
    }
    else
	--curwin->w_cursor.lnum;	/* put cursor on last line, for ":>" */
    update_topline();
    update_screen(NOT_VALID);

    if (oap->line_count > p_report)
       smsg((char_u *)"%ld line%s %ced %d time%s", oap->line_count,
	      plural(oap->line_count), (oap->op_type == OP_RSHIFT) ? '>' : '<',
			 amount, plural((long)amount));

    /*
     * Set "'[" and "']" marks.
     */
    curbuf->b_op_start = oap->start;
    curbuf->b_op_end = oap->end;
}

/*
 * shift the current line one shiftwidth left (if left != 0) or right
 * leaves cursor on first blank in the line
 */
    void
shift_line(left, round, amount)
    int left;
    int	round;
    int	amount;
{
    int	    count;
    int	    i, j;
    int	    p_sw = (int)curbuf->b_p_sw;

    count = get_indent();	    /* get current indent */

    if (round)			    /* round off indent */
    {
	i = count / p_sw;	    /* number of p_sw rounded down */
	j = count % p_sw;	    /* extra spaces */
	if (j && left)		    /* first remove extra spaces */
	    --amount;
	if (left)
	{
	    i -= amount;
	    if (i < 0)
		i = 0;
	}
	else
	    i += amount;
	count = i * p_sw;
    }
    else		/* original vi indent */
    {
	if (left)
	{
	    count -= p_sw * amount;
	    if (count < 0)
		count = 0;
	}
	else
	    count += p_sw * amount;
    }
    set_indent(count, TRUE);	    /* set new indent */
}

#if defined(LISPINDENT) || defined(CINDENT)
/*
 * op_reindent - handle reindenting a block of lines for C or lisp.
 *
 * mechanism copied from op_shift, above
 */
    void
op_reindent(oap, how)
    OPARG	*oap;
    int		(*how) __ARGS((void));
{
    long	i;
    char_u	*l;
    int		count;

    if (u_save((linenr_t)(curwin->w_cursor.lnum - 1),
		 (linenr_t)(curwin->w_cursor.lnum + oap->line_count)) == FAIL)
	return;

#ifdef SYNTAX_HL
    /* recompute syntax hl., starting with current line */
    syn_changed(curwin->w_cursor.lnum);
#endif

    for (i = oap->line_count; --i >= 0 && !got_int; )
    {
	/* it's a slow thing to do, so give feedback so there's no worry that
	 * the computer's just hung. */

	if (	   (i % 50 == 0
		    || i == oap->line_count - 1)
		&& oap->line_count > p_report)
	    smsg((char_u *)"%ld line%s to indent... ", i, plural(i));

	/*
	 * Be vi-compatible: For lisp indenting the first line is not
	 * indented, unless there is only one line.
	 */
#ifdef LISPINDENT
	if (i != oap->line_count - 1 || oap->line_count == 1 ||
						       how != get_lisp_indent)
#endif
	{
	    l = skipwhite(ml_get_curline());
	    if (*l == NUL)		    /* empty or blank line */
		count = 0;
	    else
		count = how();		    /* get the indent for this line */

	    set_indent(count, TRUE);
	}
	++curwin->w_cursor.lnum;
    }

    /* put cursor on first non-blank of indented line */
    curwin->w_cursor.lnum -= oap->line_count;
    beginline(BL_SOL | BL_FIX);

    update_topline();
    update_screen(NOT_VALID);

    if (oap->line_count > p_report)
    {
	i = oap->line_count - (i + 1);
	smsg((char_u *)"%ld line%s indented ", i, plural(i));
    }
    /* set '[ and '] marks */
    curbuf->b_op_start = oap->start;
    curbuf->b_op_end = oap->end;
}
#endif /* defined(LISPINDENT) || defined(CINDENT) */

#ifdef WANT_EVAL
/*
 * Keep the last expression line here, for repeating.
 */
static char_u	*expr_line = NULL;

/*
 * Get an expression for the "\"=expr1" or "CTRL-R =expr1"
 * Returns '=' when OK, NUL otherwise.
 */
    int
get_expr_register()
{
    char_u	*new_line;

    new_line = getcmdline('=', 0L, 0);
    if (new_line == NULL)
	return NUL;
    if (*new_line == NUL)	/* use previous line */
	vim_free(new_line);
    else
	set_expr_line(new_line);
    return '=';
}

/*
 * Set the expression for the '=' register.
 * Argument must be an allocated string.
 */
    void
set_expr_line(new_line)
    char_u	*new_line;
{
    vim_free(expr_line);
    expr_line = new_line;
}

/*
 * Get the result of the '=' register expression.
 * Returns a pointer to allocated memory, or NULL for failure.
 */
    static char_u *
get_expr_line()
{
    if (expr_line == NULL)
	return NULL;
    return eval_to_string(expr_line, NULL);
}
#endif /* WANT_EVAL */

/*
 * Check if 'regname' is a valid name of a yank register.
 * Note: There is no check for 0 (default register), caller should do this
 */
    int
valid_yank_reg(regname, writing)
    int	    regname;
    int	    writing;	    /* if TRUE check for writable registers */
{
    if (regname > '~')
	return FALSE;
    if (       isalnum(regname)
	    || (!writing && vim_strchr((char_u *)
#ifdef WANT_EVAL
				    ".%#:="
#else
				    ".%#:"
#endif
					, regname) != NULL)
	    || regname == '"'
	    || regname == '-'
	    || regname == '_'
#ifdef USE_CLIPBOARD
	    || (clipboard.available && regname == '*')
#endif
							)
	return TRUE;
    return FALSE;
}

/*
 * Set y_current and y_append, according to the value of "regname".
 * Cannot handle the '_' register.
 *
 * If regname is 0 and writing, use register 0
 * If regname is 0 and reading, use previous register
 */
    static void
get_yank_register(regname, writing)
    int	    regname;
    int	    writing;
{
    int	    i;

    y_append = FALSE;
    if (((regname == 0 && !writing) || regname == '"') && y_previous != NULL)
    {
	y_current = y_previous;
	return;
    }
    i = regname;
    if (isdigit(i))
	i -= '0';
    else if (islower(i))
	i -= 'a' - 10;
    else if (isupper(i))
    {
	i -= 'A' - 10;
	y_append = TRUE;
    }
    else if (regname == '-')
	i = DELETION_REGISTER;
#ifdef USE_CLIPBOARD
    else if (clipboard.available && regname == '*')
	i = CLIPBOARD_REGISTER;
#endif
    else		/* not 0-9, a-z, A-Z or '-': use register 0 */
	i = 0;
    y_current = &(y_regs[i]);
    if (writing)	/* remember the register we write into for do_put() */
	y_previous = y_current;
}

/*
 * return TRUE if the current yank register has type MLINE
 */
    int
yank_register_mline(regname)
    int	    regname;
{
    if (regname != 0 && !valid_yank_reg(regname, FALSE))
	return FALSE;
    if (regname == '_')		/* black hole is always empty */
	return FALSE;
    get_yank_register(regname, FALSE);
    return (y_current->y_type == MLINE);
}

/*
 * start or stop recording into a yank register
 *
 * return FAIL for failure, OK otherwise
 */
    int
do_record(c)
    int c;
{
    char_u	*p;
    static int	regname;
    struct yankreg *old_y_previous, *old_y_current;
    int		retval;

    if (Recording == FALSE)	    /* start recording */
    {
			/* registers 0-9, a-z and " are allowed */
	if (c > '~' || (!isalnum(c) && c != '"'))
	    retval = FAIL;
	else
	{
	    Recording = TRUE;
	    showmode();
	    regname = c;
	    retval = OK;
	}
    }
    else			    /* stop recording */
    {
	Recording = FALSE;
	MSG("");
	p = get_recorded();
	if (p == NULL)
	    retval = FAIL;
	else
	{
	    /*
	     * We don't want to change the default register here, so save and
	     * restore the current register name.
	     */
	    old_y_previous = y_previous;
	    old_y_current = y_current;

	    retval = stuff_yank(regname, p);

	    y_previous = old_y_previous;
	    y_current = old_y_current;
	}
    }
    return retval;
}

/*
 * Stuff string 'p' into yank register 'regname' as a single line (append if
 * uppercase).	'p' must have been alloced.
 *
 * return FAIL for failure, OK otherwise
 */
    static int
stuff_yank(regname, p)
    int		regname;
    char_u	*p;
{
    char_u	*lp;
    char_u	**pp;

    /* check for read-only register */
    if (regname != 0 && !valid_yank_reg(regname, TRUE))
    {
	vim_free(p);
	return FAIL;
    }
    if (regname == '_')		    /* black hole: don't do anything */
    {
	vim_free(p);
	return OK;
    }
    get_yank_register(regname, TRUE);
    if (y_append && y_current->y_array != NULL)
    {
	pp = &(y_current->y_array[y_current->y_size - 1]);
	lp = lalloc((long_u)(STRLEN(*pp) + STRLEN(p) + 1), TRUE);
	if (lp == NULL)
	{
	    vim_free(p);
	    return FAIL;
	}
	STRCPY(lp, *pp);
	STRCAT(lp, p);
	vim_free(p);
	vim_free(*pp);
	*pp = lp;
    }
    else
    {
	free_yank_all();
	if ((y_current->y_array =
			(char_u **)alloc((unsigned)sizeof(char_u *))) == NULL)
	{
	    vim_free(p);
	    return FAIL;
	}
	y_current->y_array[0] = p;
	y_current->y_size = 1;
	y_current->y_type = MCHAR;  /* used to be MLINE, why? */
    }
    return OK;
}

⌨️ 快捷键说明

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