summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2016-01-10 22:13:02 +0100
committerBram Moolenaar <Bram@vim.org>2016-01-10 22:13:02 +0100
commitd79e55016cf8268cee935f1ac3b5b28712d1399e (patch)
treec1651d0b492ac78594a39e5f6f8bc17e4c6780e3
parent507edf63df75fe228e0f76b845b58d60266e65d8 (diff)
patch 7.4.1087v7.4.1087
Problem: CTRL-A and CTRL-X do not work properly with blockwise visual selection if there is a mix of Tab and spaces. Solution: Add OP_NR_ADD and OP_NR_SUB. (Hirohito Higashi)
-rw-r--r--src/normal.c87
-rw-r--r--src/ops.c663
-rw-r--r--src/proto/ops.pro2
-rw-r--r--src/testdir/test_increment.vim110
-rw-r--r--src/version.c2
-rw-r--r--src/vim.h4
6 files changed, 487 insertions, 381 deletions
diff --git a/src/normal.c b/src/normal.c
index d513f75162..810aabfa00 100644
--- a/src/normal.c
+++ b/src/normal.c
@@ -40,7 +40,6 @@ static void find_start_of_word __ARGS((pos_T *));
static void find_end_of_word __ARGS((pos_T *));
static int get_mouse_class __ARGS((char_u *p));
#endif
-static void prep_redo_visual __ARGS((cmdarg_T *cap));
static void prep_redo_cmd __ARGS((cmdarg_T *cap));
static void prep_redo __ARGS((int regname, long, int, int, int, int, int));
static int checkclearop __ARGS((oparg_T *oap));
@@ -1392,6 +1391,7 @@ do_pending_operator(cap, old_col, gui_yank)
static linenr_T redo_VIsual_line_count; /* number of lines */
static colnr_T redo_VIsual_vcol; /* number of cols or end column */
static long redo_VIsual_count; /* count for Visual operator */
+ static int redo_VIsual_arg; /* extra argument */
#ifdef FEAT_VIRTUALEDIT
int include_line_break = FALSE;
#endif
@@ -1699,6 +1699,7 @@ do_pending_operator(cap, old_col, gui_yank)
redo_VIsual_vcol = resel_VIsual_vcol;
redo_VIsual_line_count = resel_VIsual_line_count;
redo_VIsual_count = cap->count0;
+ redo_VIsual_arg = cap->arg;
}
}
@@ -2108,6 +2109,24 @@ do_pending_operator(cap, old_col, gui_yank)
oap->op_type == OP_FOLDDELREC, oap->is_VIsual);
break;
#endif
+ case OP_NR_ADD:
+ case OP_NR_SUB:
+ if (empty_region_error)
+ {
+ vim_beep(BO_OPER);
+ CancelRedo();
+ }
+ else
+ {
+ VIsual_active = TRUE;
+#ifdef FEAT_LINEBREAK
+ curwin->w_p_lbr = lbr_saved;
+#endif
+ op_addsub(oap, cap->count1, redo_VIsual_arg);
+ VIsual_active = FALSE;
+ }
+ check_cursor_col();
+ break;
default:
clearopbeep(oap);
}
@@ -3603,43 +3622,6 @@ find_ident_at_pos(wp, lnum, startcol, string, find_type)
}
/*
- * Add commands to reselect Visual mode into the redo buffer.
- */
- static void
-prep_redo_visual(cap)
- cmdarg_T *cap;
-{
- ResetRedobuff();
- AppendCharToRedobuff(VIsual_mode);
- if (VIsual_mode == 'V' && curbuf->b_visual.vi_end.lnum
- != curbuf->b_visual.vi_start.lnum)
- {
- AppendNumberToRedobuff(curbuf->b_visual.vi_end.lnum
- - curbuf->b_visual.vi_start.lnum);
- AppendCharToRedobuff('j');
- }
- else if (VIsual_mode == 'v' || VIsual_mode == Ctrl_V)
- {
- /* block visual mode or char visual mmode*/
- if (curbuf->b_visual.vi_end.lnum != curbuf->b_visual.vi_start.lnum)
- {
- AppendNumberToRedobuff(curbuf->b_visual.vi_end.lnum -
- curbuf->b_visual.vi_start.lnum);
- AppendCharToRedobuff('j');
- }
- if (curbuf->b_visual.vi_curswant == MAXCOL)
- AppendCharToRedobuff('$');
- else if (curbuf->b_visual.vi_end.col > curbuf->b_visual.vi_start.col)
- {
- AppendNumberToRedobuff(curbuf->b_visual.vi_end.col
- - curbuf->b_visual.vi_start.col);
- AppendCharToRedobuff(' ');
- }
- }
- AppendNumberToRedobuff(cap->count1);
-}
-
-/*
* Prepare for redo of a normal command.
*/
static void
@@ -4243,30 +4225,16 @@ nv_help(cap)
nv_addsub(cap)
cmdarg_T *cap;
{
- int visual = VIsual_active;
-
- if (cap->oap->op_type == OP_NOP
- && do_addsub((int)cap->cmdchar, cap->count1, cap->arg) == OK)
+ if (!VIsual_active && cap->oap->op_type == OP_NOP)
{
- if (visual)
- {
- prep_redo_visual(cap);
- if (cap->arg)
- AppendCharToRedobuff('g');
- AppendCharToRedobuff(cap->cmdchar);
- }
- else
- prep_redo_cmd(cap);
+ cap->oap->op_type = cap->cmdchar == Ctrl_A ? OP_NR_ADD : OP_NR_SUB;
+ op_addsub(cap->oap, cap->count1, cap->arg);
+ cap->oap->op_type = OP_NOP;
}
+ else if (VIsual_active)
+ nv_operator(cap);
else
- clearopbeep(cap->oap);
- if (visual)
- {
- VIsual_active = FALSE;
- redo_VIsual_busy = FALSE;
- may_clear_cmdline();
- redraw_later(INVERTED);
- }
+ clearop(cap->oap);
}
/*
@@ -7924,6 +7892,7 @@ nv_g_cmd(cap)
{
cap->arg = TRUE;
cap->cmdchar = cap->nchar;
+ cap->nchar = NUL;
nv_addsub(cap);
}
else
diff --git a/src/ops.c b/src/ops.c
index 2dcdb778a3..d285893058 100644
--- a/src/ops.c
+++ b/src/ops.c
@@ -112,6 +112,7 @@ static void dis_msg __ARGS((char_u *p, int skip_esc));
static char_u *skip_comment __ARGS((char_u *line, int process, int include_space, int *is_comment));
#endif
static void block_prep __ARGS((oparg_T *oap, struct block_def *, linenr_T, int));
+static int do_addsub __ARGS((int op_type, pos_T *pos, int length, linenr_T Prenum1));
#if defined(FEAT_CLIPBOARD) || defined(FEAT_EVAL)
static void str_to_reg __ARGS((struct yankreg *y_ptr, int yank_type, char_u *str, long len, long blocklen, int str_list));
#endif
@@ -158,6 +159,8 @@ static char opchars[][3] =
{'z', 'D', TRUE}, /* OP_FOLDDELREC */
{'g', 'w', TRUE}, /* OP_FORMAT2 */
{'g', '@', FALSE}, /* OP_FUNCTION */
+ {Ctrl_A, NUL, FALSE}, /* OP_NR_ADD */
+ {Ctrl_X, NUL, FALSE}, /* OP_NR_SUB */
};
/*
@@ -175,6 +178,10 @@ get_op_type(char1, char2)
return OP_REPLACE;
if (char1 == '~') /* when tilde is an operator */
return OP_TILDE;
+ if (char1 == 'g' && char2 == Ctrl_A) /* add */
+ return OP_NR_ADD;
+ if (char1 == 'g' && char2 == Ctrl_X) /* subtract */
+ return OP_NR_SUB;
for (i = 0; ; ++i)
if (opchars[i][0] == char1 && opchars[i][1] == char2)
break;
@@ -5340,16 +5347,131 @@ block_prep(oap, bdp, lnum, is_del)
}
/*
- * add or subtract 'Prenum1' from a number in a line
- * 'command' is CTRL-A for add, CTRL-X for subtract
+ * Handle the add/subtract operator.
+ */
+ void
+op_addsub(oap, Prenum1, g_cmd)
+ oparg_T *oap;
+ linenr_T Prenum1; /* Amount of add/subtract */
+ int g_cmd; /* was g<c-a>/g<c-x> */
+{
+ pos_T pos;
+ struct block_def bd;
+ int change_cnt = 0;
+ linenr_T amount = Prenum1;
+
+ if (!VIsual_active)
+ {
+ pos = curwin->w_cursor;
+ if (u_save_cursor() == FAIL)
+ return;
+ change_cnt = do_addsub(oap->op_type, &pos, 0, amount);
+ if (change_cnt)
+ changed_lines(pos.lnum, 0, pos.lnum + 1, 0L);
+ }
+ else
+ {
+ int one_change;
+ int length;
+ pos_T startpos;
+
+ if (u_save((linenr_T)(oap->start.lnum - 1),
+ (linenr_T)(oap->end.lnum + 1)) == FAIL)
+ return;
+
+ pos = oap->start;
+ for (; pos.lnum <= oap->end.lnum; ++pos.lnum)
+ {
+ if (oap->block_mode) /* Visual block mode */
+ {
+ block_prep(oap, &bd, pos.lnum, FALSE);
+ pos.col = bd.textcol;
+ length = bd.textlen;
+ }
+ else
+ {
+ if (oap->motion_type == MLINE)
+ {
+ curwin->w_cursor.col = 0;
+ pos.col = 0;
+ length = (colnr_T)STRLEN(ml_get(pos.lnum));
+ }
+ else if (oap->motion_type == MCHAR)
+ {
+ if (!oap->inclusive)
+ dec(&(oap->end));
+ length = (colnr_T)STRLEN(ml_get(pos.lnum));
+ pos.col = 0;
+ if (pos.lnum == oap->start.lnum)
+ {
+ pos.col += oap->start.col;
+ length -= oap->start.col;
+ }
+ if (pos.lnum == oap->end.lnum)
+ {
+ length = (int)STRLEN(ml_get(oap->end.lnum));
+ if (oap->end.col >= length)
+ oap->end.col = length - 1;
+ length = oap->end.col - pos.col + 1;
+ }
+ }
+ }
+ one_change = do_addsub(oap->op_type, &pos, length, amount);
+ if (one_change)
+ {
+ /* Remember the start position of the first change. */
+ if (change_cnt == 0)
+ startpos = curbuf->b_op_start;
+ ++change_cnt;
+ }
+
+#ifdef FEAT_NETBEANS_INTG
+ if (netbeans_active() && one_change)
+ {
+ char_u *ptr = ml_get_buf(curbuf, pos.lnum, FALSE);
+
+ netbeans_removed(curbuf, pos.lnum, pos.col, (long)length);
+ netbeans_inserted(curbuf, pos.lnum, pos.col,
+ &ptr[pos.col], length);
+ }
+#endif
+ if (g_cmd && one_change)
+ amount += Prenum1;
+ }
+ if (change_cnt)
+ changed_lines(oap->start.lnum, 0, oap->end.lnum + 1, 0L);
+
+ if (!change_cnt && oap->is_VIsual)
+ /* No change: need to remove the Visual selection */
+ redraw_curbuf_later(INVERTED);
+
+ /* Set '[ mark if something changed. Keep the last end
+ * position from do_addsub(). */
+ if (change_cnt > 0)
+ curbuf->b_op_start = startpos;
+
+ if (change_cnt > p_report)
+ {
+ if (change_cnt == 1)
+ MSG(_("1 line changed"));
+ else
+ smsg((char_u *)_("%ld lines changed"), change_cnt);
+ }
+ }
+}
+
+/*
+ * Add or subtract 'Prenum1' from a number in a line
+ * op_type is OP_NR_ADD or OP_NR_SUB
*
- * return FAIL for failure, OK otherwise
+ * Returns TRUE if some character was changed.
*/
- int
-do_addsub(command, Prenum1, g_cmd)
- int command;
+ static int
+do_addsub(op_type, pos, length, Prenum1)
+ int op_type;
+ pos_T *pos;
+ int length;
linenr_T Prenum1;
- int g_cmd; /* was g<c-a>/g<c-x> */
{
int col;
char_u *buf1;
@@ -5357,11 +5479,9 @@ do_addsub(command, Prenum1, g_cmd)
int pre; /* 'X'/'x': hex; '0': octal; 'B'/'b': bin */
static int hexupper = FALSE; /* 0xABC */
unsigned long n;
- unsigned long offset = 0; /* line offset for Ctrl_V mode */
long_u oldn;
char_u *ptr;
int c;
- int length = 0; /* character length of the number */
int todel;
int dohex;
int dooct;
@@ -5372,16 +5492,9 @@ do_addsub(command, Prenum1, g_cmd)
int negative = FALSE;
int was_positive = TRUE;
int visual = VIsual_active;
- int i;
- int lnum = curwin->w_cursor.lnum;
- int lnume = curwin->w_cursor.lnum;
- int startcol = 0;
int did_change = FALSE;
pos_T t = curwin->w_cursor;
int maxlen = 0;
- int pos = 0;
- int bit = 0;
- int bits = sizeof(unsigned long) * 8;
pos_T startpos;
pos_T endpos;
@@ -5390,50 +5503,18 @@ do_addsub(command, Prenum1, g_cmd)
dobin = (vim_strchr(curbuf->b_p_nf, 'b') != NULL); /* "Bin" */
doalp = (vim_strchr(curbuf->b_p_nf, 'p') != NULL); /* "alPha" */
+ curwin->w_cursor = *pos;
+ ptr = ml_get(pos->lnum);
+ col = pos->col;
+
+ if (*ptr == NUL)
+ goto theend;
+
/*
* First check if we are on a hexadecimal number, after the "0x".
*/
- col = curwin->w_cursor.col;
- if (VIsual_active)
- {
- if (lt(curwin->w_cursor, VIsual))
- {
- curwin->w_cursor = VIsual;
- VIsual = t;
- }
-
- ptr = ml_get(VIsual.lnum);
- if (VIsual_mode == 'V')
- {
- VIsual.col = 0;
- curwin->w_cursor.col = (colnr_T)STRLEN(ptr);
- }
- else if (VIsual_mode == Ctrl_V && VIsual.col > curwin->w_cursor.col)
- {
- t = VIsual;
- VIsual.col = curwin->w_cursor.col;
- curwin->w_cursor.col = t.col;
- }
-
- /* store visual area for 'gv' */
- curbuf->b_visual.vi_start = VIsual;
- curbuf->b_visual.vi_end = curwin->w_cursor;
- curbuf->b_visual.vi_mode = VIsual_mode;
- curbuf->b_visual.vi_curswant = curwin->w_curswant;
-
- if (VIsual_mode != 'v')
- startcol = VIsual.col < curwin->w_cursor.col ? VIsual.col
- : curwin->w_cursor.col;
- else
- startcol = VIsual.col;
- col = startcol;
- lnum = VIsual.lnum;
- lnume = curwin->w_cursor.lnum;
- }
- else
+ if (!VIsual_active)
{
- ptr = ml_get_curline();
-
if (dobin)
while (col > 0 && vim_isbdigit(ptr[col]))
--col;
@@ -5453,7 +5534,7 @@ do_addsub(command, Prenum1, g_cmd)
/* In case of binary/hexadecimal pattern overlap match, rescan */
- col = curwin->w_cursor.col;
+ col = pos->col;
while (col > 0 && vim_isdigit(ptr[col]))
col--;
@@ -5480,7 +5561,7 @@ do_addsub(command, Prenum1, g_cmd)
/*
* Search forward and then backward to find the start of number.
*/
- col = curwin->w_cursor.col;
+ col = pos->col;
while (ptr[col] != NUL
&& !vim_isdigit(ptr[col])
@@ -5494,308 +5575,253 @@ do_addsub(command, Prenum1, g_cmd)
}
}
- for (i = lnum; i <= lnume; i++)
+ if (visual)
{
- colnr_T stop = 0;
-
- t = curwin->w_cursor;
- curwin->w_cursor.lnum = i;
- ptr = ml_get_curline();
- if ((int)STRLEN(ptr) <= col)
- /* try again on next line */
- continue;
- if (visual)
+ while (ptr[col] != NUL && length > 0
+ && !vim_isdigit(ptr[col])
+ && !(doalp && ASCII_ISALPHA(ptr[col])))
{
- if (VIsual_mode == 'v'
- && i == lnume)
- stop = curwin->w_cursor.col;
- else if (VIsual_mode == Ctrl_V
- && curbuf->b_visual.vi_curswant != MAXCOL)
- stop = curwin->w_cursor.col;
+ ++col;
+ --length;
+ }
- while (ptr[col] != NUL
- && !vim_isdigit(ptr[col])
- && !(doalp && ASCII_ISALPHA(ptr[col])))
- {
- if (col > 0 && col == stop)
- break;
- ++col;
- }
+ if (length == 0)
+ goto theend;
- if (col > startcol && ptr[col - 1] == '-')
- {
- negative = TRUE;
- was_positive = FALSE;
- }
- }
- /*
- * If a number was found, and saving for undo works, replace the number.
- */
- firstdigit = ptr[col];
- if ((!VIM_ISDIGIT(firstdigit) && !(doalp && ASCII_ISALPHA(firstdigit)))
- || u_save_cursor() != OK)
+ if (col > pos->col && ptr[col - 1] == '-')
{
- if (lnum < lnume)
- {
- if (visual && VIsual_mode != Ctrl_V)
- col = 0;
- else
- col = startcol;
- /* Try again on next line */
- continue;
- }
- beep_flush();
- return FAIL;
+ negative = TRUE;
+ was_positive = FALSE;
}
+ }
+
+ /*
+ * If a number was found, and saving for undo works, replace the number.
+ */
+ firstdigit = ptr[col];
+ if (!VIM_ISDIGIT(firstdigit) && !(doalp && ASCII_ISALPHA(firstdigit)))
+ {
+ beep_flush();
+ goto theend;
+ }
- if (doalp && ASCII_ISALPHA(firstdigit))
+ if (doalp && ASCII_ISALPHA(firstdigit))
+ {
+ /* decrement or increment alphabetic character */
+ if (op_type == OP_NR_SUB)
{
- /* decrement or increment alphabetic character */
- if (command == Ctrl_X)
+ if (CharOrd(firstdigit) < Prenum1)
{
- if (CharOrd(firstdigit) < Prenum1)
- {
- if (isupper(firstdigit))
- firstdigit = 'A';
- else
- firstdigit = 'a';
- }
+ if (isupper(firstdigit))
+ firstdigit = 'A';
else
-#ifdef EBCDIC
- firstdigit = EBCDIC_CHAR_ADD(firstdigit, -Prenum1);
-#else
- firstdigit -= Prenum1;
-#endif
+ firstdigit = 'a';
}
else
- {
- if (26 - CharOrd(firstdigit) - 1 < Prenum1)
- {
- if (isupper(firstdigit))
- firstdigit = 'Z';
- else
- firstdigit = 'z';
- }
- else
#ifdef EBCDIC
- firstdigit = EBCDIC_CHAR_ADD(firstdigit, Prenum1);
+ firstdigit = EBCDIC_CHAR_ADD(firstdigit, -Prenum1);
#else
- firstdigit += Prenum1;
+ firstdigit -= Prenum1;
#endif
- }
- curwin->w_cursor.col = col;
- if (!did_change)
- startpos = curwin->w_cursor;
- did_change = TRUE;
- (void)del_char(FALSE);
- ins_char(firstdigit);
- endpos = curwin->w_cursor;
- curwin->w_cursor.col = col;
}
else
{
- if (col > 0 && ptr[col - 1] == '-' && !visual)
- {
- /* negative number */
- --col;
- negative = TRUE;
- }
- /* get the number value (unsigned) */
- if (visual && VIsual_mode != 'V')
- {
- if (VIsual_mode == 'v')
- {
- if (i == lnum)
- maxlen = (lnum == lnume
- ? curwin->w_cursor.col - col + 1
- : (int)STRLEN(ptr) - col);
- else
- maxlen = (i == lnume ? curwin->w_cursor.col - col + 1
- : (int)STRLEN(ptr) - col);
- }
- else if (VIsual_mode == Ctrl_V)
- maxlen = (curbuf->b_visual.vi_curswant == MAXCOL
- ? (int)STRLEN(ptr) - col
- : curwin->w_cursor.col - col + 1);
- }
-
- vim_str2nr(ptr + col, &pre, &length,
- 0 + (dobin ? STR2NR_BIN : 0)
- + (dooct ? STR2NR_OCT : 0)
- + (dohex ? STR2NR_HEX : 0),
- NULL, &n, maxlen);
-
- /* ignore leading '-' for hex and octal and bin numbers */
- if (pre && negative)
+ if (26 - CharOrd(firstdigit) - 1 < Prenum1)
{
- ++col;
- --length;
- negative = FALSE;
+ if (isupper(firstdigit))
+ firstdigit = 'Z';
+ else
+ firstdigit = 'z';
}
+ else
+#ifdef EBCDIC
+ firstdigit = EBCDIC_CHAR_ADD(firstdigit, Prenum1);
+#else
+ firstdigit += Prenum1;
+#endif
+ }
+ curwin->w_cursor.col = col;
+ if (!did_change)
+ startpos = curwin->w_cursor;
+ did_change = TRUE;
+ (void)del_char(FALSE);
+ ins_char(firstdigit);
+ endpos = curwin->w_cursor;
+ curwin->w_cursor.col = col;
+ }
+ else
+ {
+ if (col > 0 && ptr[col - 1] == '-' && !visual)
+ {
+ /* negative number */
+ --col;
+ negative = TRUE;
+ }
+ /* get the number value (unsigned) */
+ if (visual && VIsual_mode != 'V')
+ maxlen = (curbuf->b_visual.vi_curswant == MAXCOL
+ ? (int)STRLEN(ptr) - col
+ : length);
- /* add or subtract */
- subtract = FALSE;
- if (command == Ctrl_X)
- subtract ^= TRUE;
- if (negative)
- subtract ^= TRUE;
+ vim_str2nr(ptr + col, &pre, &length,
+ 0 + (dobin ? STR2NR_BIN : 0)
+ + (dooct ? STR2NR_OCT : 0)
+ + (dohex ? STR2NR_HEX : 0),
+ NULL, &n, maxlen);
- oldn = n;
+ /* ignore leading '-' for hex and octal and bin numbers */
+ if (pre && negative)
+ {
+ ++col;
+ --length;
+ negative = FALSE;
+ }
+ /* add or subtract */
+ subtract = FALSE;
+ if (op_type == OP_NR_SUB)
+ subtract ^= TRUE;
+ if (negative)
+ subtract ^= TRUE;
+
+ oldn = n;
+ if (subtract)
+ n -= (unsigned long)Prenum1;
+ else
+ n += (unsigned long)Prenum1;
+ /* handle wraparound for decimal numbers */
+ if (!pre)
+ {
if (subtract)
- n -= (unsigned long)Prenum1;
- else
- n += (unsigned long)Prenum1;
-
- /* handle wraparound for decimal numbers */
- if (!pre)
{
- if (subtract)
+ if (n > oldn)
{
- if (n > oldn)
- {
- n = 1 + (n ^ (unsigned long)-1);
- negative ^= TRUE;
- }
+ n = 1 + (n ^ (unsigned long)-1);
+ negative ^= TRUE;
}
- else
- {
- /* add */
- if (n < oldn)
- {
- n = (n ^ (unsigned long)-1);
- negative ^= TRUE;
- }
- }
- if (n == 0)
- negative = FALSE;
- }
-
- if (visual && !was_positive && !negative && col > 0)
- {
- /* need to remove the '-' */
- col--;
- length++;
}
-
-
- /*
- * Delete the old number.
- */
- curwin->w_cursor.col = col;
- if (!did_change)
- startpos = curwin->w_cursor;
- did_change = TRUE;
- todel = length;
- c = gchar_cursor();
-
- /*
- * Don't include the '-' in the length, only the length of the
- * part after it is kept the same.
- */
- if (c == '-')
- --length;
- while (todel-- > 0)
+ else
{
- if (c < 0x100 && isalpha(c))
+ /* add */
+ if (n < oldn)
{
- if (isupper(c))
- hexupper = TRUE;
- else
- hexupper = FALSE;
+ n = (n ^ (unsigned long)-1);
+ negative ^= TRUE;
}
- /* del_char() will mark line needing displaying */
- (void)del_char(FALSE);
- c = gchar_cursor();
}
+ if (n == 0)
+ negative = FALSE;
+ }
- /*
- * Prepare the leading characters in buf1[].
- * When there are many leading zeros it could be very long.
- * Allocate a bit too much.
- */
- buf1 = alloc((unsigned)length + NUMBUFLEN);
- if (buf1 == NULL)
- return FAIL;
- ptr = buf1;
- if (negative && (!visual || (visual && was_positive)))
- {
- *ptr++ = '-';
- }
- if (pre)
- {
- *ptr++ = '0';
- --length;
- }
- if (pre == 'b' || pre == 'B' ||
- pre == 'x' || pre == 'X')
- {
- *ptr++ = pre;
- --length;
- }
+ if (visual && !was_positive && !negative && col > 0)
+ {
+ /* need to remove the '-' */
+ col--;
+ length++;
+ }
- /*
- * Put the number characters in buf2[].
- */
- if (pre == 'b' || pre == 'B')
+ /*
+ * Delete the old number.
+ */
+ curwin->w_cursor.col = col;
+ if (!did_change)
+ startpos = curwin->w_cursor;
+ did_change = TRUE;
+ todel = length;
+ c = gchar_cursor();
+ /*
+ * Don't include the '-' in the length, only the length of the
+ * part after it is kept the same.
+ */
+ if (c == '-')
+ --length;
+ while (todel-- > 0)
+ {
+ if (c < 0x100 && isalpha(c))
{
- /* leading zeros */
- for (bit = bits; bit > 0; bit--)
- if ((n >> (bit - 1)) & 0x1) break;
-
- for (pos = 0; bit > 0; bit--)
- buf2[pos++] = ((n >> (bit - 1)) & 0x1) ? '1' : '0';
-
- buf2[pos] = '\0';
+ if (isupper(c))
+ hexupper = TRUE;
+ else
+ hexupper = FALSE;
}
- else if (pre == 0)
- sprintf((char *)buf2, "%lu", n);
- else if (pre == '0')
- sprintf((char *)buf2, "%lo", n);
- else if (pre && hexupper)
- sprintf((char *)buf2, "%lX", n);
- else
- sprintf((char *)buf2, "%lx", n);
- length -= (int)STRLEN(buf2);
+ /* del_char() will mark line needing displaying */
+ (void)del_char(FALSE);
+ c = gchar_cursor();
+ }
- /*
- * Adjust number of zeros to the new number of digits, so the
- * total length of the number remains the same.
- * Don't do this when
- * the result may look like an octal number.
- */
- if (firstdigit == '0' && !(dooct && pre == 0))
- while (length-- > 0)
- *ptr++ = '0';
- *ptr = NUL;
- STRCAT(buf1, buf2);
- ins_str(buf1); /* insert the new number */
- vim_free(buf1);
- endpos = curwin->w_cursor;
- if (lnum < lnume)
- curwin->w_cursor.col = t.col;
- else if (did_change && curwin->w_cursor.col)
- --curwin->w_cursor.col;
+ /*
+ * Prepare the leading characters in buf1[].
+ * When there are many leading zeros it could be very long.
+ * Allocate a bit too much.
+ */
+ buf1 = alloc((unsigned)length + NUMBUFLEN);
+ if (buf1 == NULL)
+ goto theend;
+ ptr = buf1;
+ if (negative && (!visual || (visual && was_positive)))
+ {
+ *ptr++ = '-';
+ }
+ if (pre)
+ {
+ *ptr++ = '0';
+ --length;
+ }
+ if (pre == 'b' || pre == 'B' ||
+ pre == 'x' || pre == 'X')
+ {
+ *ptr++ = pre;
+ --length;
}
- if (g_cmd)
+ /*
+ * Put the number characters in buf2[].
+ */
+ if (pre == 'b' || pre == 'B')
{
- offset = (unsigned long)Prenum1;
- g_cmd = 0;
+ int i;
+ int bit = 0;
+ int bits = sizeof(unsigned long) * 8;
+
+ /* leading zeros */
+ for (bit = bits; bit > 0; bit--)
+ if ((n >> (bit - 1)) & 0x1) break;
+
+ for (i = 0; bit > 0; bit--)
+ buf2[i++] = ((n >> (bit - 1)) & 0x1) ? '1' : '0';
+
+ buf2[i] = '\0';
}
- /* reset */
- subtract = FALSE;
- negative = FALSE;
- was_positive = TRUE;
- if (visual && VIsual_mode == Ctrl_V)
- col = startcol;
+ else if (pre == 0)
+ sprintf((char *)buf2, "%lu", n);
+ else if (pre == '0')
+ sprintf((char *)buf2, "%lo", n);
+ else if (pre && hexupper)
+ sprintf((char *)buf2, "%lX", n);
else
- col = 0;
- Prenum1 += offset;
- curwin->w_set_curswant = TRUE;
+ sprintf((char *)buf2, "%lx", n);
+ length -= (int)STRLEN(buf2);
+
+ /*
+ * Adjust number of zeros to the new number of digits, so the
+ * total length of the number remains the same.
+ * Don't do this when
+ * the result may look like an octal number.
+ */
+ if (firstdigit == '0' && !(dooct && pre == 0))
+ while (length-- > 0)
+ *ptr++ = '0';
+ *ptr = NUL;
+ STRCAT(buf1, buf2);
+ ins_str(buf1); /* insert the new number */
+ vim_free(buf1);
+ endpos = curwin->w_cursor;
+ if (did_change && curwin->w_cursor.col)
+ --curwin->w_cursor.col;
}
+
+theend:
if (visual)
- /* cursor at the top of the selection */
- curwin->w_cursor = VIsual;
+ curwin->w_cursor = t;
if (did_change)
{
/* set the '[ and '] marks */
@@ -5804,7 +5830,8 @@ do_addsub(command, Prenum1, g_cmd)
if (curbuf->b_op_end.col > 0)
--curbuf->b_op_end.col;
}
- return OK;
+
+ return did_change;
}
#ifdef FEAT_VIMINFO
diff --git a/src/proto/ops.pro b/src/proto/ops.pro
index aaffa02025..27e0f118aa 100644
--- a/src/proto/ops.pro
+++ b/src/proto/ops.pro
@@ -43,7 +43,7 @@ void op_formatexpr __ARGS((oparg_T *oap));
int fex_format __ARGS((linenr_T lnum, long count, int c));
void format_lines __ARGS((linenr_T line_count, int avoid_fex));
int paragraph_start __ARGS((linenr_T lnum));
-int do_addsub __ARGS((int command, linenr_T Prenum1, int g_cmd));
+void op_addsub __ARGS((oparg_T *oap, linenr_T Prenum1, int g_cmd));
int read_viminfo_register __ARGS((vir_T *virp, int force));
void write_viminfo_registers __ARGS((FILE *fp));
void x11_export_final_selection __ARGS((void));
diff --git a/src/testdir/test_increment.vim b/src/testdir/test_increment.vim
index 51cc45f98d..e4f67eacad 100644
--- a/src/testdir/test_increment.vim
+++ b/src/testdir/test_increment.vim
@@ -133,7 +133,7 @@ func Test_visual_increment_04()
exec "norm! vf-\<C-A>"
call assert_equal(["foobar-10"], getline(1, '$'))
" NOTE: I think this is correct behavior...
- "call assert_equal([0, 1, 1, 0], getpos('.'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
endfunc
" 5) g<Ctrl-A> on letter
@@ -576,7 +576,111 @@ func Test_visual_increment_27()
endif
endfunc
-" 28) block-wise increment and dot-repeat
+" Tab code and linewise-visual inc/dec
+func Test_visual_increment_28()
+ call setline(1, ["x\<TAB>10", "\<TAB>-1"])
+ exec "norm! Vj\<C-A>"
+ call assert_equal(["x\<TAB>11", "\<TAB>0"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+
+ call setline(1, ["x\<TAB>10", "\<TAB>-1"])
+ exec "norm! ggVj\<C-X>"
+ call assert_equal(["x\<TAB>9", "\<TAB>-2"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" Tab code and linewise-visual inc/dec with 'nrformats'+=alpha
+func Test_visual_increment_29()
+ set nrformats+=alpha
+ call setline(1, ["x\<TAB>10", "\<TAB>-1"])
+ exec "norm! Vj\<C-A>"
+ call assert_equal(["y\<TAB>10", "\<TAB>0"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+
+ call setline(1, ["x\<TAB>10", "\<TAB>-1"])
+ exec "norm! ggVj\<C-X>"
+ call assert_equal(["w\<TAB>10", "\<TAB>-2"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" Tab code and character-visual inc/dec
+func Test_visual_increment_30()
+ call setline(1, ["x\<TAB>10", "\<TAB>-1"])
+ exec "norm! f1vjf1\<C-A>"
+ call assert_equal(["x\<TAB>11", "\<TAB>0"], getline(1, '$'))
+ call assert_equal([0, 1, 3, 0], getpos('.'))
+
+ call setline(1, ["x\<TAB>10", "\<TAB>-1"])
+ exec "norm! ggf1vjf1\<C-X>"
+ call assert_equal(["x\<TAB>9", "\<TAB>-2"], getline(1, '$'))
+ call assert_equal([0, 1, 3, 0], getpos('.'))
+endfunc
+
+" Tab code and blockwise-visual inc/dec
+func Test_visual_increment_31()
+ call setline(1, ["x\<TAB>10", "\<TAB>-1"])
+ exec "norm! f1\<C-V>jl\<C-A>"
+ call assert_equal(["x\<TAB>11", "\<TAB>0"], getline(1, '$'))
+ call assert_equal([0, 1, 3, 0], getpos('.'))
+
+ call setline(1, ["x\<TAB>10", "\<TAB>-1"])
+ exec "norm! ggf1\<C-V>jl\<C-X>"
+ call assert_equal(["x\<TAB>9", "\<TAB>-2"], getline(1, '$'))
+ call assert_equal([0, 1, 3, 0], getpos('.'))
+endfunc
+
+" Tab code and blockwise-visual decrement with 'linebreak' and 'showbreak'
+func Test_visual_increment_32()
+ 28vnew dummy_31
+ set linebreak showbreak=+
+ call setline(1, ["x\<TAB>\<TAB>\<TAB>10", "\<TAB>\<TAB>\<TAB>\<TAB>-1"])
+ exec "norm! ggf0\<C-V>jg_\<C-X>"
+ call assert_equal(["x\<TAB>\<TAB>\<TAB>1-1", "\<TAB>\<TAB>\<TAB>\<TAB>-2"], getline(1, '$'))
+ call assert_equal([0, 1, 6, 0], getpos('.'))
+ bwipe!
+endfunc
+
+" Tab code and blockwise-visual increment with $
+func Test_visual_increment_33()
+ call setline(1, ["\<TAB>123", "456"])
+ exec "norm! gg0\<C-V>j$\<C-A>"
+ call assert_equal(["\<TAB>124", "457"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" Tab code and blockwise-visual increment and redo
+func Test_visual_increment_34()
+ call setline(1, ["\<TAB>123", " 456789"])
+ exec "norm! gg0\<C-V>j\<C-A>"
+ call assert_equal(["\<TAB>123", " 457789"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+
+ exec "norm! .."
+ call assert_equal(["\<TAB>123", " 459789"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" Tab code, spaces and character-visual increment and redo
+func Test_visual_increment_35()
+ call setline(1, ["\<TAB>123", " 123", "\<TAB>123", "\<TAB>123"])
+ exec "norm! ggvjf3\<C-A>..."
+ call assert_equal(["\<TAB>127", " 127", "\<TAB>123", "\<TAB>123"], getline(1, '$'))
+ call assert_equal([0, 1, 2, 0], getpos('.'))
+endfunc
+
+" Tab code, spaces and blockwise-visual increment and redo
+func Test_visual_increment_36()
+ call setline(1, [" 123", "\<TAB>456789"])
+ exec "norm! G0\<C-V>kl\<C-A>"
+ call assert_equal([" 123", "\<TAB>556789"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+
+ exec "norm! ..."
+ call assert_equal([" 123", "\<TAB>856789"], getline(1, '$'))
+ call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" block-wise increment and dot-repeat
" Text:
" 1 23
" 4 56
@@ -587,7 +691,7 @@ endfunc
" 4 59
"
" Try with and without indent.
-func Test_visual_increment_28()
+func Test_visual_increment_37()
call setline(1, [" 1 23", " 4 56"])
exec "norm! ggf2\<C-V>jl\<C-A>.."
call assert_equal([" 1 26", " 4 59"], getline(1, 2))
diff --git a/src/version.c b/src/version.c
index b753f174ed..db72d0596a 100644
--- a/src/version.c
+++ b/src/version.c
@@ -742,6 +742,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1087,
+/**/
1086,
/**/
1085,
diff --git a/src/vim.h b/src/vim.h
index fd0b0b0dc1..81d0929116 100644
--- a/src/vim.h
+++ b/src/vim.h
@@ -1457,6 +1457,10 @@ typedef UINT32_TYPEDEF UINT32_T;
#define OP_FOLDDELREC 25 /* "zD" delete folds recursively */
#define OP_FORMAT2 26 /* "gw" format operator, keeps cursor pos */
#define OP_FUNCTION 27 /* "g@" call 'operatorfunc' */
+#define OP_NR_ADD 28 /* "<C-A>" Add to the number or alphabetic
+ character (OP_ADD conflicts with Perl) */
+#define OP_NR_SUB 29 /* "<C-X>" Subtract from the number or
+ alphabetic character */
/*
* Motion types, used for operators and for yank/delete registers.