diff options
-rw-r--r-- | src/nvim/normal.c | 82 | ||||
-rw-r--r-- | src/nvim/ops.c | 608 | ||||
-rw-r--r-- | src/nvim/ops.h | 4 | ||||
-rw-r--r-- | src/nvim/testdir/test_increment.vim | 110 | ||||
-rw-r--r-- | src/nvim/version.c | 2 |
5 files changed, 462 insertions, 344 deletions
diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 062461c9f5..af3f747195 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -1414,11 +1414,12 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) int lbr_saved = curwin->w_p_lbr; - /* The visual area is remembered for redo */ - static int redo_VIsual_mode = NUL; /* 'v', 'V', or Ctrl-V */ - 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 */ + // The visual area is remembered for redo + static int redo_VIsual_mode = NUL; // 'v', 'V', or Ctrl-V + 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 bool include_line_break = false; old_cursor = curwin->w_cursor; @@ -1656,6 +1657,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool 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; } } @@ -1990,6 +1992,20 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) deleteFold(oap->start.lnum, oap->end.lnum, oap->op_type == OP_FOLDDELREC, oap->is_VIsual); break; + + case OP_NR_ADD: + case OP_NR_SUB: + if (empty_region_error) { + vim_beep(BO_OPER); + CancelRedo(); + } else { + VIsual_active = true; + curwin->w_p_lbr = lbr_saved; + op_addsub(oap, cap->count1, redo_VIsual_arg); + VIsual_active = false; + } + check_cursor_col(); + break; default: clearopbeep(oap); } @@ -3022,34 +3038,6 @@ size_t find_ident_at_pos(win_T *wp, linenr_T lnum, colnr_T startcol, return (size_t)col; } -// Add commands to reselect Visual mode into the redo buffer. -static void prep_redo_visual(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. */ @@ -3534,27 +3522,14 @@ static void nv_help(cmdarg_T *cap) */ static void nv_addsub(cmdarg_T *cap) { - bool visual = VIsual_active; - - if (cap->oap->op_type == OP_NOP - && do_addsub((int)cap->cmdchar, cap->count1, cap->arg) == OK) { - if (visual) { - prep_redo_visual(cap); - if (cap->arg) { - AppendCharToRedobuff('g'); - } - AppendCharToRedobuff(cap->cmdchar); - } else { - prep_redo_cmd(cap); - } + if (!VIsual_active && cap->oap->op_type == OP_NOP) { + 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); } } @@ -6383,6 +6358,7 @@ static void nv_g_cmd(cmdarg_T *cap) if (VIsual_active) { cap->arg = true; cap->cmdchar = cap->nchar; + cap->nchar = NUL; nv_addsub(cap); } else { clearopbeep(oap); diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 8887b3ae91..b08a5056e4 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -115,6 +115,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 }; /* @@ -125,13 +127,27 @@ int get_op_type(int char1, int char2) { int i; - if (char1 == 'r') /* ignore second character */ + if (char1 == 'r') { + // ignore second character return OP_REPLACE; - if (char1 == '~') /* when tilde is an operator */ + } + if (char1 == '~') { + // when tilde is an operator return OP_TILDE; - for (i = 0;; i++) - if (opchars[i][0] == char1 && opchars[i][1] == char2) + } + 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; + } + } return i; } @@ -4181,14 +4197,115 @@ static void block_prep(oparg_T *oap, struct block_def *bdp, linenr_T lnum, int i bdp->textstart = pstart; } +/// Handle the add/subtract operator. +/// +/// @param[in] oap Arguments of operator. +/// @param[in] Prenum1 Amount of addition or subtraction. +/// @param[in] g_cmd Prefixed with `g`. +void op_addsub(oparg_T *oap, linenr_T Prenum1, bool g_cmd) +{ + pos_T pos; + struct block_def bd; + ssize_t 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->motion_type == MBLOCK) { + // 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++; + } + + 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 *)_("%" PRId64 " lines changed"), (int64_t)change_cnt); + } + } + } +} + /// Add or subtract from a number in a line. /// -/// @param command CTRL-A for add, CTRL-X for subtract -/// @param Prenum1 number to add or subtract -/// @param g_cmd Prefixed with `g`. +/// @param op_type OP_NR_ADD or OP_NR_SUB. +/// @param pos Cursor position. +/// @param length Target number length. +/// @param Prenum1 Amount of addition or subtraction. /// -/// @return FAIL for failure, OK otherwise -int do_addsub(int command, linenr_T Prenum1, bool g_cmd) +/// @return true if some character was changed. +int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) { int col; char_u *buf1; @@ -4196,11 +4313,9 @@ int do_addsub(int command, linenr_T Prenum1, bool g_cmd) int pre; // 'X' or 'x': hex; '0': octal; 'B' or 'b': bin static bool hexupper = false; // 0xABC unsigned long n; - unsigned long offset = 0; unsigned long oldn; char_u *ptr; int c; - int length = 0; // character length of the number int todel; bool dohex; bool dooct; @@ -4211,9 +4326,6 @@ int do_addsub(int command, linenr_T Prenum1, bool g_cmd) bool negative = false; bool was_positive = true; bool visual = VIsual_active; - int lnum = curwin->w_cursor.lnum; - int lnume = curwin->w_cursor.lnum; - int startcol = 0; bool did_change = false; pos_T t = curwin->w_cursor; int maxlen = 0; @@ -4225,44 +4337,16 @@ int do_addsub(int command, linenr_T Prenum1, bool g_cmd) dobin = (vim_strchr(curbuf->b_p_nf, 'b') != NULL); // "Bin" doalp = (vim_strchr(curbuf->b_p_nf, 'p') != NULL); // "alPha" - // 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 = 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; + curwin->w_cursor = *pos; + ptr = ml_get(pos->lnum); + col = pos->col; - lnum = VIsual.lnum; - lnume = curwin->w_cursor.lnum; - } else { - ptr = get_cursor_line_ptr(); + if (*ptr == NUL) { + goto theend; + } + // First check if we are on a hexadecimal number, after the "0x". + if (!VIsual_active) { if (dobin) { while (col > 0 && ascii_isbdigit(ptr[col])) { col--; @@ -4306,7 +4390,7 @@ int do_addsub(int command, linenr_T Prenum1, bool g_cmd) col--; } else { // Search forward and then backward to find the start of number. - col = curwin->w_cursor.col; + col = pos->col; while (ptr[col] != NUL && !ascii_isdigit(ptr[col]) @@ -4322,279 +4406,227 @@ int do_addsub(int command, linenr_T Prenum1, bool g_cmd) } } - for (int i = lnum; i <= lnume; i++) { - colnr_T stop = 0; - - t = curwin->w_cursor; - curwin->w_cursor.lnum = i; - ptr = get_cursor_line_ptr(); - if ((int)STRLEN(ptr) <= col) { - // try again on next line - continue; + if (visual) { + while (ptr[col] != NUL && length > 0 && !ascii_isdigit(ptr[col]) && + !(doalp && ASCII_ISALPHA(ptr[col]))) { + col++; + length--; } - if (visual) { - 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; - } - - while (ptr[col] != NUL - && !ascii_isdigit(ptr[col]) - && !(doalp && ASCII_ISALPHA(ptr[col]))) { - if (col > 0 && col == stop) { - break; - } - col++; - } - if (col > startcol && ptr[col - 1] == '-') { - negative = true; - was_positive = false; - } + if (length == 0) { + goto theend; } - // If a number was found, and saving for undo works, replace the number. - firstdigit = ptr[col]; - if ((!ascii_isdigit(firstdigit) && !(doalp && ASCII_ISALPHA(firstdigit))) - || u_save_cursor() != OK) { - if (lnum < lnume) { - if (visual && VIsual_mode != Ctrl_V) { - col = 0; - } else { - col = startcol; - } - // Try again on next line - continue; - } - beep_flush(); - return FAIL; + + if (col > pos->col && ptr[col - 1] == '-') { + negative = true; + was_positive = false; } + } - if (doalp && ASCII_ISALPHA(firstdigit)) { - // decrement or increment alphabetic character - if (command == Ctrl_X) { - if (CharOrd(firstdigit) < Prenum1) { - if (isupper(firstdigit)) { - firstdigit = 'A'; - } else { - firstdigit = 'a'; - } + // If a number was found, and saving for undo works, replace the number. + firstdigit = ptr[col]; + if (!ascii_isdigit(firstdigit) && !(doalp && ASCII_ISALPHA(firstdigit))) { + beep_flush(); + goto theend; + } + + if (doalp && ASCII_ISALPHA(firstdigit)) { + // decrement or increment alphabetic character + if (op_type == OP_NR_SUB) { + if (CharOrd(firstdigit) < Prenum1) { + if (isupper(firstdigit)) { + firstdigit = 'A'; } else { - firstdigit -= Prenum1; + firstdigit = 'a'; } } else { - if (26 - CharOrd(firstdigit) - 1 < Prenum1) { - if (isupper(firstdigit)) { - firstdigit = 'Z'; - } else { - firstdigit = 'z'; - } - } else { - firstdigit += Prenum1; - } + firstdigit -= Prenum1; } - 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); + if (26 - CharOrd(firstdigit) - 1 < Prenum1) { + if (isupper(firstdigit)) { + firstdigit = 'Z'; + } else { + firstdigit = 'z'; } + } else { + firstdigit += Prenum1; } + } + 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; + } - vim_str2nr(ptr + col, &pre, &length, - 0 + (dobin ? STR2NR_BIN : 0) - + (dooct ? STR2NR_OCT : 0) - + (dohex ? STR2NR_HEX : 0), - NULL, &n, maxlen); + // get the number value (unsigned) + if (visual && VIsual_mode != 'V') { + maxlen = (curbuf->b_visual.vi_curswant == MAXCOL + ? (int)STRLEN(ptr) - col + : length); + } - // ignore leading '-' for hex, 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); + + // ignore leading '-' for hex, octal and bin numbers + if (pre && negative) { + col++; + length--; + negative = false; + } - // add or subtract - subtract = false; - if (command == Ctrl_X) { - subtract ^= true; - } - if (negative) { - subtract ^= true; - } + // add or subtract + subtract = false; + if (op_type == OP_NR_SUB) { + subtract ^= true; + } + if (negative) { + subtract ^= true; + } - oldn = n; + oldn = n; - n = subtract ? n - (unsigned long) Prenum1 - : n + (unsigned long) Prenum1; + n = subtract ? n - (unsigned long) Prenum1 + : 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 { - // add - if (n < oldn) { - n = (n ^ (unsigned long)-1); - negative ^= true; - } + // handle wraparound for decimal numbers + if (!pre) { + if (subtract) { + if (n > oldn) { + n = 1 + (n ^ (unsigned long)-1); + negative ^= true; } - if (n == 0) { - negative = false; + } else { + // add + if (n < oldn) { + n = (n ^ (unsigned long)-1); + negative ^= true; } } - - if (visual && !was_positive && !negative && col > 0) { - // need to remove the '-' - col--; - length++; + if (n == 0) { + negative = false; } + } - // Delete the old number. - curwin->w_cursor.col = col; - if (!did_change) { - startpos = curwin->w_cursor; - } - did_change = true; - todel = length; - c = gchar_cursor(); + if (visual && !was_positive && !negative && col > 0) { + // need to remove the '-' + col--; + length++; + } - // 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; - } + // 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)) { + if (isupper(c)) { + hexupper = true; + } else { + hexupper = false; } - // del_char() will mark line needing displaying - (void)del_char(false); - c = gchar_cursor(); } + // del_char() will mark line needing displaying + (void)del_char(false); + c = gchar_cursor(); + } - // Prepare the leading characters in buf1[]. - // When there are many leading zeros it could be very long. - // Allocate a bit too much. - buf1 = xmalloc(length + NUMBUFLEN); - 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--; - } + // Prepare the leading characters in buf1[]. + // When there are many leading zeros it could be very long. + // Allocate a bit too much. + buf1 = xmalloc(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--; + } - // Put the number characters in buf2[]. - if (pre == 'b' || pre == 'B') { - size_t bits = 0; - size_t pos = 0; + // Put the number characters in buf2[]. + if (pre == 'b' || pre == 'B') { + size_t bits = 0; + size_t i = 0; - // leading zeros - for (bits = 8 * sizeof(n); bits > 0; bits--) { - if ((n >> (bits - 1)) & 0x1) { - break; - } - } + // leading zeros + for (bits = 8 * sizeof(n); bits > 0; bits--) { + if ((n >> (bits - 1)) & 0x1) { + break; + } + } - while (bits > 0) { - buf2[pos++] = ((n >> --bits) & 0x1) ? '1' : '0'; - } + while (bits > 0) { + buf2[i++] = ((n >> --bits) & 0x1) ? '1' : '0'; + } - buf2[pos] = '\0'; + buf2[i] = '\0'; - } else if (pre == 0) { - vim_snprintf((char *)buf2, ARRAY_SIZE(buf2), "%" PRIu64, (uint64_t)n); - } else if (pre == '0') { - vim_snprintf((char *)buf2, ARRAY_SIZE(buf2), "%" PRIo64, (uint64_t)n); - } else if (pre && hexupper) { - vim_snprintf((char *)buf2, ARRAY_SIZE(buf2), "%" PRIX64, (uint64_t)n); - } else { - vim_snprintf((char *)buf2, ARRAY_SIZE(buf2), "%" PRIx64, (uint64_t)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 - xfree(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--; - } + } else if (pre == 0) { + vim_snprintf((char *)buf2, ARRAY_SIZE(buf2), "%" PRIu64, (uint64_t)n); + } else if (pre == '0') { + vim_snprintf((char *)buf2, ARRAY_SIZE(buf2), "%" PRIo64, (uint64_t)n); + } else if (pre && hexupper) { + vim_snprintf((char *)buf2, ARRAY_SIZE(buf2), "%" PRIX64, (uint64_t)n); + } else { + vim_snprintf((char *)buf2, ARRAY_SIZE(buf2), "%" PRIx64, (uint64_t)n); } - - if (g_cmd) { - offset = (unsigned long)Prenum1; - g_cmd = 0; + 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'; + } } - // reset - subtract = false; - negative = false; - was_positive = true; - if (visual && VIsual_mode == Ctrl_V) { - col = startcol; - } else { - col = 0; + *ptr = NUL; + STRCAT(buf1, buf2); + ins_str(buf1); // insert the new number + xfree(buf1); + endpos = curwin->w_cursor; + if (did_change && curwin->w_cursor.col) { + curwin->w_cursor.col--; } - Prenum1 += offset; - curwin->w_set_curswant = true; } + +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 @@ -4604,7 +4636,7 @@ int do_addsub(int command, linenr_T Prenum1, bool g_cmd) curbuf->b_op_end.col--; } } - return OK; + return did_change; } /* diff --git a/src/nvim/ops.h b/src/nvim/ops.h index 507f933acf..81783232c5 100644 --- a/src/nvim/ops.h +++ b/src/nvim/ops.h @@ -66,6 +66,10 @@ typedef int (*Indenter)(void); #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 /// Flags for get_reg_contents(). enum GRegFlags { diff --git a/src/nvim/testdir/test_increment.vim b/src/nvim/testdir/test_increment.vim index 51cc45f98d..e4f67eacad 100644 --- a/src/nvim/testdir/test_increment.vim +++ b/src/nvim/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/nvim/version.c b/src/nvim/version.c index 516253cc08..68165363ca 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -73,6 +73,8 @@ static int included_patches[] = { + 1087, + // 1086, 1085, 1084, // 1083, |