]> granicus.if.org Git - vim/commitdiff
patch 7.4.1087 v7.4.1087
authorBram Moolenaar <Bram@vim.org>
Sun, 10 Jan 2016 21:13:02 +0000 (22:13 +0100)
committerBram Moolenaar <Bram@vim.org>
Sun, 10 Jan 2016 21:13:02 +0000 (22:13 +0100)
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)

src/normal.c
src/ops.c
src/proto/ops.pro
src/testdir/test_increment.vim
src/version.c
src/vim.h

index d513f751626f3da40f8d9b65034f4fdd90e61848..810aabfa00733ed0cfa6bdb72f01ba9471183f7c 100644 (file)
@@ -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);
        }
@@ -3602,43 +3621,6 @@ find_ident_at_pos(wp, lnum, startcol, string, find_type)
     return col;
 }
 
-/*
- * 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.
  */
@@ -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
index 2dcdb778a37bf718a094cb2364059e5800691799..d28589305837f45af22bfaaa2351868333667ca1 100644 (file)
--- 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
index aaffa020258b2b9b79fc9d1fd500a3bbedf51058..27e0f118aa68edf473c79c97ff746ba35fdc8d46 100644 (file)
@@ -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));
index 51cc45f98d643ccdc9cd3afe52a3c32a18a7a440..e4f67eacadb71f1628afcbe5f6f1b33923b571d2 100644 (file)
@@ -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))
index b753f174ed8db263ed8a41813ba4022d99f111dc..db72d0596a6eb3360df4e183f3ea4a9a843350e8 100644 (file)
@@ -741,6 +741,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1087,
 /**/
     1086,
 /**/
index fd0b0b0dc1b0af78709436b85fa15c7c6c409224..81d09291167a9e126e2ee31e1a4eae5c1d531e40 100644 (file)
--- 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.