diff options
author | Bram Moolenaar <Bram@vim.org> | 2016-01-10 22:13:02 +0100 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2016-01-10 22:13:02 +0100 |
commit | d79e55016cf8268cee935f1ac3b5b28712d1399e (patch) | |
tree | c1651d0b492ac78594a39e5f6f8bc17e4c6780e3 | |
parent | 507edf63df75fe228e0f76b845b58d60266e65d8 (diff) | |
download | vim-git-7.4.1087.tar.gz |
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.c | 87 | ||||
-rw-r--r-- | src/ops.c | 663 | ||||
-rw-r--r-- | src/proto/ops.pro | 2 | ||||
-rw-r--r-- | src/testdir/test_increment.vim | 110 | ||||
-rw-r--r-- | src/version.c | 2 | ||||
-rw-r--r-- | src/vim.h | 4 |
6 files changed, 487 insertions, 381 deletions
diff --git a/src/normal.c b/src/normal.c index d513f7516..810aabfa0 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 @@ -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 aaffa0202..27e0f118a 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 51cc45f98..e4f67eaca 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 b753f174e..db72d0596 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, @@ -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. |