/* 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. Load more
/* 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_VISUALEXTRA static 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)); #endif static 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_MBYTE static void mb_adjust_opend __ARGS((oparg_T *oap)); #endif static 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_CLIPBOARD static void copy_yank_reg __ARGS((struct yankreg *reg)); # if defined(FEAT_VISUAL) || defined(FEAT_EVAL) static void may_set_selection __ARGS((void)); # endif #endif static void dis_msg __ARGS((char_u *p, int skip_esc)); #ifdef FEAT_VISUAL static 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)); #endif static int ends_in_white __ARGS((linenr_T lnum)); #ifdef FEAT_COMMENTS static 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)); #else static 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! */ int get_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. */ int op_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. */ int get_op_char(optype) int optype; { return opchars[optype][0]; } /* * Get second operator command character. */ int get_extra_op_char(optype) int optype; { return opchars[optype][1]; } /* * op_shift - handle a shift operation */ void op_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 */ 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 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 void shift_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))