diff options
author | watiko <service@mail.watiko.net> | 2016-01-14 17:06:55 +0900 |
---|---|---|
committer | watiko <service@mail.watiko.net> | 2016-02-01 03:43:36 +0900 |
commit | 4d074e39ea1228e4f04c70ecfe4e1196a9638176 (patch) | |
tree | fc56179f5b08eac3233d961c79e5b2ee49f2f577 | |
parent | 8f22031708b351ec5bb73952e6afc39b07a72ae2 (diff) | |
download | rneovim-4d074e39ea1228e4f04c70ecfe4e1196a9638176.tar.gz rneovim-4d074e39ea1228e4f04c70ecfe4e1196a9638176.tar.bz2 rneovim-4d074e39ea1228e4f04c70ecfe4e1196a9638176.zip |
vim-patch:7.4.754
Problem: Using CTRL-A in Visual mode does not work well. (Gary Johnson)
Solution: Make it increment all numbers in the Visual area. (Christian
Brabandt)
https://github.com/vim/vim/commit/3a304b23823b089e499063e8211c5695d049f3ba
-rw-r--r-- | src/nvim/normal.c | 28 | ||||
-rw-r--r-- | src/nvim/ops.c | 450 | ||||
-rw-r--r-- | src/nvim/testdir/Makefile | 3 | ||||
-rw-r--r-- | src/nvim/testdir/test_increment.in | 143 | ||||
-rw-r--r-- | src/nvim/testdir/test_increment.ok | 66 | ||||
-rw-r--r-- | src/nvim/version.c | 2 |
6 files changed, 485 insertions, 207 deletions
diff --git a/src/nvim/normal.c b/src/nvim/normal.c index a116b5a0bd..684467d26a 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -3503,9 +3503,17 @@ static void nv_help(cmdarg_T *cap) */ static void nv_addsub(cmdarg_T *cap) { - if (!checkclearopq(cap->oap) - && do_addsub(cap->cmdchar, cap->count1)) + bool visual = VIsual_active; + if (cap->oap->op_type == OP_NOP + && do_addsub((int)cap->cmdchar, cap->count1, cap->arg) == OK) { prep_redo_cmd(cap); + } else { + clearopbeep(cap->oap); + } + if (visual) { + VIsual_active = false; + redraw_later(CLEAR); + } } /* @@ -6327,9 +6335,19 @@ static void nv_g_cmd(cmdarg_T *cap) bool flag = false; switch (cap->nchar) { - /* - * "gR": Enter virtual replace mode. - */ + // "g^A/g^X": Sequentially increment visually selected region. + case Ctrl_A: + case Ctrl_X: + if (VIsual_active) { + cap->arg = true; + cap->cmdchar = cap->nchar; + nv_addsub(cap); + } else { + clearopbeep(oap); + } + break; + + // "gR": Enter virtual replace mode. case 'R': cap->arg = true; nv_Replace(cap); diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 19dbd0f9f6..af738d3fa9 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -4201,272 +4201,322 @@ static void reverse_line(char_u *s) /// 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 Prenum1 number to add or subtract +/// @param g_cmd Prefixed with `g`. /// /// @return FAIL for failure, OK otherwise -int do_addsub(int command, linenr_T Prenum1) +int do_addsub(int command, linenr_T Prenum1, bool g_cmd) { int col; char_u *buf1; char_u buf2[NUMBUFLEN]; - int pre; // 'X' or 'x': hex; '0': octal; 'B' or 'b': bin - static int hexupper = false; // 0xABC - unsigned long n, oldn; + int pre; // 'X' or 'x': hex; '0': octal; 'B' or 'b': bin + static bool hexupper = false; // 0xABC + unsigned long n; + long offset = 0; + unsigned long oldn; char_u *ptr; int c; - int length = 0; // character length of the number + int length = 0; // character length of the number int todel; int dohex; int dooct; int dobin; int doalp; int firstdigit; - int negative; - int subtract; + bool subtract; + bool negative = false; + bool visual = VIsual_active; + int lnum = curwin->w_cursor.lnum; + int lnume = curwin->w_cursor.lnum; dohex = (vim_strchr(curbuf->b_p_nf, 'x') != NULL); // "heX" dooct = (vim_strchr(curbuf->b_p_nf, 'o') != NULL); // "Octal" dobin = (vim_strchr(curbuf->b_p_nf, 'b') != NULL); // "Bin" doalp = (vim_strchr(curbuf->b_p_nf, 'p') != NULL); // "alPha" - ptr = get_cursor_line_ptr(); - RLADDSUBFIX(ptr); - // First check if we are on a hexadecimal number, after the "0x". col = curwin->w_cursor.col; - - if (dobin) { - while (col > 0 && ascii_isbdigit(ptr[col])) { - col--; + if (VIsual_active) { + if (lt(curwin->w_cursor, VIsual)) { + pos_T t = curwin->w_cursor; + curwin->w_cursor = VIsual; + VIsual = t; } - } + if (VIsual_mode == 'V') { + VIsual.col = 0; + } + + ptr = ml_get(VIsual.lnum); + RLADDSUBFIX(ptr); + + // 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; - if (dohex) { - while (col > 0 && ascii_isxdigit(ptr[col])) { - col--; + col = VIsual.col; + lnum = VIsual.lnum; + lnume = curwin->w_cursor.lnum; + if (ptr[col] == '-') { + negative = true; + col++; } - } - if (dobin - && dohex - && !((col > 0 - && (ptr[col] == 'X' || - ptr[col] == 'x') - && ptr[col - 1] == '0' - && ascii_isxdigit(ptr[col + 1])))) { - // In case of binary/hexadecimal pattern overlap match, rescan + } else { + ptr = get_cursor_line_ptr(); + RLADDSUBFIX(ptr); - col = curwin->w_cursor.col; + if (dobin) { + while (col > 0 && ascii_isbdigit(ptr[col])) { + col--; + } + } - while (col > 0 && ascii_isdigit(ptr[col])) { + if (dohex) { + while (col > 0 && ascii_isxdigit(ptr[col])) { col--; } - } + } + if (dobin + && dohex + && !((col > 0 + && (ptr[col] == 'X' || + ptr[col] == 'x') + && ptr[col - 1] == '0' + && ascii_isxdigit(ptr[col + 1])))) { + // In case of binary/hexadecimal pattern overlap match, rescan - if ((dohex - && col > 0 - && (ptr[col] == 'X' - || ptr[col] == 'x') - && ptr[col - 1] == '0' - && ascii_isxdigit(ptr[col + 1])) || - (dobin - && col > 0 - && (ptr[col] == 'B' - || ptr[col] == 'b') - && ptr[col - 1] == '0' - && ascii_isbdigit(ptr[col + 1]))) { - // Found hexadecimal or binary number, move to its start. - col--; - } else { - // Search forward and then backward to find the start of number. - col = curwin->w_cursor.col; + col = curwin->w_cursor.col; - while (ptr[col] != NUL - && !ascii_isdigit(ptr[col]) - && !(doalp && ASCII_ISALPHA(ptr[col]))) { - col++; + while (col > 0 && ascii_isdigit(ptr[col])) { + col--; + } } - while (col > 0 - && ascii_isdigit(ptr[col - 1]) - && !(doalp && ASCII_ISALPHA(ptr[col]))) { - col--; + if ((dohex + && col > 0 + && (ptr[col] == 'X' + || ptr[col] == 'x') + && ptr[col - 1] == '0' + && ascii_isxdigit(ptr[col + 1])) || + (dobin + && col > 0 + && (ptr[col] == 'B' + || ptr[col] == 'b') + && ptr[col - 1] == '0' + && ascii_isbdigit(ptr[col + 1]))) { + // Found hexadecimal or binary number, move to its start. + col--; + } else { + // Search forward and then backward to find the start of number. + col = curwin->w_cursor.col; + + while (ptr[col] != NUL + && !ascii_isdigit(ptr[col]) + && !(doalp && ASCII_ISALPHA(ptr[col]))) { + col++; + } + + while (col > 0 + && ascii_isdigit(ptr[col - 1]) + && !(doalp && ASCII_ISALPHA(ptr[col]))) { + col--; + } } } - // If a number was found, and saving for undo works, replace the number. - firstdigit = ptr[col]; - RLADDSUBFIX(ptr); - if ((!ascii_isdigit(firstdigit) && !(doalp && ASCII_ISALPHA(firstdigit))) - || u_save_cursor() != OK) { - beep_flush(); - return FAIL; - } + for (int i = lnum; i <= lnume; i++) { + curwin->w_cursor.lnum = i; + ptr = get_cursor_line_ptr(); + RLADDSUBFIX(ptr); + if ((int)STRLEN(ptr) <= col) { + col = 0; + } + // If a number was found, and saving for undo works, replace the number. + firstdigit = ptr[col]; + RLADDSUBFIX(ptr); + if ((!ascii_isdigit(firstdigit) && !(doalp && ASCII_ISALPHA(firstdigit))) + || u_save_cursor() != OK) { + if (lnum < lnume) { + // Try again on next line + continue; + } + beep_flush(); + return FAIL; + } - // get ptr again, because u_save() may have changed it - ptr = get_cursor_line_ptr(); - RLADDSUBFIX(ptr); + ptr = get_cursor_line_ptr(); + RLADDSUBFIX(ptr); - if (doalp && ASCII_ISALPHA(firstdigit)) { - // decrement or increment alphabetic character - if (command == Ctrl_X) { - if (CharOrd(firstdigit) < Prenum1) { - if (isupper(firstdigit)) { - firstdigit = 'A'; + 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'; + } } else { - firstdigit = 'a'; + firstdigit -= Prenum1; } } else { - firstdigit -= Prenum1; - } - } else { - if (26 - CharOrd(firstdigit) - 1 < Prenum1) { - if (isupper(firstdigit)) { - firstdigit = 'Z'; + if (26 - CharOrd(firstdigit) - 1 < Prenum1) { + if (isupper(firstdigit)) { + firstdigit = 'Z'; + } else { + firstdigit = 'z'; + } } else { - firstdigit = 'z'; + firstdigit += Prenum1; } - } else { - firstdigit += Prenum1; } - } - curwin->w_cursor.col = col; - (void)del_char(false); - ins_char(firstdigit); - } else { - negative = false; - if (col > 0 && ptr[col - 1] == '-') { // negative number - --col; - negative = true; - } + curwin->w_cursor.col = col; + (void)del_char(false); + ins_char(firstdigit); + } else { + if (col > 0 && ptr[col - 1] == '-' && !visual) { + // negative number + col--; + negative = true; + } - // get the number value (unsigned) - vim_str2nr(ptr + col, &pre, &length, dobin, dooct, dohex, NULL, &n); + // get the number value (unsigned) + vim_str2nr(ptr + col, &pre, &length, dobin, dooct, dohex, NULL, &n); - // ignore leading '-' for hex, octal and bin numbers - if (pre && negative) { - ++col; - --length; - negative = false; - } + // 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 (command == Ctrl_X) { + 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; + // 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; + } } - } else { /* add */ - if (n < oldn) { - n = (n ^ (unsigned long)-1); - negative ^= true; + if (n == 0) { + negative = false; } } - if (n == 0) { - negative = false; - } - } - // Delete the old number. - curwin->w_cursor.col = col; - todel = length; - c = gchar_cursor(); + // Delete the old number. + curwin->w_cursor.col = col; + 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; + // 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) { - *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); + ptr = buf1; + // do not add leading '-' for visual mode' + if (negative && !visual) { + *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 pos = 0; - // leading zeros - for (bits = 8 * sizeof(unsigned long); bits > 0; bits--) { - if ((n >> (bits - 1)) & 0x1) { break; } - } + // leading zeros + for (bits = 8 * sizeof(unsigned long); bits > 0; bits--) { + if ((n >> (bits - 1)) & 0x1) { break; } + } + + while (bits > 0) { + buf2[pos++] = ((n >> --bits) & 0x1) ? '1' : '0'; + } - while (bits > 0) { - buf2[pos++] = ((n >> --bits) & 0x1) ? '1' : '0'; + buf2[pos] = '\0'; + + } else if (pre == 0) { + snprintf((char *)buf2, NUMBUFLEN, "%" PRIu64, (uint64_t)n + offset); + } else if (pre == '0') { + snprintf((char *)buf2, NUMBUFLEN, "%" PRIo64, (uint64_t)n + offset); + } else if (pre && hexupper) { + snprintf((char *)buf2, NUMBUFLEN, "%" PRIX64, (uint64_t)n + offset); + } else { + snprintf((char *)buf2, NUMBUFLEN, "%" PRIx64, (uint64_t)n + offset); } + length -= (int)STRLEN(buf2); - buf2[pos] = '\0'; + if (g_cmd) { + offset = subtract ? offset - (unsigned long) Prenum1 + : offset + (unsigned long) Prenum1; + } - } else if (pre == 0) { - snprintf((char *)buf2, NUMBUFLEN, "%" PRIu64, (uint64_t)n); - } else if (pre == '0') { - snprintf((char *)buf2, NUMBUFLEN, "%" PRIo64, (uint64_t)n); - } else if (pre && hexupper) { - snprintf((char *)buf2, NUMBUFLEN, "%" PRIX64, (uint64_t)n); - } else { - snprintf((char *)buf2, NUMBUFLEN, "%" 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'; + // 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); } - *ptr = NUL; - STRCAT(buf1, buf2); - ins_str(buf1); /* insert the new number */ - xfree(buf1); - } - --curwin->w_cursor.col; - curwin->w_set_curswant = true; - ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum, true); - RLADDSUBFIX(ptr); + curwin->w_cursor.col--; + curwin->w_set_curswant = true; + ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum, true); + RLADDSUBFIX(ptr); + } return OK; } diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile index 41ce2daa91..c2fdca8514 100644 --- a/src/nvim/testdir/Makefile +++ b/src/nvim/testdir/Makefile @@ -28,6 +28,7 @@ SCRIPTS := \ test_charsearch.out \ test_close_count.out \ test_command_count.out \ + test_increment.out \ NEW_TESTS = @@ -131,7 +132,7 @@ test1.out: .gdbinit test1.in # Check if the test.out file matches test.ok. @/bin/sh -c "if test -f test.out; then \ - if diff test.out $*.ok; then \ + if diff -u test.out $*.ok; then \ mv -f test.out $*.out; \ else \ echo $* FAILED >> test.log; \ diff --git a/src/nvim/testdir/test_increment.in b/src/nvim/testdir/test_increment.in new file mode 100644 index 0000000000..5b0ad06cf8 --- /dev/null +++ b/src/nvim/testdir/test_increment.in @@ -0,0 +1,143 @@ +Tests for using Ctrl-A/Ctrl-X on visual selections + +Test cases +========== + +1) Ctrl-A on visually selected number +Text: +foobar-10 + 1) Ctrl-A on start of line: + foobar-9 + 2) Ctrl-A on visually selected "-10": + foobar-9 + 3) Ctrl-A on visually selected "10": + foobar-11 + 4) Ctrl-X on visually selected "-10" + foobar-11 + 5) Ctrl-X on visually selected "10" + foobar-9 + +2) Ctrl-A on visually selected lines +Text: +10 +20 +30 +40 + + 1) Ctrl-A on visually selected lines: +11 +21 +31 +41 + + 2) Ctrl-X on visually selected lines: +9 +19 +29 +39 + +3) g Ctrl-A on visually selected lines, with non-numbers in between +Text: +10 + +20 + +30 + +40 + + 1) 2 g Ctrl-A on visually selected lines: +12 + +24 + +36 + +48 + 2) 2 g Ctrl-X on visually selected lines +8 + +16 + +24 + +32 + +4) Ctrl-A on non-number +Text: +foobar-10 + 1) visually select foobar: + foobar-10 + +STARTTEST +:so small.vim + +:" Test 1 +:/^S1=/+,/^E1=/-y a +:/^E1/+put a +:/^E1/+2put a +f-v$:/^E1/+3put a +f1v$:/^E1/+4put a +f-v$:/^E1/+5put a +f1v$ + +:" Test 22 +:/^S2=/+,/^E2=/-y a +:/^E2/+put a +V3k$:.+put a +V3k$ + +:" Test 3 +:/^S3=/+,/^E3=/-y a +:/^E3=/+put a +V6k2g:.+put a +V6k2g + +:" Test 4 +:/^S4=/+,/^E4=/-y a +:/^E4=/+put a +vf- + +:" Save the report +:/^# Test 1/,$w! test.out +:qa! + + +# Test 1 +S1====== +foobar-10 +E1====== + + + +# Test 2 +S2===== +10 +20 +30 +40 +E2===== + + + +# Test 3 +S3===== +10 + +20 + +30 + +40 +E3===== + + + +# Test 4 +S4===== +foobar-10 +E4===== + + +ENDTEST + diff --git a/src/nvim/testdir/test_increment.ok b/src/nvim/testdir/test_increment.ok new file mode 100644 index 0000000000..4a61ad1d1d --- /dev/null +++ b/src/nvim/testdir/test_increment.ok @@ -0,0 +1,66 @@ +# Test 1 +S1====== +foobar-10 +E1====== + +foobar-9 +foobar-9 +foobar-11 +foobar-11 +foobar-9 + + +# Test 2 +S2===== +10 +20 +30 +40 +E2===== + +11 +21 +31 +41 + +9 +19 +29 +39 + +# Test 3 +S3===== +10 + +20 + +30 + +40 +E3===== + +12 + +24 + +36 + +48 + +8 + +16 + +24 + +32 + +# Test 4 +S4===== +foobar-10 +E4===== + +foobar-10 + +ENDTEST + diff --git a/src/nvim/version.c b/src/nvim/version.c index 30f104562f..24fa8defe8 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -380,7 +380,7 @@ static int included_patches[] = { // 757 NA // 756 NA // 755, - // 754, + 754, 753, // 752, // 751 NA |