To: Bram (As a Vimboss)
To: Christian Brabandt (As a visual <C-A>/<C-X> first patch author)
To: Jason Schulz (As a support for bin 'nrformats' patch author)

Hi,

I refactored visual <C-A>/<C-X> to support vcol et al.
This mean is <TAB> code free!

Contents of patch.
- visual <C-A>/<C-X> support vcol. (<TAB> code free)
- 'test_increment' convert from old style test to new style test. and added 
some test items. 
- Processing was allowed to separate.
  (line loop process and add/subtract process)
  (We have to use the existing function block_prep() to process the block-wise)
- We removed the halfway right-to-left processing.
  (Remove RLADDSUBFIX() macro)
  (This is causing the actual problem)
   $ vim -Nu NONE -c "set rightleft"
   i123 45<Esc>
   <C-A>           " Unexpected swap the numbers of strings occurred.

Christian Brabandt and Jason Schulz and List>
I was wondering if you could review this patch.

Jason Schulz>
Sorry to such just your patch was included.
I have just completed the doing has been working since last fall :-)

Thanks.
--
Best regards,
Hirohito Higashi (a.k.a h_east)

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.
diff --git a/src/Makefile b/src/Makefile
index 500287f..8a38d36 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1944,7 +1944,6 @@ test1 \
 	test_erasebackword \
 	test_eval \
 	test_fixeol \
-	test_increment \
 	test_insertcount \
 	test_listchars \
 	test_listlbr \
@@ -1977,11 +1976,17 @@ test1 \
 	cd testdir; rm -f [email protected]; $(MAKE) -f Makefile [email protected] VIMPROG=../$(VIMTARGET) $(GUI_TESTARG) SCRIPTSOURCE=../$(SCRIPTSOURCE)
 
 test_assert \
+	test_backspace_opt \
 	test_cdo \
+	test_increment \
+	test_lispwords \
+	test_menu \
+	test_quickfix \
 	test_searchpos \
 	test_set \
 	test_sort \
 	test_undolevels \
+	test_unlet \
 	test_viml \
 	test_alot:
 	cd testdir; rm -f [email protected] test.log messages; $(MAKE) -f Makefile [email protected] VIMPROG=../$(VIMTARGET) $(GUI_TESTARG) SCRIPTSOURCE=../$(SCRIPTSOURCE)
diff --git a/src/normal.c b/src/normal.c
index 640c060..afaf43d 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_ADD:
+	case OP_SUBTRACT:
+	    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 - 1);
-	    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_ADD : OP_SUBTRACT;
+	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 d02b784..66a9d5d 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_ADD */
+    {Ctrl_X, NUL, FALSE},	/* OP_SUBTRACT */
 };
 
 /*
@@ -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_ADD;
+    if (char1 == 'g' && char2 == Ctrl_X)	/* subtract */
+	return OP_SUBTRACT;
     for (i = 0; ; ++i)
 	if (opchars[i][0] == char1 && opchars[i][1] == char2)
 	    break;
@@ -5339,42 +5346,126 @@ block_prep(oap, bdp, lnum, is_del)
     bdp->textstart = pstart;
 }
 
