Merge pull request #4013 from watiko/vim-increment

Vim patches related to increment and marks
This commit is contained in:
Justin M. Keyes
2016-02-01 01:47:37 -05:00
21 changed files with 1481 additions and 322 deletions

View File

@@ -370,11 +370,14 @@ CTRL-A Add [count] to the number or alphabetic character at
CTRL-X Subtract [count] from the number or alphabetic CTRL-X Subtract [count] from the number or alphabetic
character at or after the cursor. character at or after the cursor.
The CTRL-A and CTRL-X commands work for (signed) decimal numbers, unsigned The CTRL-A and CTRL-X commands can work for:
binary/octal/hexadecimal numbers and alphabetic characters. This - signed and unsigned decimal numbers
depends on the 'nrformats' option. - unsigned binary, octal and hexadecimal numbers
- When 'nrformats' includes "bin", Vim considers numbers starting with '0b' or - alphabetic characters
'0B' as binary.
This depends on the 'nrformats' option:
- When 'nrformats' includes "bin", Vim assumes numbers starting with '0b' or
'0B' are binary.
- When 'nrformats' includes "octal", Vim considers numbers starting with a '0' - When 'nrformats' includes "octal", Vim considers numbers starting with a '0'
to be octal, unless the number includes a '8' or '9'. Other numbers are to be octal, unless the number includes a '8' or '9'. Other numbers are
decimal and may have a preceding minus sign. decimal and may have a preceding minus sign.

View File

@@ -4396,7 +4396,7 @@ A jump table for the options with a short description can be found at |Q_op|.
recognized as a multi click. recognized as a multi click.
*'nrformats'* *'nf'* *'nrformats'* *'nf'*
'nrformats' 'nf' string (default "hex") 'nrformats' 'nf' string (default "bin,hex")
local to buffer local to buffer
This defines what bases Vim will consider for numbers when using the This defines what bases Vim will consider for numbers when using the
CTRL-A and CTRL-X commands for adding to and subtracting from a number CTRL-A and CTRL-X commands for adding to and subtracting from a number
@@ -4409,6 +4409,9 @@ A jump table for the options with a short description can be found at |Q_op|.
hex If included, numbers starting with "0x" or "0X" will be hex If included, numbers starting with "0x" or "0X" will be
considered to be hexadecimal. Example: Using CTRL-X on considered to be hexadecimal. Example: Using CTRL-X on
"0x100" results in "0x0ff". "0x100" results in "0x0ff".
bin If included, numbers starting with "0b" or "0B" will be
considered to be binary. Example: Using CTRL-X on
"0b1000" subtracts one, resulting in "0b0111".
Numbers which simply begin with a digit in the range 1-9 are always Numbers which simply begin with a digit in the range 1-9 are always
considered decimal. This also happens for numbers that are not considered decimal. This also happens for numbers that are not
recognized as octal or hex. recognized as octal or hex.

View File

