diff options
author | watiko <service@mail.watiko.net> | 2016-01-15 21:04:06 +0900 |
---|---|---|
committer | watiko <service@mail.watiko.net> | 2016-02-01 03:47:09 +0900 |
commit | 8f212568aa5083a77b3617f2cef5b438f3d90e42 (patch) | |
tree | 3b0181cf8069fb4e94e1d5f8156cd8e1494d2a5d /src/nvim/ops.c | |
parent | 3a94e06abbcc0dfff658b626891ec308f7582180 (diff) | |
download | rneovim-8f212568aa5083a77b3617f2cef5b438f3d90e42.tar.gz rneovim-8f212568aa5083a77b3617f2cef5b438f3d90e42.tar.bz2 rneovim-8f212568aa5083a77b3617f2cef5b438f3d90e42.zip |
vim-patch:7.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)
https://github.com/vim/vim/commit/d79e55016cf8268cee935f1ac3b5b28712d1399e
Diffstat (limited to 'src/nvim/ops.c')
-rw-r--r-- | src/nvim/ops.c | 608 |
1 files changed, 320 insertions, 288 deletions
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; } /* |