-#ifdef FEAT_RIGHTLEFT
-static void reverse_line __ARGS((char_u *s));
-
-    static void
-reverse_line(s)
-    char_u *s;
+/*
+ * 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> */
 {
-    int	    i, j;
-    char_u  c;
-
-    if ((i = (int)STRLEN(s) - 1) <= 0)
-	return;
+    pos_T		pos;
+    struct block_def	bd;
+    int			did_change = FALSE;
+    linenr_T		amount = Prenum1;
 
-    curwin->w_cursor.col = i - curwin->w_cursor.col;
-    for (j = 0; j < i; j++, i--)
+    if (!VIsual_active)
     {
-	c = s[i]; s[i] = s[j]; s[j] = c;
+	pos = curwin->w_cursor;
+	if (u_save_cursor() == FAIL)
+	    return;
+	did_change = do_addsub(oap->op_type, &pos, 0, amount);
+	if (did_change)
+	    changed_lines(pos.lnum, 0, pos.lnum + 1, 0L);
     }
-}
+    else
+    {
+	int one_change;
+	int length;
 
-# define RLADDSUBFIX(ptr) if (curwin->w_p_rl) reverse_line(ptr);
-#else
-# define RLADDSUBFIX(ptr)
+	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);
+	    did_change |= one_change;
+
+#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 (did_change)
+	    changed_lines(oap->start.lnum, 0, oap->end.lnum + 1, 0L);
+
+	if (!did_change && oap->is_VIsual)
+	    /* No change: need to remove the Visual selection */
+	    redraw_curbuf_later(INVERTED);
+
+	/*
+	* Set '[ and '] marks.
+	*/
+	curbuf->b_op_start = oap->start;
+	curbuf->b_op_end = oap->end;
+
+	if (did_change && oap->line_count > p_report)
+	{
+	    if (oap->line_count == 1)
+		MSG(_("1 line changed"));
+	    else
+		smsg((char_u *)_("%ld lines changed"), oap->line_count);
+	}
+    }
+}
 
 /*
- * add or subtract 'Prenum1' from a number in a line
- * 'command' is CTRL-A for add, CTRL-X for subtract
+ * Add or subtract 'Prenum1' from a number in a line
+ * op_type is OP_ADD or OP_SUBTRACT
  *
- * 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;
@@ -5382,11 +5473,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;
@@ -5397,68 +5486,27 @@ 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;
 
     dohex = (vim_strchr(curbuf->b_p_nf, 'x') != NULL);	/* "heX" */
     dooct = (vim_strchr(curbuf->b_p_nf, 'o') != NULL);	/* "Octal" */
     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 (!VIsual_active)
     {
-	if (lt(curwin->w_cursor, VIsual))
-	{
-	    curwin->w_cursor = VIsual;
-	    VIsual = t;
-	}
-
-	ptr = ml_get(VIsual.lnum);
-	RLADDSUBFIX(ptr);
-	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
-    {
-	ptr = ml_get_curline();
-	RLADDSUBFIX(ptr);
-
 	if (dobin)
 	    while (col > 0 && vim_isbdigit(ptr[col]))
 		--col;
@@ -5477,8 +5525,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--;
@@ -5505,7 +5552,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])
@@ -5519,308 +5566,251 @@ 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();
-	RLADDSUBFIX(ptr);
-	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_SUBTRACT)
 	{
-	    /* 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;
-	    did_change = TRUE;
-	    (void)del_char(FALSE);
-	    ins_char(firstdigit);
-	    curwin->w_cursor.col = col;
 	}
 	else
 	{
-	    if (col > 0 && ptr[col - 1] == '-' && !visual)
+	    if (26 - CharOrd(firstdigit) - 1 < Prenum1)
 	    {
-		/* 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);
+		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;
+	did_change = TRUE;
+	(void)del_char(FALSE);
+	ins_char(firstdigit);
+	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);
 
-	    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)
-	    {
-		++col;
-		--length;
-		negative = FALSE;
-	    }
+	vim_str2nr(ptr + col, &pre, &length,
+		0 + (dobin ? STR2NR_BIN : 0)
+		    + (dooct ? STR2NR_OCT : 0)
+		    + (dohex ? STR2NR_HEX : 0),
+		NULL, &n, maxlen);
 
-	    /* add or subtract */
-	    subtract = FALSE;
-	    if (command == Ctrl_X)
-		subtract ^= TRUE;
-	    if (negative)
-		subtract ^= TRUE;
+	/* 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_SUBTRACT)
+	    subtract ^= TRUE;
+	if (negative)
+	    subtract ^= TRUE;
+
+	oldn = n;
+	if (subtract)
+	    n -= (unsigned long)Prenum1;
+	else
+	    n += (unsigned long)Prenum1;
 
-	    oldn = n;
+	/* 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)
-		    {
-			n = 1 + (n ^ (unsigned long)-1);
-			negative ^= TRUE;
-		    }
-		}
-		else
+		if (n > oldn)
 		{
-		    /* add */
-		    if (n < oldn)
-		    {
-			n = (n ^ (unsigned long)-1);
-			negative ^= TRUE;
-		    }
+		    n = 1 + (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;
-	    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')
-	    {
-		/* 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';
+	/*
+	 * Delete the old number.
+	 */
+	curwin->w_cursor.col = col;
+	did_change = TRUE;
+	todel = length;
+	c = gchar_cursor();
 
-		buf2[pos] = '\0';
+	/*
+	 * 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))
+	    {
+		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);
-	    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;
-#ifdef FEAT_RIGHTLEFT
-	ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum, TRUE);
-	RLADDSUBFIX(ptr);
-#endif
+	    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);
+	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;
-    return OK;
+	curwin->w_cursor = t;
+    return did_change;
 }
 
 #ifdef FEAT_VIMINFO
diff --git a/src/proto/ops.pro b/src/proto/ops.pro
index aaffa02..27e0f11 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/Make_all.mak b/src/testdir/Make_all.mak
index 2ad039c..de5c45e 100644
--- a/src/testdir/Make_all.mak
+++ b/src/testdir/Make_all.mak
@@ -174,6 +174,7 @@ SCRIPTS_GUI = test16.out
 # Keep test_alot.res as the last one, sort the others.
 NEW_TESTS = test_assert.res \
 	    test_cdo.res \
+		test_increment.res \
 	    test_quickfix.res \
 	    test_viml.res \
 	    test_alot.res
diff --git a/src/testdir/test_increment.in b/src/testdir/test_increment.in
deleted file mode 100644
index f5d8ff9..0000000
--- a/src/testdir/test_increment.in
+++ /dev/null
@@ -1,734 +0,0 @@
-Tests for using Ctrl-A/Ctrl-X on visual selections
-
-Test cases
-==========
-
-1) Ctrl-A on visually selected number
-Text:
-foobar-10
-    Expected:
-    1)    Ctrl-A on start of line:
-	foobar-9
-    2)    Ctrl-A on visually selected "-10":
-	foobar-9
-    3)    Ctrl-A on visually selected "10":
-	foobar-11
-    4)    Ctrl-X on visually selected "-10"
-	foobar-11
-    5)    Ctrl-X on visually selected "10"
-	foobar-9
-
-2) Ctrl-A on visually selected lines
-Text:
-10
-20
-30
-40
-
-    Expected:
-    1) Ctrl-A on visually selected lines:
-11
-21
-31
-41
-
-    2) Ctrl-X on visually selected lines:
-9
-19
-29
-39
-
-3) g Ctrl-A on visually selected lines, with non-numbers in between
-Text:
-10
-
-20
-
-30
-
-40
-
-    Expected:
-    1) 2 g Ctrl-A on visually selected lines:
-12
-
-24
-
-36
-
-48
-    2) 2 g Ctrl-X on visually selected lines
-8
-
-16
-
-24
-
-32
-
-4) Ctrl-A on non-number
-Text:
-foobar-10
-    Expected:
-    1) visually select foobar:
-    foobar-10
-
-5) g<Ctrl-A> on letter
-Test:
-a
-a
-a
-a
-    Expected:
-    1) g Ctrl-A on visually selected lines
-    b
-    c
-    d
-    e
-
-6) g<Ctrl-A> on letter
-Test:
-z
-z
-z
-z
-    Expected:
-    1) g Ctrl-X on visually selected lines
-    y
-    x
-    w
-    v
-
-7) <Ctrl-A> on letter
-Test:
-2
-1
-0
--1
--2
-
-    Expected:
-    1) Ctrl-A on visually selected lines
-    3
-    2
-    1
-    0
-    -1
-
-    2) Ctrl-X on visually selected lines
-    1
-    0
-    -1
-    -2
-    -3
-8) Block increment on 0x9
-Text:
-0x9
-0x9
-    Expected:
-    1) Ctrl-A on visually block selected region (cursor at beginning):
-    0xa
-    0xa
-    2) Ctrl-A on visually block selected region (cursor at end)
-    0xa
-    0xa
-
-9) Increment and redo
-Text:
-2
-2
-
-3
-3
-
-    Expected:
-    1) 2 Ctrl-A on first 2 visually selected lines
-    4
-    4
-    2) redo (.) on 3
-    5
-    5
-10) sequentially decrement 1
-Text:
-1
-1
-1
-1
-    Expected:
-    1) g Ctrl-X on visually selected lines
-    0
-    -1
-    -2
-    -3
-
-11) visually block selected indented lines
-Text:
-    1
-1
-    1
-    1
-    Expexted:
-    1) g Ctrl-A on block selected indented lines
-    2
-1
-    3
-    4
-
-12) visually selected several columns
-Text:
-0 0
-0 0
-0 0
-    Expected:
-    1) 'v' select last zero and first zeroes
-    0 1
-    1 0
-    1 0
-
-13) visually selected part of columns
-Text:
-max: 100px
-max: 200px
-max: 300px
-max: 400px
-    Expected:
-    1) 'v' on first two numbers Ctrl-A
-    max: 110px
-    max: 220px
-    max: 330px
-    max: 400px
-    2) 'v' on first two numbers Ctrl-X
-    max: 90px
-    max: 190px
-    max: 290px
-    max: 400px
-
-14) redo in block mode
-Text:
-1 1
-1 1
-    Expected:
-    1) Ctrl-a on first column, redo on second column
-    2 2
-    2 2
-
-15) block select single numbers
-Text:
-101
-    Expected:
-    1) Ctrl-a on visually selected zero
-    111
-
-16) increment right aligned numbers
-Text:
-   1
-  19
- 119
-    Expected:
-    1) Ctrl-a on line selected region
-       2
-      20
-     120
-
-17) block-wise increment and redo
-Text:
-  100
-  1
-
-  100
-  1
-
-  Expected:
-  1) Ctrl-V j $ on first block, afterwards '.' on second
-  101
-  2
-
-  101
-  2
-
-18) repeat of g<Ctrl-a>
-Text:
-  0
-  0
-  0
-  0
-
-  Expected:
-  1) V 4j g<ctrl-a>, repeat twice afterwards with .
-  3
-  6
-  9
-  12
-  
-19) increment on number with nrformat including alpha
-Text:
- 1
- 1a
-
- Expected:
- 1) <Ctrl-V>j$ <ctrl-a>
- 2
- 2a
-
-20) increment a single letter
-Text:
- a
-
- Expected:
- 1) <Ctrl-a> and cursor is on a
- b
-
-21) block-wise increment on part of hexadecimal
-Text:
-0x123456
-
-  Expected:
-  1) Ctrl-V f3 <ctrl-a>
-0x124456
-
-22) Block increment on 0b0
-Text:
-0b1
-0b1
-    Expected:
-    1) Ctrl-A on visually block selected region (cursor at beginning):
-    0b10
-    0b10
-    2) Ctrl-A on visually block selected region (cursor at end)
-    0b10
-    0b10
-
-23) block-wise increment on part of binary
-Text:
-0b1001
-
-  Expected:
-  1) Ctrl-V 5l <ctrl-a>
-0b1011
-
-24) increment hexadecimal
-Text:
-0x0b1001
-
-  Expected:
-  1) <ctrl-a>
-0x0b1002
-
-25) increment binary with nrformats including alpha
-Text:
-0b1001a
-
-  Expected:
-  1) <ctrl-a>
-0b1010a
-
-26) increment binary with 64 bits
-Text:
-0b1111111111111111111111111111111111111111111111111111111111111110
-
-  Expected:
-  1) <ctrl-a>
-0b1111111111111111111111111111111111111111111111111111111111111111
-
-
-STARTTEST
-:so small.vim
-:"
-:" Avoid CTRL-X being mapped in Visual mode for MS-Windows
-:vmapclear
-:"
-:" Test 1
-:/^S1=/+,/^E1=/-y a
-:/^E1=/+put a
-:/^E1=/+2put a
-f-v$:/^E1=/+3put a
-f1v$:/^E1=/+4put a
-f-v$:/^E1=/+5put a
-f1v$
-
-:" Test 2
-:/^S2=/+,/^E2=/-y a
-:/^E2=/+put a
-V3k$3j:.+put a
-V3k$
-
-:" Test 3
-:/^S3=/+,/^E3=/-y a
-:/^E3=/+put a
-V6k2g6j:.+put a
-V6k2g
-
-:" Test 4
-:/^S4=/+,/^E4=/-y a
-:/^E4=/+put a
-vf-
-
-:" Test 5
-:set nrformats+=alpha
-:/^S5=/+,/^E5=/-y a
-:/^E5=/+put a
-v3kg
-
-:" Test 6
-:/^S6=/+,/^E6=/-y a
-:/^E6=/+put a
-v3kg
-
-:" Test 7
-:set nrformats&vim
-:/^S7=/+,/^E7=/-y a
-:/^E7=/+put a
-V4k4j:.+put a
-V4k
-
-:" Test 8
-:/^S8=/+,/^E8=/-y a
-:/^E8=/+put a
-kj$j:.+put a
-k$+
-
-:" Test 9
-:/^S9=/+,/^E9=/-y a
-:/^E9=/+put a
-5kVj23j.
-
-:" Test 10
-:/^S10=/+,/^E10=/-y a
-:/^E10=/+put a
-V3kg
-
-: Test 11
-:/^S11=/+,/^E11=/-y a
-:/^E11=/+put a
-3kf13jg
-
-:" Test 12
-:/^S12=/+,/^E12=/-y a
-:/^E12=/+put a
-2k$v++
-
-:" Test 13
-:/^S13=/+,/^E13=/-y a
-:/^E13=/+put a
-3kf1l2j3j:.+put a
-3kf1l2j
-
-:" Test 14
-:/^S14=/+,/^E14=/-y a
-:/^E14=/+put a
-kw.
-
-:" Test 15
-:/^S15=/+,/^E15=/-y a
-:/^E15=/+put a
-lv
-
-:" Test 16
-:/^S16=/+,/^E16=/-y a
-:/^E16=/+put a
-V3k
-
-:" Test 17
-:/^S17=/+,/^E17=/-y a
-:/^E17=/+put a
-4kj$2j.
-
-:" Test 18
-:/^S18=/+,/^E18=/-y a
-:/^E18=/+put a
-V3kg..
-
-:" Test 19
-:set nrformats+=alpha
-:/^S19=/+,/^E19=/-y a
-:/^E19=/+put a
-k$
-:set nrformats&vim
-
-:" Test 20
-:set nrformats+=alpha
-:/^S20=/+,/^E20=/-y a
-:/^E20=/+put a
-:.put =col('.')
-:set nrformats&vim
-
-:" Test 21
-:/^S21=/+,/^E21=/-y a
-:/^E21=/+put a
-:set nrformats&vim
-f3
-
-:" Test 22
-:/^S22=/+,/^E22=/-y a
-:/^E22=/+put a
-kj$j:.+put a
-k$+
-
-:" Test 23
-:/^S23=/+,/^E23=/-y a
-:/^E23=/+put a
-:set nrformats&vim
-4l
-
-:" Test 24
-:/^S24=/+,/^E24=/-y a
-:/^E24=/+put a
-:set nrformats&vim
-$
-
-:" Test 25
-:set nrformats+=alpha
-:/^S25=/+,/^E25=/-y a
-:/^E25=/+put a
-k$
-:set nrformats&vim
-
-:" Test 26
-:set nrformats+=alpha
-:/^S26=/+,/^E26=/-y a
-:/^E26=/+put a
-k$
-:set nrformats&vim
-
-:" Save the report
-:/^# Test 1/,$w! test.out
-:qa!
-
-
-# Test 1
-S1======
-foobar-10
-E1======
-
-
-
-# Test 2
-S2=====
-10
-20
-30
-40
-E2=====
-
-
-
-# Test 3
-S3=====
-10
-
-20
-
-30
-
-40
-E3=====
-
-
-
-# Test 4
-S4=====
-foobar-10
-E4=====
-
-
-
-# Test 5
-S5====
-a
-a
-a
-a
-E5====
-
-
-# Test 6
-S6====
-z
-z
-z
-z
-E6====
-
-
-
-# Test 7
-S7====
-2
-1
-0
--1
--2
-E7====
-
-
-
-# Test 8
-S8====
-0x9
-0x9
-E8====
-
-
-
-
-# Test 9
-S9====
-2
-2
-
-3
-3
-
-E9====
-
-
-
-
-# Test 10
-S10====
-1
-1
-1
-1
-E10====
-
-
-
-
-# Test 11
-S11====
-    1
-1
-    1
-    1
-E11====
-
-
-
-# Test 12
-S12====
-0 0
-0 0
-0 0
-E12====
-
-
-
-# Test 13
-S13====
-max: 100px
-max: 200px
-max: 300px
-max: 400px
-E13====
-
-
-
-# Test 14
-S14====
-1 1
-1 1
-E14====
-
-
-
-# Test 15
-S15====
-101
-E15====
-
-
-
-# Test 16
-S16====
-   1
-  19
- 119
-E16====
-
-
-
-# Test 17
-S17====
- 100
- 1
-
- 100
- 1
-E17====
-
-
-# Test 18
-S18====
-0
-0
-0
-0
-E18====
-
-
-
-# Test 19
-S19====
-1
-1a
-E19====
-
-
-
-# Test 20
-S20====
-a
-E20====
-
-
-
-# Test 21
-S21====
-0x123456
-E21====
-
-
-
-# Test 22
-S22====
-0b1
-0b1
-E22====
-
-
-
-
-# Test 23
-S23====
-0b1001
-E23====
-
-
-
-
-# Test 24
-S24====
-0x0b1001
-E24====
-
-
-
-
-# Test 25
-S25====
-0b1001a
-E25====
-
-
-
-
-# Test 26
-S26====
-0b11111111111111111111111111111110
-E26====
-
-
-
-ENDTEST
-
diff --git a/src/testdir/test_increment.ok b/src/testdir/test_increment.ok
deleted file mode 100644
index 77ce9d4..0000000
--- a/src/testdir/test_increment.ok
+++ /dev/null
@@ -1,340 +0,0 @@
-# Test 1
-S1======
-foobar-10
-E1======
-
-foobar-9
-foobar-9
-foobar-11
-foobar-11
-foobar-9
-
-
-# Test 2
-S2=====
-10
-20
-30
-40
-E2=====
-
-11
-21
-31
-41
-
-9
-19
-29
-39
-
-# Test 3
-S3=====
-10
-
-20
-
-30
-
-40
-E3=====
-
-12
-
-24
-
-36
-
-48
-
-8
-
-16
-
-24
-
-32
-
-# Test 4
-S4=====
-foobar-10
-E4=====
-
-foobar-10
-
-
-# Test 5
-S5====
-a
-a
-a
-a
-E5====
-
-b
-c
-d
-e
-
-# Test 6
-S6====
-z
-z
-z
-z
-E6====
-
-y
-x
-w
-v
-
-
-# Test 7
-S7====
-2
-1
-0
--1
--2
-E7====
-
-3
-2
-1
-0
--1
-
-1
-0
--1
--2
--3
-
-# Test 8
-S8====
-0x9
-0x9
-E8====
-
-0xa
-0xa
-
-0xa
-0xa
-
-
-# Test 9
-S9====
-2
-2
-
-3
-3
-
-E9====
-
-4
-4
-
-5
-5
-
-
-
-
-# Test 10
-S10====
-1
-1
-1
-1
-E10====
-
-0
--1
--2
--3
-
-
-
-# Test 11
-S11====
-    1
-1
-    1
-    1
-E11====
-
-    2
-1
-    3
-    4
-
-
-# Test 12
-S12====
-0 0
-0 0
-0 0
-E12====
-
-0 1
-1 0
-1 0
-
-
-# Test 13
-S13====
-max: 100px
-max: 200px
-max: 300px
-max: 400px
-E13====
-
-max: 110px
-max: 210px
-max: 310px
-max: 400px
-
-max: 90px
-max: 190px
-max: 290px
-max: 400px
-
-# Test 14
-S14====
-1 1
-1 1
-E14====
-
-2 2
-2 2
-
-
-# Test 15
-S15====
-101
-E15====
-
-111
-
-
-# Test 16
-S16====
-   1
-  19
- 119
-E16====
-
-   2
-  20
- 120
-
-
-# Test 17
-S17====
- 100
- 1
-
- 100
- 1
-E17====
-
- 101
- 2
-
- 101
- 1
-
-# Test 18
-S18====
-0
-0
-0
-0
-E18====
-
-3
-6
-9
-12
-
-
-# Test 19
-S19====
-1
-1a
-E19====
-
-2
-2a
-
-
-# Test 20
-S20====
-a
-E20====
-
-b
-1
-
-
-# Test 21
-S21====
-0x123456
-E21====
-
-0x124456
-
-
-# Test 22
-S22====
-0b1
-0b1
-E22====
-
-0b10
-0b10
-
-0b10
-0b10
-
-
-# Test 23
-S23====
-0b1001
-E23====
-
-0b1011
-
-
-
-# Test 24
-S24====
-0x0b1001
-E24====
-
-0x0b1002
-
-
-
-# Test 25
-S25====
-0b1001a
-E25====
-
-0b1010a
-
-
-
-# Test 26
-S26====
-0b11111111111111111111111111111110
-E26====
-
-0b11111111111111111111111111111111
-
-
-ENDTEST
-
diff --git a/src/testdir/test_increment.vim b/src/testdir/test_increment.vim
new file mode 100644
index 0000000..56777df
--- /dev/null
+++ b/src/testdir/test_increment.vim
@@ -0,0 +1,383 @@
+" Tests for using Ctrl-A/Ctrl-X on visual selections
+
+func SetUp()
+  new dummy
+  set nrformats&vim
+endfunc
+
+func TearDown()
+  bwipe!
+endfunc
+
+" Ctrl-A on visually selected number
+func Test_visual_increment_01()
+  call setline(1, repeat(["foobaar-10"], 5))
+
+  call cursor(1, 1)
+  exec "norm! \<C-A>"
+  call assert_equal("foobaar-9", getline('.'))
+  call assert_equal([0, 1, 9, 0], getpos('.'))
+
+  call cursor(2, 1)
+  exec "norm! f-v$\<C-A>"
+  call assert_equal("foobaar-9", getline('.'))
+  call assert_equal([0, 2, 8, 0], getpos('.'))
+
+  call cursor(3, 1)
+  exec "norm! f1v$\<C-A>"
+  call assert_equal("foobaar-11", getline('.'))
+  call assert_equal([0, 3, 9, 0], getpos('.'))
+
+  call cursor(4, 1)
+  exec "norm! f-v$\<C-X>"
+  call assert_equal("foobaar-11", getline('.'))
+  call assert_equal([0, 4, 8, 0], getpos('.'))
+
+  call cursor(5, 1)
+  exec "norm! f1v$\<C-X>"
+  call assert_equal("foobaar-9", getline('.'))
+  call assert_equal([0, 5, 9, 0], getpos('.'))
+endfunc
+
+" Ctrl-A on visually selected lines
+func Test_visual_increment_02()
+  call setline(1, ["10", "20", "30", "40"])
+  exec "norm! GV3k$\<C-A>"
+  call assert_equal(["11", "21", "31", "41"], getline(1, '$'))
+  call assert_equal([0, 1, 1, 0], getpos('.'))
+
+  call setline(1, ["10", "20", "30", "40"])
+  exec "norm! GV3k$\<C-X>"
+  call assert_equal(["9", "19", "29", "39"], getline(1, '$'))
+  call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" g Ctrl-A on visually selected lines, with non-numbers in between
+func Test_visual_increment_03()
+  call setline(1, ["10", "", "20", "", "30", "", "40"])
+  exec "norm! GV6k2g\<C-A>"
+  call assert_equal(["12", "", "24", "", "36", "", "48"], getline(1, '$'))
+  call assert_equal([0, 1, 1, 0], getpos('.'))
+
+  call setline(1, ["10", "", "20", "", "30", "", "40"])
+  exec "norm! GV6k2g\<C-X>"
+  call assert_equal(["8", "", "16", "", "24", "", "32"], getline(1, '$'))
+  call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" Ctrl-A on non-number
+func Test_visual_increment_04()
+  call setline(1, ["foobar-10"])
+  exec "norm! vf-\<C-A>"
+  call assert_equal(["foobar-10"], getline(1, '$'))
+  call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" g<Ctrl-A> on letter
+func Test_visual_increment_05()
+  set nrformats+=alpha
+  call setline(1, repeat(["a"], 4))
+  exec "norm! GV3kg\<C-A>"
+  call assert_equal(["b", "c", "d", "e"], getline(1, '$'))
+  call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" g<Ctrl-X> on letter
+func Test_visual_increment_06()
+  set nrformats+=alpha
+  call setline(1, repeat(["z"], 4))
+  exec "norm! GV3kg\<C-X>"
+  call assert_equal(["y", "x", "w", "v"], getline(1, '$'))
+  call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" <Ctrl-A> on letter
+func Test_visual_increment_07()
+  call setline(1, ["2", "1", "0", "-1", "-2"])
+  exec "norm! GV4k\<C-A>"
+  call assert_equal(["3", "2", "1", "0", "-1"], getline(1, '$'))
+  call assert_equal([0, 1, 1, 0], getpos('.'))
+
+  call setline(1, ["2", "1", "0", "-1", "-2"])
+  exec "norm! GV4k\<C-X>"
+  call assert_equal(["1", "0", "-1", "-2", "-3"], getline(1, '$'))
+  call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" Block increment on 0x9
+func Test_visual_increment_08()
+  call setline(1, repeat(["0x9"], 2))
+  exec "norm! \<C-V>j$\<C-A>"
+  call assert_equal(["0xa", "0xa"], getline(1, '$'))
+  call assert_equal([0, 1, 1, 0], getpos('.'))
+
+  call setline(1, repeat(["0x9"], 2))
+  exec "norm! gg$\<C-V>+\<C-A>"
+  call assert_equal(["0xa", "0xa"], getline(1, '$'))
+  call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" Increment and redo
+func Test_visual_increment_09()
+  call setline(1, ["2", "2", "", "3", "3", ""])
+  exec "norm! ggVj2\<C-A>3j."
+  call assert_equal(["4", "4", "", "5", "5", ""], getline(1, '$'))
+  call assert_equal([0, 4, 1, 0], getpos('.'))
+endfunc
+
+" sequentially decrement 1
+func Test_visual_increment_10()
+  call setline(1, repeat(["1"], 4))
+  exec "norm! GV3kg\<C-X>"
+  call assert_equal(["0", "-1", "-2", "-3"], getline(1, '$'))
+  call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" visually block selected indented lines
+func Test_visual_increment_11()
+  call setline(1, ["    1", "1", "    1", "    1"])
+  exec "norm! f1\<C-V>3jg\<C-A>"
+  call assert_equal(["    2", "1", "    3", "    4"], getline(1, '$'))
+  call assert_equal([0, 1, 5, 0], getpos('.'))
+endfunc
+
+" visually selected several columns
+func Test_visual_increment_12()
+  call setline(1, repeat(["0 0"], 3))
+  exec "norm! $v++\<C-A>"
+  call assert_equal(["0 1", "1 0", "1 0"], getline(1, '$'))
+  call assert_equal([0, 1, 3, 0], getpos('.'))
+endfunc
+
+" visually selected part of columns
+func Test_visual_increment_13()
+  call setline(1, ["max: 100px", "max: 200px", "max: 300px", "max: 400px"])
+  exec "norm! f1\<C-V>l2j\<C-A>"
+  call assert_equal(["max: 110px", "max: 210px", "max: 310px", "max: 400px"], getline(1, '$'))
+  call assert_equal([0, 1, 6, 0], getpos('.'))
+
+  call setline(1, ["max: 100px", "max: 200px", "max: 300px", "max: 400px"])
+  exec "norm! ggf1\<C-V>l2j\<C-X>"
+  call assert_equal(["max: 90px", "max: 190px", "max: 290px", "max: 400px"], getline(1, '$'))
+  call assert_equal([0, 1, 6, 0], getpos('.'))
+endfunc
+
+" redo in block mode
+func Test_visual_increment_14()
+  call setline(1, repeat(["1 1"], 2))
+  exec "norm! G\<C-V>k\<C-A>w."
+  call assert_equal(["2 2", "2 2"], getline(1, '$'))
+  call assert_equal([0, 1, 3, 0], getpos('.'))
+endfunc
+
+" block select single numbers
+func Test_visual_increment_15()
+  call setline(1, ["101"])
+  exec "norm! lv\<C-A>"
+  call assert_equal(["111"], getline(1, '$'))
+  call assert_equal([0, 1, 2, 0], getpos('.'))
+endfunc
+
+" increment right aligned numbers
+func Test_visual_increment_16()
+  call setline(1, ["   1", "  19", " 119"])
+  exec "norm! VG\<C-A>"
+  call assert_equal(["   2", "  20", " 120"], getline(1, '$'))
+  call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" block-wise increment and redo
+func Test_visual_increment_17()
+  call setline(1, [" 100", " 1", "", " 100", " 1"])
+  exec "norm! \<C-V>j$\<C-A>2j."
+  call assert_equal([" 101", " 2", "", " 101", " 1"], getline(1, '$'))
+  call assert_equal([0, 3, 1, 0], getpos('.'))
+endfunc
+
+" repeat of g<Ctrl-a>
+func Test_visual_increment_18()
+  call setline(1, repeat(["0"], 4))
+  exec "norm! GV3kg\<C-A>"
+  exec "norm! .."
+  call assert_equal(["3", "6", "9", "12"], getline(1, '$'))
+  call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" increment on number with nrformat including alpha
+func Test_visual_increment_19()
+  set nrformats+=alpha
+  call setline(1, ["1", "1a"])
+  exec "norm! \<C-V>G$\<C-A>"
+  call assert_equal(["2", "2a"], getline(1, '$'))
+  call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" increment a single letter
+func Test_visual_increment_20()
+  set nrformats+=alpha
+  call setline(1, ["a"])
+  exec "norm! \<C-A>"
+  call assert_equal(["b"], getline(1, '$'))
+  call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" block-wise increment on part of hexadecimal
+func Test_visual_increment_21()
+  call setline(1, ["0x123456"])
+  exec "norm! \<C-V>f3\<C-A>"
+  call assert_equal(["0x124456"], getline(1, '$'))
+  call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" block increment on 0b0
+func Test_visual_increment_22()
+  call setline(1, repeat(["0b1"], 2))
+  exec "norm! \<C-V>j$\<C-A>"
+  call assert_equal(repeat(["0b10"], 2), getline(1, '$'))
+  call assert_equal([0, 1, 1, 0], getpos('.'))
+
+  call setline(1, repeat(["0b1"], 2))
+  exec "norm! $\<C-V>+\<C-A>"
+  call assert_equal(repeat(["0b10"], 2), getline(1, '$'))
+  call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" block-wise increment on part of binary
+func Test_visual_increment_23()
+  call setline(1, ["0b1001"])
+  exec "norm! \<C-V>4l\<C-A>"
+  call assert_equal(["0b1011"], getline(1, '$'))
+  call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" increment hexadecimal
+func Test_visual_increment_24()
+  call setline(1, ["0x0b1001"])
+  exec "norm! \<C-V>$\<C-A>"
+  call assert_equal(["0x0b1002"], getline(1, '$'))
+  call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" increment binary with nrformats including alpha
+func Test_visual_increment_25()
+  set nrformats+=alpha
+  call setline(1, ["0b1001a"])
+  exec "norm! \<C-V>$\<C-A>"
+  call assert_equal(["0b1010a"], getline(1, '$'))
+  call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" increment binary with 64 bits
+func Test_visual_increment_26()
+  set nrformats+=alpha
+  call setline(1, ["0b11111111111111111111111111111110"])
+  exec "norm! \<C-V>$\<C-A>"
+  call assert_equal(["0b11111111111111111111111111111111"], getline(1, '$'))
+  call assert_equal([0, 1, 1, 0], getpos('.'))
+endfunc
+
+" Tab code and linewise-visual inc/dec
+func Test_visual_increment_27()
+  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_28()
+  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_29()
+  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_30()
+  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_31()
+  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_32()
+  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_33()
+  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_34()
+  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_35()
+"  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, 8, 0], getpos('.'))
+"
+"  exec "norm! ..."
+"  call assert_equal(["           123", "\<TAB>856789"], getline(1, '$'))
+"  call assert_equal([0, 1, 8, 0], getpos('.'))
+"endfunc
+
+" vim: tabstop=2 shiftwidth=2 expandtab
diff --git a/src/vim.h b/src/vim.h
index 1a176be..7e44d73 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_ADD		28	/* "<C-A>" Add to the number or alphabetic
+				   character */
+#define OP_SUBTRACT	29	/* "<C-C>" Subtract to the number or alphabetic
+				   character */
 
 /*
  * Motion types, used for operators and for yank/delete registers.

Raspunde prin e-mail lui