@@ -1767,29 +1767,26 @@ int vim_isblankline(char_u *lbuf)
/// If "len" is not NULL, the length of the number in characters is returned. /// If "len" is not NULL, the length of the number in characters is returned.
/// If "nptr" is not NULL, the signed result is returned in it. /// If "nptr" is not NULL, the signed result is returned in it.
/// If "unptr" is not NULL, the unsigned result is returned in it. /// If "unptr" is not NULL, the unsigned result is returned in it.
/// If "dobin" is non-zero recognize binary numbers, when > 1 always assume /// If "what" contains STR2NR_BIN recognize binary numbers.
/// binary number. /// If "what" contains STR2NR_OCT recognize octal numbers.
/// If "dooct" is non-zero recognize octal numbers, when > 1 always assume /// If "what" contains STR2NR_HEX recognize hex numbers.
/// octal number. /// If "what" contains STR2NR_FORCE always assume bin/oct/hex.
/// If "dohex" is non-zero recognize hex numbers, when > 1 always assume /// If maxlen > 0, check at a maximum maxlen chars.
/// hex number.
/// ///
/// @param start /// @param start
/// @param prep Returns type of number 0 = decimal, 'x' or 'X' is hex, /// @param prep Returns type of number 0 = decimal, 'x' or 'X' is hex,
// '0' = octal, 'b' or 'B' is bin /// '0' = octal, 'b' or 'B' is bin
/// @param len Returns the detected length of number. /// @param len Returns the detected length of number.
/// @param dobin recognize binary number /// @param what Recognizes what number passed.
/// @param dooct recognize octal number
/// @param dohex recognize hex number
/// @param nptr Returns the signed result. /// @param nptr Returns the signed result.
/// @param unptr Returns the unsigned result. /// @param unptr Returns the unsigned result.
void vim_str2nr(char_u *start, int *prep, int *len, /// @param maxlen Max length of string to check.
int dobin, int dooct, int dohex, void vim_str2nr(char_u *start, int *prep, int *len, int what,
long *nptr, unsigned long *unptr) long *nptr, unsigned long *unptr, int maxlen)
{ {
char_u *ptr = start; char_u *ptr = start;
int pre = 0; // default is decimal int pre = 0; // default is decimal
int negative = false; bool negative = false;
unsigned long un = 0; unsigned long un = 0;
if (ptr[0] == '-') { if (ptr[0] == '-') {
@@ -1797,25 +1794,28 @@ void vim_str2nr(char_u *start, int *prep, int *len,
ptr++; ptr++;
} }
// Recognize hex, octal, and bin. // Recognize hex, octal and bin.
if ((ptr[0] == '0') && (ptr[1] != '8') && (ptr[1] != '9')) { if ((ptr[0] == '0') && (ptr[1] != '8') && (ptr[1] != '9')
&& (maxlen == 0 || maxlen > 1)) {
pre = ptr[1]; pre = ptr[1];
if (dohex if ((what & STR2NR_HEX)
&& ((pre == 'X') || (pre == 'x')) && ((pre == 'X') || (pre == 'x'))
&& ascii_isxdigit(ptr[2])) { && ascii_isxdigit(ptr[2])
&& (maxlen == 0 || maxlen > 2)) {
// hexadecimal // hexadecimal
ptr += 2; ptr += 2;
} else if (dobin } else if ((what & STR2NR_BIN)
&& ((pre == 'B') || (pre == 'b')) && ((pre == 'B') || (pre == 'b'))
&& ascii_isbdigit(ptr[2])) { && ascii_isbdigit(ptr[2])
&& (maxlen == 0 || maxlen > 2)) {
// binary // binary
ptr += 2; ptr += 2;
} else { } else {
// default is decimal // decimal or octal, default is decimal
pre = 0; pre = 0;
if (dooct) { if (what & STR2NR_OCT) {
// Don't interpret "0", "08" or "0129" as octal. // Don't interpret "0", "08" or "0129" as octal.
for (int n = 1; ascii_isdigit(ptr[n]); ++n) { for (int n = 1; ascii_isdigit(ptr[n]); ++n) {
if (ptr[n] > '7') { if (ptr[n] > '7') {
@@ -1827,35 +1827,58 @@ void vim_str2nr(char_u *start, int *prep, int *len,
// assume octal // assume octal
pre = '0'; pre = '0';
} }
if (n == maxlen) {
break;
}
} }
} }
} }
} }
// Do the string-to-numeric conversion "manually" to avoid sscanf quirks. // 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 // bin
if (pre != 0) {
n += 2; // skip over "0b"
}
while ('0' <= *ptr && *ptr <= '1') { while ('0' <= *ptr && *ptr <= '1') {
un = 2 * un + (unsigned long)(*ptr - '0'); un = 2 * un + (unsigned long)(*ptr - '0');
ptr++; ptr++;
if (n++ == maxlen) {
break;
}
} }
} else if ((pre == '0') || (dooct > 1)) { } else if ((pre == '0') || what == STR2NR_OCT + STR2NR_FORCE) {
// octal // octal
while ('0' <= *ptr && *ptr <= '7') { while ('0' <= *ptr && *ptr <= '7') {
un = 8 * un + (unsigned long)(*ptr - '0'); un = 8 * un + (unsigned long)(*ptr - '0');
ptr++; ptr++;
if (n++ == maxlen) {
break;
}
} }
} else if ((pre == 'X') || (pre == 'x') || dohex > 1) { } else if ((pre == 'X') || (pre == 'x')
|| what == STR2NR_HEX + STR2NR_FORCE) {
// hex // hex
if (pre != 0) {
n += 2; // skip over "0x"
}
while (ascii_isxdigit(*ptr)) { while (ascii_isxdigit(*ptr)) {
un = 16 * un + (unsigned long)hex2nr(*ptr); un = 16 * un + (unsigned long)hex2nr(*ptr);
ptr++; ptr++;
if (n++ == maxlen) {
break;
}
} }
} else { } else {
// decimal // decimal
while (ascii_isdigit(*ptr)) { while (ascii_isdigit(*ptr)) {
un = 10 * un + (unsigned long)(*ptr - '0'); un = 10 * un + (unsigned long)(*ptr - '0');
ptr++; ptr++;
if (n++ == maxlen) {
break;
}
} }
} }

View File

@@ -1147,7 +1147,7 @@ int call_vim_function(
len = 0; len = 0;
} else { } else {
// Recognize a number argument, the others must be strings. // 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, STR2NR_ALL, &n, NULL, 0);
} }
if (len != 0 && len == (int)STRLEN(argv[i])) { if (len != 0 && len == (int)STRLEN(argv[i])) {
argvars[i].v_type = VAR_NUMBER; argvars[i].v_type = VAR_NUMBER;
@@ -4138,7 +4138,7 @@ static int eval7(
rettv->vval.v_float = f; rettv->vval.v_float = f;
} }
} else { } else {
vim_str2nr(*arg, NULL, &len, true, true, true, &n, NULL); vim_str2nr(*arg, NULL, &len, STR2NR_ALL, &n, NULL, 0);
*arg += len; *arg += len;
if (evaluate) { if (evaluate) {
rettv->v_type = VAR_NUMBER; rettv->v_type = VAR_NUMBER;
@@ -16037,6 +16037,7 @@ static void f_str2nr(typval_T *argvars, typval_T *rettv)
int base = 10; int base = 10;
char_u *p; char_u *p;
long n; long n;
int what;
if (argvars[1].v_type != VAR_UNKNOWN) { if (argvars[1].v_type != VAR_UNKNOWN) {
base = get_tv_number(&argvars[1]); base = get_tv_number(&argvars[1]);
@@ -16050,11 +16051,20 @@ static void f_str2nr(typval_T *argvars, typval_T *rettv)
if (*p == '+') { if (*p == '+') {
p = skipwhite(p + 1); p = skipwhite(p + 1);
} }
vim_str2nr(p, NULL, NULL, switch (base) {
base == 2 ? 2 : 0, case 2:
base == 8 ? 2 : 0, what = STR2NR_BIN + STR2NR_FORCE;
base == 16 ? 2 : 0, break;
&n, NULL); case 8:
what = STR2NR_OCT + STR2NR_FORCE;
break;
case 16:
what = STR2NR_HEX + STR2NR_FORCE;
break;
default:
what = 0;
}
vim_str2nr(p, NULL, NULL, what, &n, NULL, 0);
rettv->vval.v_number = n; rettv->vval.v_number = n;
} }
@@ -18336,7 +18346,7 @@ long get_tv_number_chk(typval_T *varp, int *denote)
case VAR_STRING: case VAR_STRING:
if (varp->vval.v_string != NULL) { if (varp->vval.v_string != NULL) {
vim_str2nr(varp->vval.v_string, NULL, NULL, vim_str2nr(varp->vval.v_string, NULL, NULL,
true, true, true, &n, NULL); STR2NR_ALL, &n, NULL, 0);
} }
return n; return n;
case VAR_LIST: case VAR_LIST:

View File

@@ -342,27 +342,27 @@ void ex_sort(exarg_T *eap)
char_u *s; char_u *s;
char_u *s2; char_u *s2;
char_u c; // temporary character storage char_u c; // temporary character storage
int unique = false; bool unique = false;
long deleted; long deleted;
colnr_T start_col; colnr_T start_col;
colnr_T end_col; colnr_T end_col;
int sort_bin; // sort on bin number int sort_what = 0;
int sort_oct; // sort on octal number
int sort_hex; // sort on hex number
// Sorting one line is really quick! // Sorting one line is really quick!
if (count <= 1) { if (count <= 1) {
return; return;
} }
if (u_save((linenr_T)(eap->line1 - 1), (linenr_T)(eap->line2 + 1)) == FAIL) if (u_save((linenr_T)(eap->line1 - 1), (linenr_T)(eap->line2 + 1)) == FAIL) {
return; return;
}
sortbuf1 = NULL; sortbuf1 = NULL;
sortbuf2 = NULL; sortbuf2 = NULL;
regmatch.regprog = NULL; regmatch.regprog = NULL;
sorti_T *nrs = xmalloc(count * sizeof(sorti_T)); sorti_T *nrs = xmalloc(count * sizeof(sorti_T));
sort_abort = sort_ic = sort_rx = sort_nr = sort_bin = sort_oct = sort_hex = 0; sort_abort = sort_ic = sort_rx = sort_nr = 0;
size_t format_found = 0;
for (p = eap->arg; *p != NUL; ++p) { for (p = eap->arg; *p != NUL; ++p) {
if (ascii_iswhite(*p)) { if (ascii_iswhite(*p)) {
@@ -372,12 +372,16 @@ void ex_sort(exarg_T *eap)
sort_rx = true; sort_rx = true;
} else if (*p == 'n') { } else if (*p == 'n') {
sort_nr = 2; sort_nr = 2;
format_found++;
} else if (*p == 'b') { } else if (*p == 'b') {
sort_bin = 2; sort_what = STR2NR_BIN + STR2NR_FORCE;
format_found++;
} else if (*p == 'o') { } else if (*p == 'o') {
sort_oct = 2; sort_what = STR2NR_OCT + STR2NR_FORCE;
format_found++;
} else if (*p == 'x') { } else if (*p == 'x') {
sort_hex = 2; sort_what = STR2NR_HEX + STR2NR_FORCE;
format_found++;
} else if (*p == 'u') { } else if (*p == 'u') {
unique = true; unique = true;
} else if (*p == '"') { } else if (*p == '"') {
@@ -415,13 +419,13 @@ void ex_sort(exarg_T *eap)
} }
// Can only have one of 'n', 'b', 'o' and 'x'. // Can only have one of 'n', 'b', 'o' and 'x'.
if (sort_nr + sort_bin + sort_oct + sort_hex > 2) { if (format_found > 1) {
EMSG(_(e_invarg)); EMSG(_(e_invarg));
goto sortend; goto sortend;
} }
// From here on "sort_nr" is used as a flag for any number sorting. // From here on "sort_nr" is used as a flag for any number sorting.
sort_nr += sort_bin + sort_oct + sort_hex; sort_nr += sort_what;
// Make an array with all line numbers. This avoids having to copy all // Make an array with all line numbers. This avoids having to copy all
// the lines into allocated memory. // the lines into allocated memory.
@@ -457,22 +461,23 @@ void ex_sort(exarg_T *eap)
*s2 = NUL; *s2 = NUL;
// Sorting on number: Store the number itself. // Sorting on number: Store the number itself.
p = s + start_col; p = s + start_col;
if (sort_hex) { if (sort_what & STR2NR_HEX) {
s = skiptohex(p); s = skiptohex(p);
} else if (sort_bin) { } else if (sort_what & STR2NR_BIN) {
s = (char_u*) skiptobin((char*) p); s = (char_u*) skiptobin((char*) p);
} else { } else {
s = skiptodigit(p); s = skiptodigit(p);
} }
if (s > p && s[-1] == '-') { if (s > p && s[-1] == '-') {
--s; // include preceding negative sign // include preceding negative sign
s--;
} }
if (*s == NUL) { if (*s == NUL) {
// empty line should sort before any number // empty line should sort before any number
nrs[lnum - eap->line1].start_col_nr = -MAXLNUM; nrs[lnum - eap->line1].start_col_nr = -MAXLNUM;
} else { } else {
vim_str2nr(s, NULL, NULL, sort_bin, sort_oct, sort_hex, vim_str2nr(s, NULL, NULL, sort_what,
&nrs[lnum - eap->line1].start_col_nr, NULL); &nrs[lnum - eap->line1].start_col_nr, NULL, 0);
} }
*s2 = c; *s2 = c;
} else { } else {

View File

@@ -4786,7 +4786,7 @@ int get_list_range(char_u **str, int *num1, int *num2)
*str = skipwhite(*str); *str = skipwhite(*str);
if (**str == '-' || ascii_isdigit(**str)) { // parse "from" part of range 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, 0, &num, NULL, 0);
*str += len; *str += len;
*num1 = (int)num; *num1 = (int)num;
first = true; first = true;
@@ -4794,7 +4794,7 @@ int get_list_range(char_u **str, int *num1, int *num2)
*str = skipwhite(*str); *str = skipwhite(*str);
if (**str == ',') { // parse "to" part of range if (**str == ',') { // parse "to" part of range
*str = skipwhite(*str + 1); *str = skipwhite(*str + 1);
vim_str2nr(*str, NULL, &len, false, false, false, &num, NULL); vim_str2nr(*str, NULL, &len, 0, &num, NULL, 0);
if (len > 0) { if (len > 0) {
*num2 = (int)num; *num2 = (int)num;
*str = skipwhite(*str + len); *str = skipwhite(*str + len);

View File

@@ -574,7 +574,7 @@ int find_special_key(
if (bp[0] == 't' && bp[1] == '_' && bp[2] && bp[3]) { if (bp[0] == 't' && bp[1] == '_' && bp[2] && bp[3]) {
bp += 3; // skip t_xx, xx may be '-' or '>' bp += 3; // skip t_xx, xx may be '-' or '>'
} else if (STRNICMP(bp, "char-", 5) == 0) { } else if (STRNICMP(bp, "char-", 5) == 0) {
vim_str2nr(bp + 5, NULL, &l, true, true, true, NULL, NULL); vim_str2nr(bp + 5, NULL, &l, STR2NR_ALL, NULL, NULL, 0);
bp += l + 5; bp += l + 5;
break; break;
} }
@@ -600,7 +600,7 @@ int find_special_key(
if (STRNICMP(last_dash + 1, "char-", 5) == 0 if (STRNICMP(last_dash + 1, "char-", 5) == 0
&& ascii_isdigit(last_dash[6])) { && ascii_isdigit(last_dash[6])) {
// <Char-123> or <Char-033> or <Char-0x33> // <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, STR2NR_ALL, NULL, &n, 0);
key = (int)n; key = (int)n;
} else { } else {
/* /*

View File

@@ -1414,11 +1414,12 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
int lbr_saved = curwin->w_p_lbr; int lbr_saved = curwin->w_p_lbr;
/* The visual area is remembered for redo */ // The visual area is remembered for redo
static int redo_VIsual_mode = NUL; /* 'v', 'V', or Ctrl-V */ static int redo_VIsual_mode = NUL; // 'v', 'V', or Ctrl-V
static linenr_T redo_VIsual_line_count; /* number of lines */ static linenr_T redo_VIsual_line_count; // number of lines
static colnr_T redo_VIsual_vcol; /* number of cols or end column */ static colnr_T redo_VIsual_vcol; // number of cols or end column
static long redo_VIsual_count; /* count for Visual operator */ static long redo_VIsual_count; // count for Visual operator
static int redo_VIsual_arg; // extra argument
bool include_line_break = false; bool include_line_break = false;
old_cursor = curwin->w_cursor; 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_vcol = resel_VIsual_vcol;
redo_VIsual_line_count = resel_VIsual_line_count; redo_VIsual_line_count = resel_VIsual_line_count;
redo_VIsual_count = cap->count0; redo_VIsual_count = cap->count0;
redo_VIsual_arg = cap->arg;
} }
} }
@@ -1705,10 +1707,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
VIsual_active = false; VIsual_active = false;
setmouse(); setmouse();
mouse_dragging = 0; mouse_dragging = 0;
if (mode_displayed) may_clear_cmdline();
clear_cmdline = true; /* unshow visual mode later */
else
clear_showcmd();
if ((oap->op_type == OP_YANK if ((oap->op_type == OP_YANK
|| oap->op_type == OP_COLON || oap->op_type == OP_COLON
|| oap->op_type == OP_FUNCTION || oap->op_type == OP_FUNCTION
@@ -1993,6 +1992,20 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank)
deleteFold(oap->start.lnum, oap->end.lnum, deleteFold(oap->start.lnum, oap->end.lnum,
oap->op_type == OP_FOLDDELREC, oap->is_VIsual); oap->op_type == OP_FOLDDELREC, oap->is_VIsual);
break; 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: default:
clearopbeep(oap); clearopbeep(oap);
} }
@@ -2852,10 +2865,7 @@ void end_visual_mode(void)
if (!virtual_active()) if (!virtual_active())
curwin->w_cursor.coladd = 0; curwin->w_cursor.coladd = 0;
if (mode_displayed) may_clear_cmdline();
clear_cmdline = true; /* unshow visual mode later */
else
clear_showcmd();
adjust_cursor_eol(); adjust_cursor_eol();
} }
@@ -3121,10 +3131,19 @@ static void unshift_special(cmdarg_T *cap)
cap->cmdchar = simplify_key(cap->cmdchar, &mod_mask); cap->cmdchar = simplify_key(cap->cmdchar, &mod_mask);
} }
/* /// If the mode is currently displayed clear the command line or update the
* Routines for displaying a partly typed command /// command displayed.
*/ static void may_clear_cmdline(void)
{
if (mode_displayed) {
// unshow visual mode later
clear_cmdline = true;
} else {
clear_showcmd();
}
}
// Routines for displaying a partly typed command
# define SHOWCMD_BUFLEN SHOWCMD_COLS + 1 + 30 # define SHOWCMD_BUFLEN SHOWCMD_COLS + 1 + 30
static char_u showcmd_buf[SHOWCMD_BUFLEN]; static char_u showcmd_buf[SHOWCMD_BUFLEN];
static char_u old_showcmd_buf[SHOWCMD_BUFLEN]; /* For push_showcmd() */ static char_u old_showcmd_buf[SHOWCMD_BUFLEN]; /* For push_showcmd() */
@@ -3503,9 +3522,16 @@ static void nv_help(cmdarg_T *cap)
*/ */
static void nv_addsub(cmdarg_T *cap) static void nv_addsub(cmdarg_T *cap)
{ {
if (!checkclearopq(cap->oap) if (!VIsual_active && cap->oap->op_type == OP_NOP) {
&& do_addsub(cap->cmdchar, cap->count1))
prep_redo_cmd(cap); prep_redo_cmd(cap);
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 {
clearop(cap->oap);
}
} }
/* /*
@@ -6327,9 +6353,20 @@ static void nv_g_cmd(cmdarg_T *cap)
bool flag = false; bool flag = false;
switch (cap->nchar) { switch (cap->nchar) {
/* // "g^A/g^X": Sequentially increment visually selected region.
* "gR": Enter virtual replace mode. case Ctrl_A:
*/ case Ctrl_X:
if (VIsual_active) {
cap->arg = true;
cap->cmdchar = cap->nchar;
cap->nchar = NUL;
nv_addsub(cap);
} else {
clearopbeep(oap);
}
break;
// "gR": Enter virtual replace mode.
case 'R': case 'R':
cap->arg = true; cap->arg = true;
nv_Replace(cap); nv_Replace(cap);

View File

@@ -87,34 +87,36 @@ struct block_def {
*/ */
static char opchars[][3] = static char opchars[][3] =
{ {
{NUL, NUL, FALSE}, /* OP_NOP */ { NUL, NUL, false }, // OP_NOP
{'d', NUL, FALSE}, /* OP_DELETE */ { 'd', NUL, false }, // OP_DELETE
{'y', NUL, FALSE}, /* OP_YANK */ { 'y', NUL, false }, // OP_YANK
{'c', NUL, FALSE}, /* OP_CHANGE */ { 'c', NUL, false }, // OP_CHANGE
{'<', NUL, TRUE}, /* OP_LSHIFT */ { '<', NUL, true }, // OP_LSHIFT
{'>', NUL, TRUE}, /* OP_RSHIFT */ { '>', NUL, true }, // OP_RSHIFT
{'!', NUL, TRUE}, /* OP_FILTER */ { '!', NUL, true }, // OP_FILTER
{'g', '~', FALSE}, /* OP_TILDE */ { 'g', '~', false }, // OP_TILDE
{'=', NUL, TRUE}, /* OP_INDENT */ { '=', NUL, true }, // OP_INDENT
{'g', 'q', TRUE}, /* OP_FORMAT */ { 'g', 'q', true }, // OP_FORMAT
{':', NUL, TRUE}, /* OP_COLON */ { ':', NUL, true }, // OP_COLON
{'g', 'U', FALSE}, /* OP_UPPER */ { 'g', 'U', false }, // OP_UPPER
{'g', 'u', FALSE}, /* OP_LOWER */ { 'g', 'u', false }, // OP_LOWER
{'J', NUL, TRUE}, /* DO_JOIN */ { 'J', NUL, true }, // DO_JOIN
{'g', 'J', TRUE}, /* DO_JOIN_NS */ { 'g', 'J', true }, // DO_JOIN_NS
{'g', '?', FALSE}, /* OP_ROT13 */ { 'g', '?', false }, // OP_ROT13
{'r', NUL, FALSE}, /* OP_REPLACE */ { 'r', NUL, false }, // OP_REPLACE
{'I', NUL, FALSE}, /* OP_INSERT */ { 'I', NUL, false }, // OP_INSERT
{'A', NUL, FALSE}, /* OP_APPEND */ { 'A', NUL, false }, // OP_APPEND
{'z', 'f', TRUE}, /* OP_FOLD */ { 'z', 'f', true }, // OP_FOLD
{'z', 'o', TRUE}, /* OP_FOLDOPEN */ { 'z', 'o', true }, // OP_FOLDOPEN
{'z', 'O', TRUE}, /* OP_FOLDOPENREC */ { 'z', 'O', true }, // OP_FOLDOPENREC
{'z', 'c', TRUE}, /* OP_FOLDCLOSE */ { 'z', 'c', true }, // OP_FOLDCLOSE
{'z', 'C', TRUE}, /* OP_FOLDCLOSEREC */ { 'z', 'C', true }, // OP_FOLDCLOSEREC
{'z', 'd', TRUE}, /* OP_FOLDDEL */ { 'z', 'd', true }, // OP_FOLDDEL
{'z', 'D', TRUE}, /* OP_FOLDDELREC */ { 'z', 'D', true }, // OP_FOLDDELREC
{'g', 'w', TRUE}, /* OP_FORMAT2 */ { 'g', 'w', true }, // OP_FORMAT2
{'g', '@', FALSE}, /* OP_FUNCTION */ { '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; int i;
if (char1 == 'r') /* ignore second character */ if (char1 == 'r') {
// ignore second character
return OP_REPLACE; return OP_REPLACE;
if (char1 == '~') /* when tilde is an operator */ }
if (char1 == '~') {
// when tilde is an operator
return OP_TILDE; 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; break;
}
}
return i; return i;
} }
@@ -4181,134 +4197,241 @@ static void block_prep(oparg_T *oap, struct block_def *bdp, linenr_T lnum, int i
bdp->textstart = pstart; bdp->textstart = pstart;
} }
/// Handle the add/subtract operator.
static void reverse_line(char_u *s) ///
/// @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)
{ {
int i, j; pos_T pos;
char_u c; struct block_def bd;
ssize_t change_cnt = 0;
linenr_T amount = Prenum1;
if ((i = (int)STRLEN(s) - 1) <= 0) if (!VIsual_active) {
return; 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;
curwin->w_cursor.col = i - curwin->w_cursor.col; if (u_save((linenr_T)(oap->start.lnum - 1),
for (j = 0; j < i; j++, i--) { (linenr_T)(oap->end.lnum + 1)) == FAIL) {
c = s[i]; s[i] = s[j]; s[j] = c; 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 {
// 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);
}
}
} }
} }
# define RLADDSUBFIX(ptr) if (curwin->w_p_rl) reverse_line(ptr);
/// Add or subtract from a number in a line. /// Add or subtract from a number in a line.
/// ///
/// @param command CTRL-A for add, CTRL-X for subtract /// @param op_type OP_NR_ADD or OP_NR_SUB.
// @param Prenum1 number to add or subtract /// @param pos Cursor position.
/// @param length Target number length.
/// @param Prenum1 Amount of addition or subtraction.
/// ///
/// @return FAIL for failure, OK otherwise /// @return true if some character was changed.
int do_addsub(int command, linenr_T Prenum1) int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
{ {
int col; int col;
char_u *buf1; char_u *buf1;
char_u buf2[NUMBUFLEN]; char_u buf2[NUMBUFLEN];
int pre; // 'X' or 'x': hex; '0': octal; 'B' or 'b': bin int pre; // 'X' or 'x': hex; '0': octal; 'B' or 'b': bin
static int hexupper = false; // 0xABC static bool hexupper = false; // 0xABC
unsigned long n, oldn; unsigned long n;
unsigned long oldn;
char_u *ptr; char_u *ptr;
int c; int c;
int length = 0; // character length of the number
int todel; int todel;
int dohex; bool dohex;
int dooct; bool dooct;
int dobin; bool dobin;
int doalp; bool doalp;
int firstdigit; int firstdigit;
int negative; bool subtract;
int subtract; bool negative = false;
bool was_positive = true;
bool visual = VIsual_active;
bool did_change = false;
pos_T save_cursor = curwin->w_cursor;
int maxlen = 0;
pos_T startpos;
pos_T endpos;
dohex = (vim_strchr(curbuf->b_p_nf, 'x') != NULL); // "heX" dohex = (vim_strchr(curbuf->b_p_nf, 'x') != NULL); // "heX"
dooct = (vim_strchr(curbuf->b_p_nf, 'o') != NULL); // "Octal" dooct = (vim_strchr(curbuf->b_p_nf, 'o') != NULL); // "Octal"
dobin = (vim_strchr(curbuf->b_p_nf, 'b') != NULL); // "Bin" dobin = (vim_strchr(curbuf->b_p_nf, 'b') != NULL); // "Bin"
doalp = (vim_strchr(curbuf->b_p_nf, 'p') != NULL); // "alPha" doalp = (vim_strchr(curbuf->b_p_nf, 'p') != NULL); // "alPha"
ptr = get_cursor_line_ptr(); curwin->w_cursor = *pos;
RLADDSUBFIX(ptr); ptr = ml_get(pos->lnum);
col = pos->col;
if (*ptr == NUL) {
goto theend;
}
// First check if we are on a hexadecimal number, after the "0x". // First check if we are on a hexadecimal number, after the "0x".
col = curwin->w_cursor.col; if (!VIsual_active) {
if (dobin) {
if (dobin) { while (col > 0 && ascii_isbdigit(ptr[col])) {
while (col > 0 && ascii_isbdigit(ptr[col])) {
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
col = curwin->w_cursor.col;
while (col > 0 && ascii_isdigit(ptr[col])) {
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 if (dohex) {
&& ascii_isdigit(ptr[col - 1]) while (col > 0 && ascii_isxdigit(ptr[col])) {
&& !(doalp && ASCII_ISALPHA(ptr[col]))) { 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
col = curwin->w_cursor.col;
while (col > 0 && ascii_isdigit(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 = pos->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 (visual) {
while (ptr[col] != NUL && length > 0 && !ascii_isdigit(ptr[col]) &&
!(doalp && ASCII_ISALPHA(ptr[col]))) {
col++;
length--;
}
if (length == 0) {
goto theend;
}
if (col > pos->col && ptr[col - 1] == '-') {
negative = true;
was_positive = false;
} }
} }
// If a number was found, and saving for undo works, replace the number. // If a number was found, and saving for undo works, replace the number.
firstdigit = ptr[col]; firstdigit = ptr[col];
RLADDSUBFIX(ptr); if (!ascii_isdigit(firstdigit) && !(doalp && ASCII_ISALPHA(firstdigit))) {
if ((!ascii_isdigit(firstdigit) && !(doalp && ASCII_ISALPHA(firstdigit)))
|| u_save_cursor() != OK) {
beep_flush(); beep_flush();
return FAIL; goto theend;
} }
// get ptr again, because u_save() may have changed it
ptr = get_cursor_line_ptr();
RLADDSUBFIX(ptr);
if (doalp && ASCII_ISALPHA(firstdigit)) { if (doalp && ASCII_ISALPHA(firstdigit)) {
// decrement or increment alphabetic character // decrement or increment alphabetic character
if (command == Ctrl_X) { if (op_type == OP_NR_SUB) {
if (CharOrd(firstdigit) < Prenum1) { if (CharOrd(firstdigit) < Prenum1) {
if (isupper(firstdigit)) { if (isupper(firstdigit)) {
firstdigit = 'A'; firstdigit = 'A';
@@ -4330,28 +4453,44 @@ int do_addsub(int command, linenr_T Prenum1)
} }
} }
curwin->w_cursor.col = col; curwin->w_cursor.col = col;
if (!did_change) {
startpos = curwin->w_cursor;
}
did_change = true;
(void)del_char(false); (void)del_char(false);
ins_char(firstdigit); ins_char(firstdigit);
endpos = curwin->w_cursor;
curwin->w_cursor.col = col;
} else { } else {
negative = false; if (col > 0 && ptr[col - 1] == '-' && !visual) {
if (col > 0 && ptr[col - 1] == '-') { // negative number // negative number
--col; col--;
negative = true; negative = true;
} }
// get the number value (unsigned) // get the number value (unsigned)
vim_str2nr(ptr + col, &pre, &length, dobin, dooct, dohex, NULL, &n); if (visual && VIsual_mode != 'V') {
maxlen = (curbuf->b_visual.vi_curswant == MAXCOL
? (int)STRLEN(ptr) - col
: length);
}
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 // ignore leading '-' for hex, octal and bin numbers
if (pre && negative) { if (pre && negative) {
++col; col++;
--length; length--;
negative = false; negative = false;
} }
// add or subtract // add or subtract
subtract = false; subtract = false;
if (command == Ctrl_X) { if (op_type == OP_NR_SUB) {
subtract ^= true; subtract ^= true;
} }
if (negative) { if (negative) {
@@ -4370,7 +4509,8 @@ int do_addsub(int command, linenr_T Prenum1)
n = 1 + (n ^ (unsigned long)-1); n = 1 + (n ^ (unsigned long)-1);
negative ^= true; negative ^= true;
} }
} else { /* add */ } else {
// add
if (n < oldn) { if (n < oldn) {
n = (n ^ (unsigned long)-1); n = (n ^ (unsigned long)-1);
negative ^= true; negative ^= true;
@@ -4381,15 +4521,25 @@ int do_addsub(int command, linenr_T Prenum1)
} }
} }
if (visual && !was_positive && !negative && col > 0) {
// need to remove the '-'
col--;
length++;
}
// Delete the old number. // Delete the old number.
curwin->w_cursor.col = col; curwin->w_cursor.col = col;
if (!did_change) {
startpos = curwin->w_cursor;
}
did_change = true;
todel = length; todel = length;
c = gchar_cursor(); c = gchar_cursor();
// Don't include the '-' in the length, only the length of the part // Don't include the '-' in the length, only the length of the part
// after it is kept the same. // after it is kept the same.
if (c == '-') { if (c == '-') {
--length; length--;
} }
while (todel-- > 0) { while (todel-- > 0) {
if (c < 0x100 && isalpha(c)) { if (c < 0x100 && isalpha(c)) {
@@ -4405,47 +4555,52 @@ int do_addsub(int command, linenr_T Prenum1)
} }
// Prepare the leading characters in buf1[]. // Prepare the leading characters in buf1[].
// When there are many leading zeros it could be very long. Allocate // When there are many leading zeros it could be very long.
// a bit too much. // Allocate a bit too much.
buf1 = xmalloc(length + NUMBUFLEN); buf1 = xmalloc(length + NUMBUFLEN);
if (buf1 == NULL) {
goto theend;
}
ptr = buf1; ptr = buf1;
if (negative) { if (negative && (!visual || (visual && was_positive))) {
*ptr++ = '-'; *ptr++ = '-';
} }
if (pre) { if (pre) {
*ptr++ = '0'; *ptr++ = '0';
--length; length--;
} }
if (pre == 'b' || pre == 'B' || if (pre == 'b' || pre == 'B' ||
pre == 'x' || pre == 'X') { pre == 'x' || pre == 'X') {
*ptr++ = pre; *ptr++ = pre;
--length; length--;
} }
// Put the number characters in buf2[]. // Put the number characters in buf2[].
if (pre == 'b' || pre == 'B') { if (pre == 'b' || pre == 'B') {
size_t bits = 0; size_t bits = 0;
size_t pos = 0; size_t i = 0;
// leading zeros // leading zeros
for (bits = 8 * sizeof(unsigned long); bits > 0; bits--) { for (bits = 8 * sizeof(n); bits > 0; bits--) {
if ((n >> (bits - 1)) & 0x1) { break; } if ((n >> (bits - 1)) & 0x1) {
break;
}
} }
while (bits > 0) { while (bits > 0) {
buf2[pos++] = ((n >> --bits) & 0x1) ? '1' : '0'; buf2[i++] = ((n >> --bits) & 0x1) ? '1' : '0';
} }
buf2[pos] = '\0'; buf2[i] = '\0';
} else if (pre == 0) { } else if (pre == 0) {
snprintf((char *)buf2, NUMBUFLEN, "%" PRIu64, (uint64_t)n); vim_snprintf((char *)buf2, ARRAY_SIZE(buf2), "%" PRIu64, (uint64_t)n);
} else if (pre == '0') { } else if (pre == '0') {
snprintf((char *)buf2, NUMBUFLEN, "%" PRIo64, (uint64_t)n); vim_snprintf((char *)buf2, ARRAY_SIZE(buf2), "%" PRIo64, (uint64_t)n);
} else if (pre && hexupper) { } else if (pre && hexupper) {
snprintf((char *)buf2, NUMBUFLEN, "%" PRIX64, (uint64_t)n); vim_snprintf((char *)buf2, ARRAY_SIZE(buf2), "%" PRIX64, (uint64_t)n);
} else { } else {
snprintf((char *)buf2, NUMBUFLEN, "%" PRIx64, (uint64_t)n); vim_snprintf((char *)buf2, ARRAY_SIZE(buf2), "%" PRIx64, (uint64_t)n);
} }
length -= (int)STRLEN(buf2); length -= (int)STRLEN(buf2);
@@ -4460,14 +4615,29 @@ int do_addsub(int command, linenr_T Prenum1)
} }
*ptr = NUL; *ptr = NUL;
STRCAT(buf1, buf2); STRCAT(buf1, buf2);
ins_str(buf1); /* insert the new number */ ins_str(buf1); // insert the new number
xfree(buf1); xfree(buf1);
endpos = curwin->w_cursor;
if (did_change && curwin->w_cursor.col) {
curwin->w_cursor.col--;
}
} }
--curwin->w_cursor.col;
curwin->w_set_curswant = true; if (did_change) {
ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum, true); // set the '[ and '] marks
RLADDSUBFIX(ptr); curbuf->b_op_start = startpos;
return OK; curbuf->b_op_end = endpos;
if (curbuf->b_op_end.col > 0) {
curbuf->b_op_end.col--;
}
}
theend:
if (visual) {
curwin->w_cursor = save_cursor;
}
return did_change;
} }
/* /*

View File

@@ -35,37 +35,39 @@ typedef int (*Indenter)(void);
#define PLUS_REGISTER 38 #define PLUS_REGISTER 38
#define NUM_REGISTERS 39 #define NUM_REGISTERS 39
/* // Operator IDs; The order must correspond to opchars[] in ops.c!
* Operator IDs; The order must correspond to opchars[] in ops.c! #define OP_NOP 0 // no pending operation
*/ #define OP_DELETE 1 // "d" delete operator
#define OP_NOP 0 /* no pending operation */ #define OP_YANK 2 // "y" yank operator
#define OP_DELETE 1 /* "d" delete operator */ #define OP_CHANGE 3 // "c" change operator
#define OP_YANK 2 /* "y" yank operator */ #define OP_LSHIFT 4 // "<" left shift operator
#define OP_CHANGE 3 /* "c" change operator */ #define OP_RSHIFT 5 // ">" right shift operator
#define OP_LSHIFT 4 /* "<" left shift operator */ #define OP_FILTER 6 // "!" filter operator
#define OP_RSHIFT 5 /* ">" right shift operator */ #define OP_TILDE 7 // "g~" switch case operator
#define OP_FILTER 6 /* "!" filter operator */ #define OP_INDENT 8 // "=" indent operator
#define OP_TILDE 7 /* "g~" switch case operator */ #define OP_FORMAT 9 // "gq" format operator
#define OP_INDENT 8 /* "=" indent operator */ #define OP_COLON 10 // ":" colon operator
#define OP_FORMAT 9 /* "gq" format operator */ #define OP_UPPER 11 // "gU" make upper case operator
#define OP_COLON 10 /* ":" colon operator */ #define OP_LOWER 12 // "gu" make lower case operator
#define OP_UPPER 11 /* "gU" make upper case operator */ #define OP_JOIN 13 // "J" join operator, only for Visual mode
#define OP_LOWER 12 /* "gu" make lower case operator */ #define OP_JOIN_NS 14 // "gJ" join operator, only for Visual mode
#define OP_JOIN 13 /* "J" join operator, only for Visual mode */ #define OP_ROT13 15 // "g?" rot-13 encoding
#define OP_JOIN_NS 14 /* "gJ" join operator, only for Visual mode */ #define OP_REPLACE 16 // "r" replace chars, only for Visual mode
#define OP_ROT13 15 /* "g?" rot-13 encoding */ #define OP_INSERT 17 // "I" Insert column, only for Visual mode
#define OP_REPLACE 16 /* "r" replace chars, only for Visual mode */ #define OP_APPEND 18 // "A" Append column, only for Visual mode
#define OP_INSERT 17 /* "I" Insert column, only for Visual mode */ #define OP_FOLD 19 // "zf" define a fold
#define OP_APPEND 18 /* "A" Append column, only for Visual mode */ #define OP_FOLDOPEN 20 // "zo" open folds
#define OP_FOLD 19 /* "zf" define a fold */ #define OP_FOLDOPENREC 21 // "zO" open folds recursively
#define OP_FOLDOPEN 20 /* "zo" open folds */ #define OP_FOLDCLOSE 22 // "zc" close folds
#define OP_FOLDOPENREC 21 /* "zO" open folds recursively */ #define OP_FOLDCLOSEREC 23 // "zC" close folds recursively
#define OP_FOLDCLOSE 22 /* "zc" close folds */ #define OP_FOLDDEL 24 // "zd" delete folds
#define OP_FOLDCLOSEREC 23 /* "zC" close folds recursively */ #define OP_FOLDDELREC 25 // "zD" delete folds recursively
#define OP_FOLDDEL 24 /* "zd" delete folds */ #define OP_FORMAT2 26 // "gw" format operator, keeps cursor pos
#define OP_FOLDDELREC 25 /* "zD" delete folds recursively */ #define OP_FUNCTION 27 // "g@" call 'operatorfunc'
#define OP_FORMAT2 26 /* "gw" format operator, keeps cursor pos */ #define OP_NR_ADD 28 // "<C-A>" Add to the number or alphabetic
#define OP_FUNCTION 27 /* "g@" call 'operatorfunc' */ // 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(). /// Flags for get_reg_contents().
enum GRegFlags { enum GRegFlags {

View File

@@ -1432,7 +1432,7 @@ do_set (
} else if (*arg == '-' || ascii_isdigit(*arg)) { } else if (*arg == '-' || ascii_isdigit(*arg)) {
// Allow negative (for 'undolevels'), octal and // Allow negative (for 'undolevels'), octal and
// hex numbers. // hex numbers.
vim_str2nr(arg, NULL, &i, true, true, true, &value, NULL); vim_str2nr(arg, NULL, &i, STR2NR_ALL, &value, NULL, 0);
if (arg[i] != NUL && !ascii_iswhite(arg[i])) { if (arg[i] != NUL && !ascii_iswhite(arg[i])) {
errmsg = e_invarg; errmsg = e_invarg;
goto skip; goto skip;

View File

@@ -12910,8 +12910,8 @@ void ex_spelldump(exarg_T *eap)
do_cmdline_cmd("new"); do_cmdline_cmd("new");
// enable spelling locally in the new window // enable spelling locally in the new window
set_option_value((char_u*)"spell", TRUE, (char_u*)"", OPT_LOCAL); set_option_value((char_u*)"spell", true, (char_u*)"", OPT_LOCAL);
set_option_value((char_u*)"spl", dummy, spl, OPT_LOCAL); set_option_value((char_u*)"spl", dummy, spl, OPT_LOCAL);
xfree(spl); xfree(spl);
if (!bufempty() || !buf_valid(curbuf)) if (!bufempty() || !buf_valid(curbuf))

View File

@@ -28,6 +28,7 @@ SCRIPTS := \
test_charsearch.out \ test_charsearch.out \
test_close_count.out \ test_close_count.out \
test_command_count.out \ test_command_count.out \
test_marks.out \
NEW_TESTS = NEW_TESTS =
@@ -131,7 +132,7 @@ test1.out: .gdbinit test1.in
# Check if the test.out file matches test.ok. # Check if the test.out file matches test.ok.
@/bin/sh -c "if test -f test.out; then \ @/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; \ mv -f test.out $*.out; \
else \ else \
echo $* FAILED >> test.log; \ echo $* FAILED >> test.log; \

View File

@@ -0,0 +1,34 @@
Tests for marks.
STARTTEST
:so small.vim
:" test that a deleted mark is restored after delete-undo-redo-undo
:/^\t/+1
:set nocp viminfo+=nviminfo
madduu
:let a = string(getpos("'a"))
:$put ='Mark after delete-undo-redo-undo: '.a
:''
ENDTEST
textline A
textline B
textline C
STARTTEST
:" test that CTRL-A and CTRL-X updates last changed mark '[, '].
:/^123/
:execute "normal! \<C-A>`[v`]rAjwvjw\<C-X>`[v`]rX"
ENDTEST
CTRL-A CTRL-X:
123 123 123
123 123 123
123 123 123
STARTTEST
:g/^STARTTEST/.,/^ENDTEST/d
:wq! test.out
ENDTEST
Results:

View File

@@ -0,0 +1,16 @@
Tests for marks.
textline A
textline B
textline C
CTRL-A CTRL-X:
AAA 123 123
123 XXXXXXX
XXX 123 123
Results:
Mark after delete-undo-redo-undo: [0, 15, 2, 0]

View File

@@ -2222,12 +2222,17 @@ static void u_undoredo(int undo)
/* /*
* restore marks from before undo/redo * restore marks from before undo/redo
*/ */
for (i = 0; i < NMARKS; ++i) for (i = 0; i < NMARKS; ++i) {
if (curhead->uh_namedm[i].mark.lnum != 0) { if (curhead->uh_namedm[i].mark.lnum != 0) {
free_fmark(curbuf->b_namedm[i]); free_fmark(curbuf->b_namedm[i]);
curbuf->b_namedm[i] = curhead->uh_namedm[i]; curbuf->b_namedm[i] = curhead->uh_namedm[i];
curhead->uh_namedm[i] = namedm[i];
} }
if (namedm[i].mark.lnum != 0) {
curhead->uh_namedm[i] = namedm[i];
} else {
curhead->uh_namedm[i].mark.lnum = 0;
}
}
if (curhead->uh_visual.vi_start.lnum != 0) { if (curhead->uh_visual.vi_start.lnum != 0) {
curbuf->b_visual = curhead->uh_visual; curbuf->b_visual = curhead->uh_visual;
curhead->uh_visual = visualinfo; curhead->uh_visual = visualinfo;

View File

@@ -73,12 +73,40 @@ static int included_patches[] = {
1089,
1088,
1087,
// 1086,
1085,
1084,
// 1083,
// 1082,
1081, 1081,
// 1080,
// 1079,
// 1078,
// 1077,
1076,
// 1075,
// 1074,
// 1073,
1072,
// 1071,
// 1070,
// 1069,
// 1068,
// 1067,
// 1066,
1065,
// 1064,
// 1063,
// 1062,
// 1061,
// 1060,
// 1059,
// 1058,
// 1057,
// 1056,
1055, 1055,
// 1054, // 1054,
// 1053, // 1053,
@@ -105,9 +133,9 @@ static int included_patches[] = {
1032, 1032,
// 1031, // 1031,
// 1030, // 1030,
// 1029, 1029,
// 1028, // 1028,
// 1027, 1027,
// 1026, // 1026,
// 1025, // 1025,
// 1024, // 1024,
@@ -286,7 +314,7 @@ static int included_patches[] = {
// 851 NA // 851 NA
// 850 NA // 850 NA
849, 849,
// 848, 848,
// 847, // 847,
// 846 NA // 846 NA
// 845, // 845,
@@ -311,7 +339,7 @@ static int included_patches[] = {
826, 826,
// 825, // 825,
// 824 NA // 824 NA
// 823, 823,
// 822, // 822,
// 821, // 821,
// 820, // 820,
@@ -327,8 +355,8 @@ static int included_patches[] = {
// 810, // 810,
809, 809,
// 808 NA // 808 NA
// 807, 807,
// 806, 806,
// 805, // 805,
// 804, // 804,
803, 803,
@@ -352,11 +380,11 @@ static int included_patches[] = {
785, 785,
784, 784,
// 783 NA // 783 NA
// 782, 782,
781, 781,
// 780 NA 780,
// 779, 779,
// 778, 778,
// 777 NA // 777 NA
776, 776,
775, 775,
@@ -369,8 +397,8 @@ static int included_patches[] = {
// 768, // 768,
// 767, // 767,
// 766 NA // 766 NA
// 765, 765,
// 764, 764,
// 763 NA // 763 NA
// 762 NA // 762 NA
// 761 NA // 761 NA
@@ -380,7 +408,7 @@ static int included_patches[] = {
// 757 NA // 757 NA
// 756 NA // 756 NA
// 755, // 755,
// 754, 754,
753, 753,
// 752, // 752,
// 751 NA // 751 NA
@@ -500,7 +528,7 @@ static int included_patches[] = {
637, 637,
636, 636,
635, 635,
// 634, 634,
633, 633,
// 632 NA // 632 NA
631, 631,

View File

@@ -35,7 +35,15 @@ Error: configure did not run properly.Check auto/config.log.
#include "nvim/os/os_defs.h" /* bring lots of system header files */ #include "nvim/os/os_defs.h" /* bring lots of system header files */
#define NUMBUFLEN 65 // length of a buffer to store a number in ASCII /// length of a buffer to store a number in ASCII (64 bits binary + NUL)
#define NUMBUFLEN 65
// flags for vim_str2nr()
#define STR2NR_BIN 1
#define STR2NR_OCT 2
#define STR2NR_HEX 4
#define STR2NR_ALL (STR2NR_BIN + STR2NR_OCT + STR2NR_HEX)
#define STR2NR_FORCE 8 // only when ONE of the above is used
#define MAX_TYPENR 65535 #define MAX_TYPENR 65535

View File

@@ -600,39 +600,72 @@ describe(':sort', function()
eq('Vim(sort):E474: Invalid argument', eval('tmpvar')) eq('Vim(sort):E474: Invalid argument', eval('tmpvar'))
expect(text) expect(text)
end) end)
it('binary', function() it('binary', function()
insert([[ insert([[
0b111000 0b111000
0b101100 0b101100
0b101001 0b101001
0b101001 0b101001
0b101000 0b101000
0b000000 0b000000
0b001000 0b001000
0b010000 0b010000
0b101000 0b101000
0b100000 0b100000
0b101010 0b101010
0b100010 0b100010
0b100100 0b100100
0b100010]]) 0b100010]])
execute([[sort b]]) execute([[sort b]])
expect([[ expect([[
0b000000 0b000000
0b001000 0b001000
0b010000 0b010000
0b100000 0b100000
0b100010 0b100010
0b100010 0b100010
0b100100 0b100100
0b101000 0b101000
0b101000 0b101000
0b101001 0b101001
0b101001 0b101001
0b101010 0b101010
0b101100 0b101100
0b111000]]) 0b111000]])
end) end)
it('binary with leading characters', function()
insert([[
0b100010
0b010000
0b101001
b0b101100
0b100010
0b100100
a0b001000
0b101000
0b101000
a0b101001
ab0b100000
0b101010
0b000000
b0b111000]])
execute([[sort b]])
expect([[
0b000000
a0b001000
0b010000
ab0b100000
0b100010
0b100010
0b100100
0b101000
0b101000
0b101001
a0b101001
0b101010
b0b101100
b0b111000]])
end)
end) end)

View File

@@ -31,8 +31,6 @@ describe("spell checking with 'encoding' set to utf-8", function()
RAR ? RAR ?
BAD ! BAD !
#NOSPLITSUGS
PFX I N 1 PFX I N 1
PFX I 0 in . PFX I 0 in .
@@ -92,8 +90,6 @@ describe("spell checking with 'encoding' set to utf-8", function()
RAR ? RAR ?
BAD ! BAD !
#NOSPLITSUGS
PFX I N 1 PFX I N 1
PFX I 0 in . PFX I 0 in .
@@ -300,6 +296,24 @@ describe("spell checking with 'encoding' set to utf-8", function()
tail/123 tail/123
middle/77,1 middle/77,1
]]) ]])
write_latin1('Xtest8.aff', [[
SET ISO8859-1
NOSPLITSUGS
]])
write_latin1('Xtest8.dic', [[
1234
foo
bar
faabar
]])
write_latin1('Xtest9.aff', [[
]])
write_latin1('Xtest9.dic', [[
1234
foo
bar
]])
write_latin1('Xtest-sal.aff', [[ write_latin1('Xtest-sal.aff', [[
SET ISO8859-1 SET ISO8859-1
TRY esianrtolcdugmphbyfvkwjkqxz-ëéèêïîäàâöüû'ESIANRTOLCDUGMPHBYFVKWJKQXZ TRY esianrtolcdugmphbyfvkwjkqxz-ëéèêïîäàâöüû'ESIANRTOLCDUGMPHBYFVKWJKQXZ
@@ -314,8 +328,6 @@ describe("spell checking with 'encoding' set to utf-8", function()
RAR ? RAR ?
BAD ! BAD !
#NOSPLITSUGS
PFX I N 1 PFX I N 1
PFX I 0 in . PFX I 0 in .
@@ -483,6 +495,10 @@ describe("spell checking with 'encoding' set to utf-8", function()
os.remove('Xtest6.dic') os.remove('Xtest6.dic')
os.remove('Xtest7.aff') os.remove('Xtest7.aff')
os.remove('Xtest7.dic') os.remove('Xtest7.dic')
os.remove('Xtest8.aff')
os.remove('Xtest8.dic')
os.remove('Xtest9.aff')
os.remove('Xtest9.dic')
end) end)
-- Function to test .aff/.dic with list of good and bad words. This was a -- Function to test .aff/.dic with list of good and bad words. This was a
@@ -940,4 +956,46 @@ describe("spell checking with 'encoding' set to utf-8", function()
leadprobar leadprobar
['leadprebar', 'lead prebar', 'leadbar']]=]) ['leadprebar', 'lead prebar', 'leadbar']]=])
end) end)
it('part 8-8', function()
insert([[
8good: foo bar faabar
bad: foobar barfoo
badend
]])
-- NOSPLITSUGS
test_one(8, 8)
-- Assert buffer contents.
execute('1,/^test 8-8/-1d')
expect([=[
test 8-8
# file: Xtest.utf-8.spl
bar
faabar
foo
-------
bad
['bar', 'foo']
foobar
['faabar', 'foo bar', 'bar']
barfoo
['bar foo', 'bar', 'foo']]=])
end)
it('part 9-9', function()
insert([[
9good: 0b1011 0777 1234 0x01ff
badend
]])
-- NOSPLITSUGS
test_one(9, 9)
-- Assert buffer contents.
execute('1,/^test 9-9/-1d')
expect([=[
test 9-9
# file: Xtest.utf-8.spl
bar
foo
-------]=])
end)
end) end)

View File

@@ -0,0 +1,723 @@
-- Tests for using Ctrl-A/Ctrl-X on visual selections
local helpers = require('test.functional.helpers')
local source, execute = helpers.source, helpers.execute
local call, clear = helpers.call, helpers.clear
local eq, nvim = helpers.eq, helpers.meths
describe('Ctrl-A/Ctrl-X on visual selections', function()
before_each(function()
clear()
source([=[
" 1) Ctrl-A on visually selected number
" Text:
" foobar-10
" Expected:
" 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
func Test_visual_increment_01()
call setline(1, repeat(["foobaar-10"], 5))
call cursor(1, 1)
exec "norm! \<C-A>"
call assert_equal("foobaar-9", getline('.'))
call assert_equal([0, 1, 9, 0], getpos('.'))
call cursor(2, 1)
exec "norm! f-v$\<C-A>"
call assert_equal("foobaar-9", getline('.'))
call assert_equal([0, 2, 8, 0], getpos('.'))
call cursor(3, 1)
exec "norm! f1v$\<C-A>"
call assert_equal("foobaar-11", getline('.'))
call assert_equal([0, 3, 9, 0], getpos('.'))
call cursor(4, 1)
exec "norm! f-v$\<C-X>"
call assert_equal("foobaar-11", getline('.'))
call assert_equal([0, 4, 8, 0], getpos('.'))
call cursor(5, 1)
exec "norm! f1v$\<C-X>"
call assert_equal("foobaar-9", getline('.'))
call assert_equal([0, 5, 9, 0], getpos('.'))
endfunc
" 2) Ctrl-A on visually selected lines
" Text:
" 10
" 20
" 30
" 40
"
" Expected:
" 1) Ctrl-A on visually selected lines:
" 11
" 21
" 31
" 41
"
" 2) Ctrl-X on visually selected lines:
" 9
" 19
" 29
" 39
func Test_visual_increment_02()
call setline(1, ["10", "20", "30", "40"])
exec "norm! GV3k$\<C-A>"
call assert_equal(["11", "21", "31", "41"], getline(1, '$'))
call assert_equal([0, 1, 1, 0], getpos('.'))
call setline(1, ["10", "20", "30", "40"])
exec "norm! GV3k$\<C-X>"
call assert_equal(["9", "19", "29", "39"], getline(1, '$'))
call assert_equal([0, 1, 1, 0], getpos('.'))
endfunc
" 3) g Ctrl-A on visually selected lines, with non-numbers in between
" Text:
" 10
"
" 20
"
" 30
"
" 40
"
" Expected:
" 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
func Test_visual_increment_03()
call setline(1, ["10", "", "20", "", "30", "", "40"])
exec "norm! GV6k2g\<C-A>"
call assert_equal(["12", "", "24", "", "36", "", "48"], getline(1, '$'))
call assert_equal([0, 1, 1, 0], getpos('.'))
call setline(1, ["10", "", "20", "", "30", "", "40"])
exec "norm! GV6k2g\<C-X>"
call assert_equal(["8", "", "16", "", "24", "", "32"], getline(1, '$'))
call assert_equal([0, 1, 1, 0], getpos('.'))
endfunc
" 4) Ctrl-A on non-number
" Text:
" foobar-10
" Expected:
" 1) visually select foobar:
" foobar-10
func Test_visual_increment_04()
call setline(1, ["foobar-10"])
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('.'))
endfunc
" 5) g<Ctrl-A> on letter
" Test:
" a
" a
" a
" a
" Expected:
" 1) g Ctrl-A on visually selected lines
" b
" c
" d
" e
func Test_visual_increment_05()
set nrformats+=alpha
call setline(1, repeat(["a"], 4))
exec "norm! GV3kg\<C-A>"
call assert_equal(["b", "c", "d", "e"], getline(1, '$'))
call assert_equal([0, 1, 1, 0], getpos('.'))
endfunc
" 6) g<Ctrl-A> on letter
" Test:
" z
" z
" z
" z
" Expected:
" 1) g Ctrl-X on visually selected lines
" y
" x
" w
" v
func Test_visual_increment_06()
set nrformats+=alpha
call setline(1, repeat(["z"], 4))
exec "norm! GV3kg\<C-X>"
call assert_equal(["y", "x", "w", "v"], getline(1, '$'))
call assert_equal([0, 1, 1, 0], getpos('.'))
endfunc
" 7) <Ctrl-A> on letter
" Test:
" 2
" 1
" 0
" -1
" -2
"
" Expected:
" 1) Ctrl-A on visually selected lines
" 3
" 2
" 1
" 0
" -1
"
" 2) Ctrl-X on visually selected lines
" 1
" 0
" -1
" -2
" -3
func Test_visual_increment_07()
call setline(1, ["2", "1", "0", "-1", "-2"])
exec "norm! GV4k\<C-A>"
call assert_equal(["3", "2", "1", "0", "-1"], getline(1, '$'))
call assert_equal([0, 1, 1, 0], getpos('.'))
call setline(1, ["2", "1", "0", "-1", "-2"])
exec "norm! GV4k\<C-X>"
call assert_equal(["1", "0", "-1", "-2", "-3"], getline(1, '$'))
call assert_equal([0, 1, 1, 0], getpos('.'))
endfunc
" 8) Block increment on 0x9
" Text:
" 0x9
" 0x9
" Expected:
" 1) Ctrl-A on visually block selected region (cursor at beginning):
" 0xa
" 0xa
" 2) Ctrl-A on visually block selected region (cursor at end)
" 0xa
" 0xa
func Test_visual_increment_08()
call setline(1, repeat(["0x9"], 2))
exec "norm! \<C-V>j$\<C-A>"
call assert_equal(["0xa", "0xa"], getline(1, '$'))
call assert_equal([0, 1, 1, 0], getpos('.'))
call setline(1, repeat(["0x9"], 2))
exec "norm! gg$\<C-V>+\<C-A>"
call assert_equal(["0xa", "0xa"], getline(1, '$'))
call assert_equal([0, 1, 1, 0], getpos('.'))
endfunc
" 9) Increment and redo
" Text:
" 2
" 2
"
" 3
" 3
"
" Expected:
" 1) 2 Ctrl-A on first 2 visually selected lines
" 4
" 4
" 2) redo (.) on 3
" 5
" 5
func Test_visual_increment_09()
call setline(1, ["2", "2", "", "3", "3", ""])
exec "norm! ggVj2\<C-A>"
call assert_equal(["4", "4", "", "3", "3", ""], getline(1, '$'))
call assert_equal([0, 1, 1, 0], getpos('.'))
exec "norm! 3j."
call assert_equal(["4", "4", "", "5", "5", ""], getline(1, '$'))
call assert_equal([0, 4, 1, 0], getpos('.'))
endfunc
" 10) sequentially decrement 1
" Text:
" 1
" 1
" 1
" 1
" Expected:
" 1) g Ctrl-X on visually selected lines
" 0
" -1
" -2
" -3
func Test_visual_increment_10()
call setline(1, repeat(["1"], 4))
exec "norm! GV3kg\<C-X>"
call assert_equal(["0", "-1", "-2", "-3"], getline(1, '$'))
call assert_equal([0, 1, 1, 0], getpos('.'))
endfunc
" 11) visually block selected indented lines
" Text:
" 1
" 1
" 1
" 1
" Expexted:
" 1) g Ctrl-A on block selected indented lines
" 2
" 1
" 3
" 4
func Test_visual_increment_11()
call setline(1, [" 1", "1", " 1", " 1"])
exec "norm! f1\<C-V>3jg\<C-A>"
call assert_equal([" 2", "1", " 3", " 4"], getline(1, '$'))
call assert_equal([0, 1, 5, 0], getpos('.'))
endfunc
" 12) visually selected several columns
" Text:
" 0 0
" 0 0
" 0 0
" Expected:
" 1) 'v' select last zero and first zeroes
" 0 1
" 1 0
" 1 0
func Test_visual_increment_12()
call setline(1, repeat(["0 0"], 3))
exec "norm! $v++\<C-A>"
call assert_equal(["0 1", "1 0", "1 0"], getline(1, '$'))
call assert_equal([0, 1, 3, 0], getpos('.'))
endfunc
" 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
func Test_visual_increment_13()
call setline(1, ["max: 100px", "max: 200px", "max: 300px", "max: 400px"])
exec "norm! f1\<C-V>l2j\<C-A>"
call assert_equal(["max: 110px", "max: 210px", "max: 310px", "max: 400px"], getline(1, '$'))
call assert_equal([0, 1, 6, 0], getpos('.'))
call setline(1, ["max: 100px", "max: 200px", "max: 300px", "max: 400px"])
exec "norm! ggf1\<C-V>l2j\<C-X>"
call assert_equal(["max: 90px", "max: 190px", "max: 290px", "max: 400px"], getline(1, '$'))
call assert_equal([0, 1, 6, 0], getpos('.'))
endfunc
" 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
func Test_visual_increment_14()
call setline(1, repeat(["1 1"], 2))
exec "norm! G\<C-V>k\<C-A>w."
call assert_equal(["2 2", "2 2"], getline(1, '$'))
call assert_equal([0, 1, 3, 0], getpos('.'))
endfunc
" 15) block select single numbers
" Text:
" 101
" Expected:
" 1) Ctrl-a on visually selected zero
" 111
func Test_visual_increment_15()
call setline(1, ["101"])
exec "norm! lv\<C-A>"
call assert_equal(["111"], getline(1, '$'))
call assert_equal([0, 1, 2, 0], getpos('.'))
endfunc
" 16) increment right aligned numbers
" Text:
" 1
" 19
" 119
" Expected:
" 1) Ctrl-a on line selected region
" 2
" 20
" 120
func Test_visual_increment_16()
call setline(1, [" 1", " 19", " 119"])
exec "norm! VG\<C-A>"
call assert_equal([" 2", " 20", " 120"], getline(1, '$'))
call assert_equal([0, 1, 1, 0], getpos('.'))
endfunc
" 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
func Test_visual_increment_17()
call setline(1, [" 100", " 1", "", " 100", " 1"])
exec "norm! \<C-V>j$\<C-A>2j."
call assert_equal([" 101", " 2", "", " 101", " 1"], getline(1, '$'))
call assert_equal([0, 3, 1, 0], getpos('.'))
endfunc
" 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
func Test_visual_increment_18()
call setline(1, repeat(["0"], 4))
exec "norm! GV3kg\<C-A>"
exec "norm! .."
call assert_equal(["3", "6", "9", "12"], getline(1, '$'))
call assert_equal([0, 1, 1, 0], getpos('.'))
endfunc
" 19) increment on number with nrformat including alpha
" Text:
" 1
" 1a
"
" Expected:
" 1) <Ctrl-V>j$ <ctrl-a>
" 2
" 2a
func Test_visual_increment_19()
set nrformats+=alpha
call setline(1, ["1", "1a"])
exec "norm! \<C-V>G$\<C-A>"
call assert_equal(["2", "2a"], getline(1, '$'))
call assert_equal([0, 1, 1, 0], getpos('.'))
endfunc
" 20) increment a single letter
" Text:
" a
"
" Expected:
" 1) <Ctrl-a> and cursor is on a
" b
func Test_visual_increment_20()
set nrformats+=alpha
call setline(1, ["a"])
exec "norm! \<C-A>"
call assert_equal(["b"], getline(1, '$'))
call assert_equal([0, 1, 1, 0], getpos('.'))
endfunc
" 21) block-wise increment on part of hexadecimal
" Text:
" 0x123456
"
" Expected:
" 1) Ctrl-V f3 <ctrl-a>
" 0x124456
func Test_visual_increment_21()
call setline(1, ["0x123456"])
exec "norm! \<C-V>f3\<C-A>"
call assert_equal(["0x124456"], getline(1, '$'))
call assert_equal([0, 1, 1, 0], getpos('.'))
endfunc
" 22) Block increment on 0b0
" Text:
" 0b1
" 0b1
" Expected:
" 1) Ctrl-A on visually block selected region (cursor at beginning):
" 0b10
" 0b10
" 2) Ctrl-A on visually block selected region (cursor at end)
" 0b10
" 0b10
func Test_visual_increment_22()
call setline(1, repeat(["0b1"], 2))
exec "norm! \<C-V>j$\<C-A>"
call assert_equal(repeat(["0b10"], 2), getline(1, '$'))
call assert_equal([0, 1, 1, 0], getpos('.'))
call setline(1, repeat(["0b1"], 2))
exec "norm! $\<C-V>+\<C-A>"
call assert_equal(repeat(["0b10"], 2), getline(1, '$'))
call assert_equal([0, 1, 1, 0], getpos('.'))
endfunc
" 23) block-wise increment on part of binary
" Text:
" 0b1001
"
" Expected:
" 1) Ctrl-V 5l <ctrl-a>
" 0b1011
func Test_visual_increment_23()
call setline(1, ["0b1001"])
exec "norm! \<C-V>4l\<C-A>"
call assert_equal(["0b1011"], getline(1, '$'))
call assert_equal([0, 1, 1, 0], getpos('.'))
endfunc
" 24) increment hexadecimal
" Text:
" 0x0b1001
"
" Expected:
" 1) <ctrl-a>
" 0x0b1002
func Test_visual_increment_24()
call setline(1, ["0x0b1001"])
exec "norm! \<C-V>$\<C-A>"
call assert_equal(["0x0b1002"], getline(1, '$'))
call assert_equal([0, 1, 1, 0], getpos('.'))
endfunc
" 25) increment binary with nrformats including alpha
" Text:
" 0b1001a
"
" Expected:
" 1) <ctrl-a>
" 0b1010a
func Test_visual_increment_25()
set nrformats+=alpha
call setline(1, ["0b1001a"])
exec "norm! \<C-V>$\<C-A>"
call assert_equal(["0b1010a"], getline(1, '$'))
call assert_equal([0, 1, 1, 0], getpos('.'))
endfunc
" 26) increment binary with 32 bits
" Text:
" 0b11111111111111111111111111111110
"
" Expected:
" 1) <ctrl-a>
" 0b11111111111111111111111111111111
func Test_visual_increment_26()
set nrformats+=alpha
call setline(1, ["0b11111111111111111111111111111110"])
exec "norm! \<C-V>$\<C-A>"
call assert_equal(["0b11111111111111111111111111111111"], getline(1, '$'))
call assert_equal([0, 1, 1, 0], getpos('.'))
set nrformats-=alpha
endfunc
" 27) increment with 'rightreft', if supported
func Test_visual_increment_27()
if exists('+rightleft')
set rightleft
call setline(1, ["1234 56"])
exec "norm! $\<C-A>"
call assert_equal(["1234 57"], getline(1, '$'))
call assert_equal([0, 1, 7, 0], getpos('.'))
exec "norm! \<C-A>"
call assert_equal(["1234 58"], getline(1, '$'))
call assert_equal([0, 1, 7, 0], getpos('.'))
set norightleft
endif
endfunc
" 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
"
" Expected:
" 1) f2 Ctrl-V jl <ctrl-a>, repeat twice afterwards with .
" 1 26
" 4 59
"
" Try with and without indent.
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))
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))
endfunc
" Check redo after the normal mode increment
func Test_visual_increment_38()
exec "norm! i10\<ESC>5\<C-A>."
call assert_equal(["20"], getline(1, '$'))
call assert_equal([0, 1, 2, 0], getpos('.'))
endfunc
]=])
end)
for i = 1, 38 do
local id = string.format('%02d', i)
it('works on Test ' .. id, function()
execute('set nrformats&vi') -- &vi makes Vim compatible
call('Test_visual_increment_' .. id)
eq({}, nvim.get_vvar('errors'))
end)
end
end)