# HG changeset patch # User Bram Moolenaar # Date 1437131028 -7200 # Node ID 58d9f967ae1a4dc16be4ca92f921976fbc3225ed # Parent b2839b524d9f4adeabf7b80b2d9809c0482eace1 patch 7.4.782 Problem: Still a few problems with CTRL-A and CTRL-X in Visual mode. Solution: Fix the reported problems. (Christian Brabandt) diff --git a/src/charset.c b/src/charset.c --- a/src/charset.c +++ b/src/charset.c @@ -1835,9 +1835,10 @@ vim_isblankline(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 */ void -vim_str2nr(start, hexp, len, dooct, dohex, nptr, unptr) +vim_str2nr(start, hexp, len, dooct, dohex, nptr, unptr, maxlen) char_u *start; int *hexp; /* return: type of number 0 = decimal, 'x' or 'X' is hex, '0' = octal */ @@ -1846,6 +1847,7 @@ vim_str2nr(start, hexp, len, dooct, dohe int dohex; /* recognize hex number */ long *nptr; /* return: signed result */ unsigned long *unptr; /* return: unsigned result */ + int maxlen; /* max length of string to check */ { char_u *ptr = start; int hex = 0; /* default is decimal */ @@ -1860,10 +1862,12 @@ vim_str2nr(start, hexp, len, dooct, dohe } /* Recognize hex and octal. */ - if (ptr[0] == '0' && ptr[1] != '8' && ptr[1] != '9') + if (ptr[0] == '0' && ptr[1] != '8' && ptr[1] != '9' + && (maxlen == 0 || maxlen > 1)) { hex = ptr[1]; - if (dohex && (hex == 'X' || hex == 'x') && vim_isxdigit(ptr[2])) + if (dohex && (hex == 'X' || hex == 'x') && vim_isxdigit(ptr[2]) + && (maxlen == 0 || maxlen > 2)) ptr += 2; /* hexadecimal */ else { @@ -1880,6 +1884,8 @@ vim_str2nr(start, hexp, len, dooct, dohe } if (ptr[n] >= '0') hex = '0'; /* assume octal */ + if (n == maxlen) + break; } } } @@ -1888,6 +1894,7 @@ vim_str2nr(start, hexp, len, dooct, dohe /* * Do the string-to-numeric conversion "manually" to avoid sscanf quirks. */ + n = 1; if (hex == '0' || dooct > 1) { /* octal */ @@ -1895,6 +1902,8 @@ vim_str2nr(start, hexp, len, dooct, dohe { un = 8 * un + (unsigned long)(*ptr - '0'); ++ptr; + if (n++ == maxlen) + break; } } else if (hex != 0 || dohex > 1) @@ -1904,6 +1913,8 @@ vim_str2nr(start, hexp, len, dooct, dohe { un = 16 * un + (unsigned long)hex2nr(*ptr); ++ptr; + if (n++ == maxlen) + break; } } else @@ -1913,6 +1924,8 @@ vim_str2nr(start, hexp, len, dooct, dohe { un = 10 * un + (unsigned long)(*ptr - '0'); ++ptr; + if (n++ == maxlen) + break; } } diff --git a/src/eval.c b/src/eval.c --- a/src/eval.c +++ b/src/eval.c @@ -1615,7 +1615,7 @@ call_vim_function(func, argc, argv, safe len = 0; else /* Recognize a number argument, the others must be strings. */ - vim_str2nr(argv[i], NULL, &len, TRUE, TRUE, &n, NULL); + vim_str2nr(argv[i], NULL, &len, TRUE, TRUE, &n, NULL, 0); if (len != 0 && len == (int)STRLEN(argv[i])) { argvars[i].v_type = VAR_NUMBER; @@ -5128,7 +5128,7 @@ eval7(arg, rettv, evaluate, want_string) else #endif { - vim_str2nr(*arg, NULL, &len, TRUE, TRUE, &n, NULL); + vim_str2nr(*arg, NULL, &len, TRUE, TRUE, &n, NULL, 0); *arg += len; if (evaluate) { @@ -18233,7 +18233,7 @@ f_str2nr(argvars, rettv) p = skipwhite(get_tv_string(&argvars[0])); if (*p == '+') p = skipwhite(p + 1); - vim_str2nr(p, NULL, NULL, base == 8 ? 2 : 0, base == 16 ? 2 : 0, &n, NULL); + vim_str2nr(p, NULL, NULL, base == 8 ? 2 : 0, base == 16 ? 2 : 0, &n, NULL, 0); rettv->vval.v_number = n; } @@ -21039,7 +21039,7 @@ get_tv_number_chk(varp, denote) case VAR_STRING: if (varp->vval.v_string != NULL) vim_str2nr(varp->vval.v_string, NULL, NULL, - TRUE, TRUE, &n, NULL); + TRUE, TRUE, &n, NULL, 0); return n; case VAR_LIST: EMSG(_("E745: Using a List as a Number")); diff --git a/src/ex_cmds.c b/src/ex_cmds.c --- a/src/ex_cmds.c +++ b/src/ex_cmds.c @@ -500,7 +500,7 @@ ex_sort(eap) nrs[lnum - eap->line1].start_col_nr = -MAXLNUM; else vim_str2nr(s, NULL, NULL, 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/ex_getln.c b/src/ex_getln.c --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -5917,7 +5917,7 @@ get_list_range(str, num1, num2) *str = skipwhite(*str); if (**str == '-' || vim_isdigit(**str)) /* parse "from" part of range */ { - vim_str2nr(*str, NULL, &len, FALSE, FALSE, &num, NULL); + vim_str2nr(*str, NULL, &len, FALSE, FALSE, &num, NULL, 0); *str += len; *num1 = (int)num; first = TRUE; @@ -5926,7 +5926,7 @@ get_list_range(str, num1, num2) if (**str == ',') /* parse "to" part of range */ { *str = skipwhite(*str + 1); - vim_str2nr(*str, NULL, &len, FALSE, FALSE, &num, NULL); + vim_str2nr(*str, NULL, &len, FALSE, FALSE, &num, NULL, 0); if (len > 0) { *num2 = (int)num; diff --git a/src/misc2.c b/src/misc2.c --- a/src/misc2.c +++ b/src/misc2.c @@ -2813,7 +2813,7 @@ find_special_key(srcp, modp, keycode, ke bp += 3; /* skip t_xx, xx may be '-' or '>' */ else if (STRNICMP(bp, "char-", 5) == 0) { - vim_str2nr(bp + 5, NULL, &l, TRUE, TRUE, NULL, NULL); + vim_str2nr(bp + 5, NULL, &l, TRUE, TRUE, NULL, NULL, 0); bp += l + 5; break; } @@ -2845,7 +2845,7 @@ find_special_key(srcp, modp, keycode, ke && VIM_ISDIGIT(last_dash[6])) { /* or or */ - vim_str2nr(last_dash + 6, NULL, NULL, TRUE, TRUE, NULL, &n); + vim_str2nr(last_dash + 6, NULL, NULL, TRUE, TRUE, NULL, &n, 0); key = (int)n; } else diff --git a/src/normal.c b/src/normal.c --- a/src/normal.c +++ b/src/normal.c @@ -40,6 +40,7 @@ static void find_start_of_word __ARGS((p 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)); @@ -3613,6 +3614,43 @@ find_ident_at_pos(wp, lnum, startcol, st } /* + * 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 - 1); + AppendCharToRedobuff(' '); + } + } + AppendNumberToRedobuff(cap->count1); +} + +/* * Prepare for redo of a normal command. */ static void @@ -4207,16 +4245,9 @@ nv_addsub(cap) { 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 @@ -4227,7 +4258,8 @@ nv_addsub(cap) if (visual) { VIsual_active = FALSE; - redraw_later(CLEAR); + redo_VIsual_busy = FALSE; + redraw_later(INVERTED); } } diff --git a/src/ops.c b/src/ops.c --- a/src/ops.c +++ b/src/ops.c @@ -5405,6 +5405,8 @@ do_addsub(command, Prenum1, g_cmd) int lnume = curwin->w_cursor.lnum; int startcol = 0; int 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" */ @@ -5418,21 +5420,30 @@ do_addsub(command, Prenum1, g_cmd) { if (lt(curwin->w_cursor, VIsual)) { - pos_T 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 ? VIsual.col @@ -5482,36 +5493,60 @@ do_addsub(command, Prenum1, g_cmd) for (i = lnum; i <= lnume; i++) { + t = curwin->w_cursor; curwin->w_cursor.lnum = i; ptr = ml_get_curline(); + 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++; + } + /* skip to first digit, but allow for leading '-' */ + else if (dohex) + { + while (!(vim_isxdigit(ptr[col]) || (ptr[col] == '-' + && vim_isxdigit(ptr[col+1]))) && ptr[col]) + col++; + } + else /* decimal */ + { + while (!(vim_isdigit(ptr[col]) || (ptr[col] == '-' + && vim_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 ((!VIM_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; } - ptr = ml_get_curline(); - RLADDSUBFIX(ptr); - if (doalp && ASCII_ISALPHA(firstdigit)) { /* decrement or increment alphabetic character */ @@ -5560,9 +5595,27 @@ do_addsub(command, Prenum1, g_cmd) --col; negative = TRUE; } - /* get the number value (unsigned) */ - vim_str2nr(ptr + col, &hex, &length, 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, &hex, &length, dooct, dohex, NULL, &n, + maxlen); /* ignore leading '-' for hex and octal numbers */ if (hex && negative) @@ -5609,7 +5662,7 @@ do_addsub(command, Prenum1, g_cmd) negative = FALSE; } - if (visual && !was_positive && !negative) + if (visual && !was_positive && !negative && col > 0) { /* need to remove the '-' */ col--; @@ -5695,6 +5748,10 @@ do_addsub(command, Prenum1, g_cmd) STRCAT(buf1, buf2); ins_str(buf1); /* insert the new number */ vim_free(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) @@ -5705,6 +5762,7 @@ do_addsub(command, Prenum1, g_cmd) /* reset */ subtract = FALSE; negative = FALSE; + was_positive = TRUE; if (visual && VIsual_mode == Ctrl_V) col = startcol; else @@ -5716,8 +5774,9 @@ do_addsub(command, Prenum1, g_cmd) RLADDSUBFIX(ptr); #endif } - 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/option.c b/src/option.c --- a/src/option.c +++ b/src/option.c @@ -4561,7 +4561,7 @@ do_set(arg, opt_flags) { /* Allow negative (for 'undolevels'), octal and * hex numbers. */ - vim_str2nr(arg, NULL, &i, TRUE, TRUE, &value, NULL); + vim_str2nr(arg, NULL, &i, TRUE, TRUE, &value, NULL, 0); if (arg[i] != NUL && !vim_iswhite(arg[i])) { errmsg = e_invarg; diff --git a/src/proto/charset.pro b/src/proto/charset.pro --- a/src/proto/charset.pro +++ b/src/proto/charset.pro @@ -49,7 +49,7 @@ char_u *skiptowhite __ARGS((char_u *p)); char_u *skiptowhite_esc __ARGS((char_u *p)); long getdigits __ARGS((char_u **pp)); int vim_isblankline __ARGS((char_u *lbuf)); -void vim_str2nr __ARGS((char_u *start, int *hexp, int *len, int dooct, int dohex, long *nptr, unsigned long *unptr)); +void vim_str2nr __ARGS((char_u *start, int *hexp, int *len, int dooct, int dohex, long *nptr, unsigned long *unptr, int strlen)); int hex2nr __ARGS((int c)); int hexhex2nr __ARGS((char_u *p)); int rem_backslash __ARGS((char_u *str)); diff --git a/src/testdir/test_increment.in b/src/testdir/test_increment.in --- a/src/testdir/test_increment.in +++ b/src/testdir/test_increment.in @@ -185,6 +185,83 @@ 0 0 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 +Text: + 0 + 0 + 0 + 0 + + Expected: + 1) V 4j g, 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 @@ 3kf13jg :/^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/testdir/test_increment.ok b/src/testdir/test_increment.ok --- a/src/testdir/test_increment.ok +++ b/src/testdir/test_increment.ok @@ -184,7 +184,81 @@ 1 0 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/version.c b/src/version.c --- 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 */ /**/ + 782, +/**/ 781, /**/ 780,