6379 lines · 152.6 KB · C
RawDownload
/* 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. * See README.txt for an overview of the Vim source code. */ /* * 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 = registers '1' to '9', for deletes * 10..35 = registers 'a' to 'z' *     36 = delete register '-' *     37 = Selection register '*'. Only if FEAT_CLIPBOARD defined *     38 = Clipboard register '+'. Only if FEAT_CLIPBOARD and FEAT_X11 defined *//* * Symbolic names for some registers. */#define DELETION_REGISTER	36#ifdef FEAT_CLIPBOARD# define STAR_REGISTER		37#  ifdef FEAT_X11#   define PLUS_REGISTER	38#  else#   define PLUS_REGISTER	STAR_REGISTER	    /* there is only one */#  endif#endif#ifdef FEAT_DND# define TILDE_REGISTER		(PLUS_REGISTER + 1)#endif #ifdef FEAT_CLIPBOARD# ifdef FEAT_DND#  define NUM_REGISTERS		(TILDE_REGISTER + 1)# else#  define NUM_REGISTERS		(PLUS_REGISTER + 1)# endif#else# define NUM_REGISTERS		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 */#ifdef FEAT_VISUAL    colnr_T	y_width;	/* only set if y_type == MBLOCK */#endif} 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 * also op_change, op_shift, op_insert, op_replace - AKelly */struct block_def{    int		startspaces;	/* 'extra' cols of first char */    int		endspaces;	/* 'extra' cols of first char */    int		textlen;	/* chars in block */    char_u	*textstart;	/* pointer to 1st char in block */    colnr_T	textcol;	/* cols of chars (at least part.) in block */    colnr_T	start_vcol;	/* start col of 1st char wholly inside block */    colnr_T	end_vcol;	/* start col of 1st char wholly after block */#ifdef FEAT_VISUALEXTRA    int		is_short;	/* TRUE if line is too short to fit in block */    int		is_MAX;		/* TRUE if curswant==MAXCOL when starting */    int		is_oneChar;	/* TRUE if block within one character */    int		pre_whitesp;	/* screen cols of ws before block */    int		pre_whitesp_c;	/* chars of ws before block */    colnr_T	end_char_vcols;	/* number of vcols of post-block char */#endif    colnr_T	start_char_vcols; /* number of vcols of pre-block char */}; #ifdef FEAT_VISUALEXTRAstatic void shift_block __ARGS((oparg_T *oap, int amount));static void block_insert __ARGS((oparg_T *oap, char_u *s, int b_insert, struct block_def*bdp));#endifstatic int	stuff_yank __ARGS((int, char_u *));static void	put_reedit_in_typebuf __ARGS((int silent));static int	put_in_typebuf __ARGS((char_u *s, int esc, int colon,								 int silent));static void	stuffescaped __ARGS((char_u *arg, int literally));#ifdef FEAT_MBYTEstatic void	mb_adjust_opend __ARGS((oparg_T *oap));#endifstatic void	free_yank __ARGS((long));static void	free_yank_all __ARGS((void));static int	yank_copy_line __ARGS((struct block_def *bd, long y_idx));#ifdef FEAT_CLIPBOARDstatic void	copy_yank_reg __ARGS((struct yankreg *reg));# if defined(FEAT_VISUAL) || defined(FEAT_EVAL)static void	may_set_selection __ARGS((void));# endif#endifstatic void	dis_msg __ARGS((char_u *p, int skip_esc));#ifdef FEAT_VISUALstatic void	block_prep __ARGS((oparg_T *oap, struct block_def *, linenr_T, int));#endif#if defined(FEAT_CLIPBOARD) || defined(FEAT_EVAL)static void	str_to_reg __ARGS((struct yankreg *y_ptr, int type, char_u *str, long len, long blocklen));#endifstatic int	ends_in_white __ARGS((linenr_T lnum));#ifdef FEAT_COMMENTSstatic int	same_leader __ARGS((linenr_T lnum, int, char_u *, int, char_u *));static int	fmt_check_par __ARGS((linenr_T, int *, char_u **, int do_comments));#elsestatic int	fmt_check_par __ARGS((linenr_T));#endif /* * The names of operators. * IMPORTANT: Index must correspond with defines in vim.h!!! * The third field indicates whether the operator always works on lines. */static char opchars[][3] ={    {NUL, NUL, FALSE},	/* OP_NOP */    {'d', NUL, FALSE},	/* OP_DELETE */    {'y', NUL, FALSE},	/* OP_YANK */    {'c', NUL, FALSE},	/* OP_CHANGE */    {'<', NUL, TRUE},	/* OP_LSHIFT */    {'>', NUL, TRUE},	/* OP_RSHIFT */    {'!', NUL, TRUE},	/* OP_FILTER */    {'g', '~', FALSE},	/* OP_TILDE */    {'=', NUL, TRUE},	/* OP_INDENT */    {'g', 'q', TRUE},	/* OP_FORMAT */    {':', NUL, TRUE},	/* OP_COLON */    {'g', 'U', FALSE},	/* OP_UPPER */    {'g', 'u', FALSE},	/* OP_LOWER */    {'J', NUL, TRUE},	/* DO_JOIN */    {'g', 'J', TRUE},	/* DO_JOIN_NS */    {'g', '?', FALSE},	/* OP_ROT13 */    {'r', NUL, FALSE},	/* OP_REPLACE */    {'I', NUL, FALSE},	/* OP_INSERT */    {'A', NUL, FALSE},	/* OP_APPEND */    {'z', 'f', TRUE},	/* OP_FOLD */    {'z', 'o', TRUE},	/* OP_FOLDOPEN */    {'z', 'O', TRUE},	/* OP_FOLDOPENREC */    {'z', 'c', TRUE},	/* OP_FOLDCLOSE */    {'z', 'C', TRUE},	/* OP_FOLDCLOSEREC */    {'z', 'd', TRUE},	/* OP_FOLDDEL */    {'z', 'D', TRUE},	/* OP_FOLDDELREC */    {'g', 'w', TRUE},	/* OP_FORMAT2 */    {'g', '@', FALSE},	/* OP_FUNCTION */}; /* * Translate a command name into an operator type. * Must only be called with a valid operator name! */    intget_op_type(char1, char2)    int		char1;    int		char2;{    int		i;     if (char1 == 'r')		/* ignore second character */	return OP_REPLACE;    if (char1 == '~')		/* when tilde is an operator */	return OP_TILDE;    for (i = 0; ; ++i)	if (opchars[i][0] == char1 && opchars[i][1] == char2)	    break;    return i;} #if defined(FEAT_VISUAL) || defined(PROTO)/* * Return TRUE if operator "op" always works on whole lines. */    intop_on_lines(op)    int op;{    return opchars[op][2];}#endif /* * Get first operator command character. * Returns 'g' or 'z' if there is another command character. */    intget_op_char(optype)    int		optype;{    return opchars[optype][0];} /* * Get second operator command character. */    intget_extra_op_char(optype)    int		optype;{    return opchars[optype][1];} /* * op_shift - handle a shift operation */    voidop_shift(oap, curs_top, amount)    oparg_T	    *oap;    int		    curs_top;    int		    amount;{    long	    i;    int		    first_char;    char_u	    *s;#ifdef FEAT_VISUAL    int		    block_col = 0;#endif     if (u_save((linenr_T)(oap->start.lnum - 1),				       (linenr_T)(oap->end.lnum + 1)) == FAIL)	return; #ifdef FEAT_VISUAL    if (oap->block_mode)	block_col = curwin->w_cursor.col;#endif     for (i = oap->line_count; --i >= 0; )    {	first_char = *ml_get_curline();	if (first_char == NUL)				/* empty line */	    curwin->w_cursor.col = 0;#ifdef FEAT_VISUALEXTRA	else if (oap->block_mode)	    shift_block(oap, amount);#endif	else	    /* Move the line right if it doesn't start with '#', 'smartindent'	     * isn't set or 'cindent' isn't set or '#' isn't in 'cino'. */#if defined(FEAT_SMARTINDENT) || defined(FEAT_CINDENT)	    if (first_char != '#' || !preprocs_left())#endif	{	    shift_line(oap->op_type == OP_LSHIFT, p_sr, amount);	}	++curwin->w_cursor.lnum;    }     changed_lines(oap->start.lnum, 0, oap->end.lnum + 1, 0L); #ifdef FEAT_VISUAL    if (oap->block_mode)    {	curwin->w_cursor.lnum = oap->start.lnum;	curwin->w_cursor.col = block_col;    }    else#endif	if (curs_top)	    /* put cursor on first line, for ">>" */    {	curwin->w_cursor.lnum = oap->start.lnum;	beginline(BL_SOL | BL_FIX);   /* shift_line() may have set cursor.col */    }    else	--curwin->w_cursor.lnum;	/* put cursor on last line, for ":>" */     if (oap->line_count > p_report)    {	if (oap->op_type == OP_RSHIFT)	    s = (char_u *)">";	else	    s = (char_u *)"<";	if (oap->line_count == 1)	{	    if (amount == 1)		sprintf((char *)IObuff, _("1 line %sed 1 time"), s);	    else		sprintf((char *)IObuff, _("1 line %sed %d times"), s, amount);	}	else	{	    if (amount == 1)		sprintf((char *)IObuff, _("%ld lines %sed 1 time"),							  oap->line_count, s);	    else		sprintf((char *)IObuff, _("%ld lines %sed %d times"),						  oap->line_count, s, amount);	}	msg(IObuff);    }     /*     * Set "'[" and "']" marks.     */    curbuf->b_op_start = oap->start;    curbuf->b_op_end.lnum = oap->end.lnum;    curbuf->b_op_end.col = (colnr_T)STRLEN(ml_get(oap->end.lnum));    if (curbuf->b_op_end.col > 0)	--curbuf->b_op_end.col;} /* * shift the current line one shiftwidth left (if left != 0) or right * leaves cursor on first blank in the line */    voidshift_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 new indent */#ifdef FEAT_VREPLACE    if (State & VREPLACE_FLAG)	change_indent(INDENT_SET, count, FALSE, NUL);    else#endif	(void)set_indent(count, SIN_CHANGED);} #if defined(FEAT_VISUALEXTRA) || defined(PROTO)/* * Shift one line of the current block one shiftwidth right or left. * Leaves cursor on first character in block. */    static voidshift_block(oap, amount)    oparg_T	*oap;    int		amount;{    int			left = (oap->op_type == OP_LSHIFT);    int			oldstate = State;    int			total, split;    char_u		*newp, *oldp, *midp, *ptr;    int			oldcol = curwin->w_cursor.col;    int			p_sw = (int)curbuf->b_p_sw;    int			p_ts = (int)curbuf->b_p_ts;    struct block_def	bd;    int			internal = 0;    int			incr;    colnr_T		vcol, col = 0, ws_vcol;    int			i = 0, j = 0;    int			len; #ifdef FEAT_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 */    block_prep(oap, &bd, curwin->w_cursor.lnum, TRUE);    if (bd.is_short)	return;     /* total is number of screen columns to be inserted/removed */    total = amount * p_sw;    oldp = ml_get_curline();     if (!left)    {	/*	 *  1. Get start vcol	 *  2. Total ws vcols	 *  3. Divvy into TABs & spp	 *  4. Construct new string	 */	total += bd.pre_whitesp; /* all virtual WS upto & incl a split TAB */	ws_vcol = bd.start_vcol - bd.pre_whitesp;	if (bd.startspaces)	{#ifdef FEAT_MBYTE	    if (has_mbyte)		bd.textstart += (*mb_ptr2len)(bd.textstart);#endif	    ++bd.textstart;	}	for ( ; vim_iswhite(*bd.textstart); )	{	    incr = lbr_chartabsize_adv(&bd.textstart, (colnr_T)(bd.start_vcol));	    total += incr;	    bd.start_vcol += incr;	}	/* OK, now total=all the VWS reqd, and textstart points at the 1st	 * non-ws char in the block. */	if (!curbuf->b_p_et)	    i = ((ws_vcol % p_ts) + total) / p_ts; /* number of tabs */	if (i)	    j = ((ws_vcol % p_ts) + total) % p_ts; /* number of spp */	else	    j = total;	/* if we're splitting a TAB, allow for it */	bd.textcol -= bd.pre_whitesp_c - (bd.startspaces != 0);	len = (int)STRLEN(bd.textstart) + 1;	newp = alloc_check((unsigned)(bd.textcol + i + j + len));	if (newp == NULL)	    return;	vim_memset(newp, NUL, (size_t)(bd.textcol + i + j + len));	mch_memmove(newp, oldp, (size_t)bd.textcol);	copy_chars(newp + bd.textcol, (size_t)i, TAB);	copy_spaces(newp + bd.textcol + i, (size_t)j);	/* the end */	mch_memmove(newp + bd.textcol + i + j, bd.textstart, (size_t)len);    }    else /* left */    {	vcol = oap->start_vcol;	/* walk vcol past ws to be removed */	for (midp = oldp + bd.textcol;	      vcol < (oap->start_vcol + total) && vim_iswhite(*midp); )	{	    incr = lbr_chartabsize_adv(&midp, (colnr_T)vcol);	    vcol += incr;	}	/* internal is the block-internal ws replacing a split TAB */	if (vcol > (oap->start_vcol + total))	{	    /* we have to split the TAB *(midp-1) */	    internal = vcol - (oap->start_vcol + total);	}	/* if 'expandtab' is not set, use TABs */ 	split = bd.startspaces + internal;	if (split > 0)	{	    if (!curbuf->b_p_et)	    {		for (ptr = oldp, col = 0; ptr < oldp+bd.textcol; )		    col += lbr_chartabsize_adv(&ptr, (colnr_T)col); 		/* col+1 now equals the start col of the first char of the		 * block (may be < oap.start_vcol if we're splitting a TAB) */		i = ((col % p_ts) + split) / p_ts; /* number of tabs */	    }	    if (i)		j = ((col % p_ts) + split) % p_ts; /* number of spp */	    else		j = split;	} 	newp = alloc_check(bd.textcol + i + j + (unsigned)STRLEN(midp) + 1);	if (newp == NULL)	    return;	vim_memset(newp, NUL, (size_t)(bd.textcol + i + j + STRLEN(midp) + 1)); 	/* copy first part we want to keep */	mch_memmove(newp, oldp, (size_t)bd.textcol);	/* Now copy any TABS and spp to ensure correct alignment! */	while (vim_iswhite(*midp))

Lines 1–500 of 6379.