diff options
-rw-r--r-- | src/nvim/charset.c | 33 | ||||
-rw-r--r-- | src/nvim/eval.c | 8 | ||||
-rw-r--r-- | src/nvim/ex_cmds.c | 2 | ||||
-rw-r--r-- | src/nvim/ex_getln.c | 4 | ||||
-rw-r--r-- | src/nvim/keymap.c | 4 | ||||
-rw-r--r-- | src/nvim/normal.c | 43 | ||||
-rw-r--r-- | src/nvim/ops.c | 84 | ||||
-rw-r--r-- | src/nvim/option.c | 2 | ||||
-rw-r--r-- | src/nvim/testdir/test_increment.in | 172 | ||||
-rw-r--r-- | src/nvim/testdir/test_increment.ok | 74 | ||||
-rw-r--r-- | src/nvim/version.c | 2 |
11 files changed, 382 insertions, 46 deletions
diff --git a/src/nvim/charset.c b/src/nvim/charset.c index 9c63eca1f2..e689af0c82 100644 --- a/src/nvim/charset.c +++ b/src/nvim/charset.c @@ -1773,6 +1773,7 @@ int vim_isblankline(char_u *lbuf) /// octal number. /// If "dohex" is non-zero recognize hex numbers, when > 1 always assume /// hex number. +/// If maxlen > 0, check at a maximum maxlen chars. /// /// @param start /// @param prep Returns type of number 0 = decimal, 'x' or 'X' is hex, @@ -1783,9 +1784,10 @@ int vim_isblankline(char_u *lbuf) /// @param dohex recognize hex number /// @param nptr Returns the signed result. /// @param unptr Returns the unsigned result. +/// @param maxlen Max length of string to check. void vim_str2nr(char_u *start, int *prep, int *len, int dobin, int dooct, int dohex, - long *nptr, unsigned long *unptr) + long *nptr, unsigned long *unptr, int maxlen) { char_u *ptr = start; int pre = 0; // default is decimal @@ -1797,18 +1799,21 @@ void vim_str2nr(char_u *start, int *prep, int *len, ptr++; } - // Recognize hex, octal, and bin. - if ((ptr[0] == '0') && (ptr[1] != '8') && (ptr[1] != '9')) { + // Recognize hex, octal and bin. + if ((ptr[0] == '0') && (ptr[1] != '8') && (ptr[1] != '9') + && (maxlen == 0 || maxlen > 1)) { pre = ptr[1]; if (dohex && ((pre == 'X') || (pre == 'x')) - && ascii_isxdigit(ptr[2])) { + && ascii_isxdigit(ptr[2]) + && (maxlen == 0 || maxlen > 2)) { // hexadecimal ptr += 2; } else if (dobin && ((pre == 'B') || (pre == 'b')) - && ascii_isbdigit(ptr[2])) { + && ascii_isbdigit(ptr[2]) + && (maxlen == 0 || maxlen > 2)) { // binary ptr += 2; } else { @@ -1827,35 +1832,51 @@ void vim_str2nr(char_u *start, int *prep, int *len, // assume octal pre = '0'; } + if (n == maxlen) { + break; + } } } } } // Do the string-to-numeric conversion "manually" to avoid sscanf quirks. - if ((pre == 'B') || (pre == 'b') || (dobin > 1)) { + int n = 1; + if ((pre == 'B') || (pre == 'b') || what == STR2NR_BIN + STR2NR_FORCE) { // bin while ('0' <= *ptr && *ptr <= '1') { un = 2 * un + (unsigned long)(*ptr - '0'); ptr++; + if (n++ == maxlen) { + break; + } } } else if ((pre == '0') || (dooct > 1)) { // octal while ('0' <= *ptr && *ptr <= '7') { un = 8 * un + (unsigned long)(*ptr - '0'); ptr++; + if (n++ == maxlen) { + break; + } } } else if ((pre == 'X') || (pre == 'x') || dohex > 1) { // hex while (ascii_isxdigit(*ptr)) { un = 16 * un + (unsigned long)hex2nr(*ptr); ptr++; + if (n++ == maxlen) { + break; + } } } else { // decimal while (ascii_isdigit(*ptr)) { un = 10 * un + (unsigned long)(*ptr - '0'); ptr++; + if (n++ == maxlen) { + break; + } } } diff --git a/src/nvim/eval.c b/src/nvim/eval.c index a1c5f958d1..52c22b19b9 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -1147,7 +1147,7 @@ int call_vim_function( len = 0; } else { // Recognize a number argument, the others must be strings. - vim_str2nr(argv[i], NULL, &len, true, true, true, &n, NULL); + vim_str2nr(argv[i], NULL, &len, true, true, true, &n, NULL, 0); } if (len != 0 && len == (int)STRLEN(argv[i])) { argvars[i].v_type = VAR_NUMBER; @@ -4138,7 +4138,7 @@ static int eval7( rettv->vval.v_float = f; } } else { - vim_str2nr(*arg, NULL, &len, true, true, true, &n, NULL); + vim_str2nr(*arg, NULL, &len, true, true, true, &n, NULL, 0); *arg += len; if (evaluate) { rettv->v_type = VAR_NUMBER; @@ -16054,7 +16054,7 @@ static void f_str2nr(typval_T *argvars, typval_T *rettv) base == 2 ? 2 : 0, base == 8 ? 2 : 0, base == 16 ? 2 : 0, - &n, NULL); + &n, NULL, 0); rettv->vval.v_number = n; } @@ -18336,7 +18336,7 @@ long get_tv_number_chk(typval_T *varp, int *denote) case VAR_STRING: if (varp->vval.v_string != NULL) { vim_str2nr(varp->vval.v_string, NULL, NULL, - true, true, true, &n, NULL); + true, true, true, &n, NULL, 0); } return n; case VAR_LIST: diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 407dded6af..5cabb9b820 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -472,7 +472,7 @@ void ex_sort(exarg_T *eap) nrs[lnum - eap->line1].start_col_nr = -MAXLNUM; } else { vim_str2nr(s, NULL, NULL, sort_bin, sort_oct, sort_hex, - &nrs[lnum - eap->line1].start_col_nr, NULL); + &nrs[lnum - eap->line1].start_col_nr, NULL, 0); } *s2 = c; } else { diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index b19331ad06..d47e2fa954 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -4786,7 +4786,7 @@ int get_list_range(char_u **str, int *num1, int *num2) *str = skipwhite(*str); if (**str == '-' || ascii_isdigit(**str)) { // parse "from" part of range - vim_str2nr(*str, NULL, &len, false, false, false, &num, NULL); + vim_str2nr(*str, NULL, &len, false, false, false, &num, NULL, 0); *str += len; *num1 = (int)num; first = true; @@ -4794,7 +4794,7 @@ int get_list_range(char_u **str, int *num1, int *num2) *str = skipwhite(*str); if (**str == ',') { // parse "to" part of range *str = skipwhite(*str + 1); - vim_str2nr(*str, NULL, &len, false, false, false, &num, NULL); + vim_str2nr(*str, NULL, &len, false, false, false, &num, NULL, 0); if (len > 0) { *num2 = (int)num; *str = skipwhite(*str + len); diff --git a/src/nvim/keymap.c b/src/nvim/keymap.c index 7054bb822a..6aa42a9801 100644 --- a/src/nvim/keymap.c +++ b/src/nvim/keymap.c @@ -574,7 +574,7 @@ int find_special_key( if (bp[0] == 't' && bp[1] == '_' && bp[2] && bp[3]) { bp += 3; // skip t_xx, xx may be '-' or '>' } else if (STRNICMP(bp, "char-", 5) == 0) { - vim_str2nr(bp + 5, NULL, &l, true, true, true, NULL, NULL); + vim_str2nr(bp + 5, NULL, &l, true, true, true, NULL, NULL, 0); bp += l + 5; break; } @@ -600,7 +600,7 @@ int find_special_key( if (STRNICMP(last_dash + 1, "char-", 5) == 0 && ascii_isdigit(last_dash[6])) { // <Char-123> or <Char-033> or <Char-0x33> - vim_str2nr(last_dash + 6, NULL, NULL, true, true, true, NULL, &n); + vim_str2nr(last_dash + 6, NULL, NULL, true, true, true, NULL, &n, 0); key = (int)n; } else { /* diff --git a/src/nvim/normal.c b/src/nvim/normal.c index d831679b64..23e2e634cc 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -3028,6 +3028,34 @@ 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 - 1); + AppendCharToRedobuff(' '); + } + } + AppendNumberToRedobuff(cap->count1); +} + /* * Prepare for redo of a normal command. */ @@ -3507,15 +3535,9 @@ static void nv_addsub(cmdarg_T *cap) if (cap->oap->op_type == OP_NOP && do_addsub((int)cap->cmdchar, cap->count1, cap->arg) == OK) { if (visual) { - ResetRedobuff(); - AppendCharToRedobuff(VIsual_mode); - if (VIsual_mode == 'V') { - AppendNumberToRedobuff(cap->oap->line_count); - AppendCharToRedobuff('j'); - } - AppendNumberToRedobuff(cap->count1); - if (cap->nchar != NUL) { - AppendCharToRedobuff(cap->nchar); + prep_redo_visual(cap); + if (cap->arg) { + AppendCharToRedobuff('g'); } AppendCharToRedobuff(cap->cmdchar); } else { @@ -3526,7 +3548,8 @@ static void nv_addsub(cmdarg_T *cap) } if (visual) { VIsual_active = false; - redraw_later(CLEAR); + redo_VIsual_busy = false; + redraw_later(INVERTED); } } diff --git a/src/nvim/ops.c b/src/nvim/ops.c index a7c2f2ae72..af38391437 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -4232,6 +4232,8 @@ int do_addsub(int command, linenr_T Prenum1, bool g_cmd) int lnume = curwin->w_cursor.lnum; int startcol = 0; bool did_change = false; + pos_T t = curwin->w_cursor; + int maxlen = 0; dohex = (vim_strchr(curbuf->b_p_nf, 'x') != NULL); // "heX" dooct = (vim_strchr(curbuf->b_p_nf, 'o') != NULL); // "Octal" @@ -4242,21 +4244,27 @@ int do_addsub(int command, linenr_T Prenum1, bool g_cmd) col = curwin->w_cursor.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); + 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 @@ -4332,24 +4340,51 @@ int do_addsub(int command, linenr_T Prenum1, bool g_cmd) } for (int i = lnum; i <= lnume; i++) { + t = curwin->w_cursor; curwin->w_cursor.lnum = i; ptr = get_cursor_line_ptr(); + RLADDSUBFIX(ptr); if ((int)STRLEN(ptr) <= col) { // try again on next line continue; } + if (visual) { + if (doalp) { + // search for ascii chars + while (!ASCII_ISALPHA(ptr[col]) && ptr[col]) { + col++; + } + } else if (dohex) { + // skip to first digit, but allow for leading '-' + while (!(ascii_isxdigit(ptr[col]) + || (ptr[col] == '-' && ascii_isxdigit(ptr[col + 1]))) + && ptr[col]) { + col++; + } + } else { + // decimal + while (!(ascii_isdigit(ptr[col]) + || (ptr[col] == '-' && ascii_isdigit(ptr[col + 1]))) + && ptr[col]) { + col++; + } + } + } if (visual && ptr[col] == '-') { negative = true; was_positive = false; col++; } - RLADDSUBFIX(ptr); // 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) { + if (visual && VIsual_mode != Ctrl_V) { + col = 0; + } else { + col = startcol; + } // Try again on next line continue; } @@ -4357,9 +4392,6 @@ int do_addsub(int command, linenr_T Prenum1, bool g_cmd) return FAIL; } - ptr = get_cursor_line_ptr(); - RLADDSUBFIX(ptr); - if (doalp && ASCII_ISALPHA(firstdigit)) { // decrement or increment alphabetic character if (command == Ctrl_X) { @@ -4395,7 +4427,26 @@ int do_addsub(int command, linenr_T Prenum1, bool g_cmd) } // get the number value (unsigned) - vim_str2nr(ptr + col, &pre, &length, dobin, dooct, dohex, NULL, &n); + 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, dobin, dooct, dohex, + NULL, &n, maxlen); // ignore leading '-' for hex, octal and bin numbers if (pre && negative) { @@ -4437,7 +4488,7 @@ int do_addsub(int command, linenr_T Prenum1, bool g_cmd) } } - if (visual && !was_positive && !negative) { + if (visual && !was_positive && !negative && col > 0) { // need to remove the '-' col--; length++; @@ -4525,6 +4576,11 @@ int do_addsub(int command, linenr_T Prenum1, bool g_cmd) STRCAT(buf1, buf2); ins_str(buf1); // insert the new number xfree(buf1); + if (lnum < lnume) { + curwin->w_cursor.col = t.col; + } else if (did_change && curwin->w_cursor.col) { + curwin->w_cursor.col--; + } } if (g_cmd) { @@ -4534,6 +4590,7 @@ int do_addsub(int command, linenr_T Prenum1, bool g_cmd) // reset subtract = false; negative = false; + was_positive = true; if (visual && VIsual_mode == Ctrl_V) { col = startcol; } else { @@ -4544,8 +4601,9 @@ int do_addsub(int command, linenr_T Prenum1, bool g_cmd) ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum, true); RLADDSUBFIX(ptr); } - if (did_change && curwin->w_cursor.col > 0) { - curwin->w_cursor.col--; + if (visual) { + // cursor at the top of the selection + curwin->w_cursor = VIsual; } return OK; } diff --git a/src/nvim/option.c b/src/nvim/option.c index b4054dc28c..dd512d2dba 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -1432,7 +1432,7 @@ do_set ( } else if (*arg == '-' || ascii_isdigit(*arg)) { // Allow negative (for 'undolevels'), octal and // hex numbers. - vim_str2nr(arg, NULL, &i, true, true, true, &value, NULL); + vim_str2nr(arg, NULL, &i, true, true, true, &value, NULL, 0); if (arg[i] != NUL && !ascii_iswhite(arg[i])) { errmsg = e_invarg; goto skip; diff --git a/src/nvim/testdir/test_increment.in b/src/nvim/testdir/test_increment.in index 45ed23b9a5..916f77e84b 100644 --- a/src/nvim/testdir/test_increment.in +++ b/src/nvim/testdir/test_increment.in @@ -185,6 +185,83 @@ Text: 1 0 1 0 +13) visually selected part of columns +Text: +max: 100px +max: 200px +max: 300px +max: 400px + Expected: + 1) 'v' on first two numbers Ctrl-A + max: 110px + max: 220px + max: 330px + max: 400px + 2) 'v' on first two numbers Ctrl-X + max: 90px + max: 190px + max: 290px + max: 400px + +14) redo in block mode +Text: +1 1 +1 1 + Expected: + 1) Ctrl-a on first column, redo on second column + 2 2 + 2 2 + +15) block select single numbers +Text: +101 + Expected: + 1) Ctrl-a on visually selected zero + 111 + +16) increment right aligned numbers +Text: + 1 + 19 + 119 + Expected: + 1) Ctrl-a on line selected region + 2 + 20 + 120 + +17) block-wise increment and redo +Text: + 100 + 1 + + 100 + 1 + + Expected: + 1) Ctrl-V j $ on first block, afterwards '.' on second + 101 + 2 + + 101 + 2 + +18) repeat of g<Ctrl-a> +Text: + 0 + 0 + 0 + 0 + + Expected: + 1) V 4j g<ctrl-a>, repeat twice afterwards with . + 3 + 6 + 9 + 12 + + + STARTTEST :so small.vim :" @@ -200,16 +277,16 @@ f1v$:/^E1=/+4put a f-v$:/^E1=/+5put a f1v$ -:" Test 22 +:" Test 2 :/^S2=/+,/^E2=/-y a :/^E2=/+put a -V3k$:.+put a +V3k$3j:.+put a V3k$ :" Test 3 :/^S3=/+,/^E3=/-y a :/^E3=/+put a -V6k2g:.+put a +V6k2g6j:.+put a V6k2g :" Test 4 @@ -229,21 +306,22 @@ v3kg v3kg :" Test 7 +:set nrformats&vim :/^S7=/+,/^E7=/-y a :/^E7=/+put a -V4k:.+put a +V4k4j:.+put a V4k :" Test 8 :/^S8=/+,/^E8=/-y a :/^E8=/+put a -kj$:.+put a +kj$j:.+put a k$+ :" Test 9 :/^S9=/+,/^E9=/-y a :/^E9=/+put a -5kVj22j. +5kVj23j. :" Test 10 :/^S10=/+,/^E10=/-y a @@ -260,6 +338,37 @@ V3kg :/^E12=/+put a 2k$v++ +:" Test 13 +:/^S13=/+,/^E13=/-y a +:/^E13=/+put a +3kf1l2j3j:.+put a +3kf1l2j + +:" Test 14 +:/^S14=/+,/^E14=/-y a +:/^E14=/+put a +kw. + +:" Test 15 +:/^S15=/+,/^E15=/-y a +:/^E15=/+put a +lv + +:" Test 16 +:/^S16=/+,/^E16=/-y a +:/^E16=/+put a +V3k + +:" Test 17 +:/^S17=/+,/^E17=/-y a +:/^E17=/+put a +4kj$2j. + +:" Test 18 +:/^S18=/+,/^E18=/-y a +:/^E18=/+put a +V3kg.. + :" Save the report :/^# Test 1/,$w! test.out :qa! @@ -384,6 +493,57 @@ E12==== +# Test 13 +S13==== +max: 100px +max: 200px +max: 300px +max: 400px +E13==== + + + +# Test 14 +S14==== +1 1 +1 1 +E14==== + + + +# Test 15 +S15==== +101 +E15==== + + + +# Test 16 +S16==== + 1 + 19 + 119 +E16==== + + + +# Test 17 +S17==== + 100 + 1 + + 100 + 1 +E17==== + + +# Test 18 +S18==== +0 +0 +0 +0 +E18==== diff --git a/src/nvim/testdir/test_increment.ok b/src/nvim/testdir/test_increment.ok index 03a10cbaa0..6ca0acce66 100644 --- a/src/nvim/testdir/test_increment.ok +++ b/src/nvim/testdir/test_increment.ok @@ -184,7 +184,81 @@ E12==== 1 0 +# Test 13 +S13==== +max: 100px +max: 200px +max: 300px +max: 400px +E13==== +max: 110px +max: 210px +max: 310px +max: 400px + +max: 90px +max: 190px +max: 290px +max: 400px + +# Test 14 +S14==== +1 1 +1 1 +E14==== + +2 2 +2 2 + + +# Test 15 +S15==== +101 +E15==== + +111 + + +# Test 16 +S16==== + 1 + 19 + 119 +E16==== + + 2 + 20 + 120 + + +# Test 17 +S17==== + 100 + 1 + + 100 + 1 +E17==== + + 101 + 2 + + 101 + 1 + +# Test 18 +S18==== +0 +0 +0 +0 +E18==== + +3 +6 +9 +12 diff --git a/src/nvim/version.c b/src/nvim/version.c index 955a042fcc..0b9468ac6c 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -352,7 +352,7 @@ static int included_patches[] = { 785, 784, // 783 NA - // 782, + 782, 781, 780, 779, |