mirror of
https://github.com/neovim/neovim.git
synced 2025-10-04 17:06:30 +00:00
Merge pull request #4013 from watiko/vim-increment
Vim patches related to increment and marks
This commit is contained in:
@@ -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.
|
||||||
|
@@ -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.
|
||||||
|
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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:
|
||||||
|
@@ -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 {
|
||||||
|
@@ -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);
|
||||||
|
@@ -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 {
|
||||||
/*
|
/*
|
||||||
|
@@ -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);
|
||||||
|
366
src/nvim/ops.c
366
src/nvim/ops.c
@@ -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,60 +4197,155 @@ 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) {
|
||||||
|
pos = curwin->w_cursor;
|
||||||
|
if (u_save_cursor() == FAIL) {
|
||||||
return;
|
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--;
|
col--;
|
||||||
@@ -4278,7 +4389,7 @@ int do_addsub(int command, linenr_T Prenum1)
|
|||||||
col--;
|
col--;
|
||||||
} else {
|
} else {
|
||||||
// Search forward and then backward to find the start of number.
|
// Search forward and then backward to find the start of number.
|
||||||
col = curwin->w_cursor.col;
|
col = pos->col;
|
||||||
|
|
||||||
while (ptr[col] != NUL
|
while (ptr[col] != NUL
|
||||||
&& !ascii_isdigit(ptr[col])
|
&& !ascii_isdigit(ptr[col])
|
||||||
@@ -4292,23 +4403,35 @@ int do_addsub(int command, linenr_T Prenum1)
|
|||||||
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;
|
|
||||||
ptr = ml_get_buf(curbuf, curwin->w_cursor.lnum, true);
|
if (did_change) {
|
||||||
RLADDSUBFIX(ptr);
|
// set the '[ and '] marks
|
||||||
return OK;
|
curbuf->b_op_start = startpos;
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@@ -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 {
|
||||||
|
@@ -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;
|
||||||
|
@@ -12910,7 +12910,7 @@ 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);
|
||||||
|
|
||||||
|
@@ -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; \
|
||||||
|
34
src/nvim/testdir/test_marks.in
Normal file
34
src/nvim/testdir/test_marks.in
Normal 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:
|
16
src/nvim/testdir/test_marks.ok
Normal file
16
src/nvim/testdir/test_marks.ok
Normal 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]
|
@@ -2222,11 +2222,16 @@ 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];
|
||||||
|
}
|
||||||
|
if (namedm[i].mark.lnum != 0) {
|
||||||
curhead->uh_namedm[i] = namedm[i];
|
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;
|
||||||
|
@@ -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,
|
||||||
|
@@ -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
|
||||||
|
|
||||||
|
@@ -635,4 +635,37 @@ describe(':sort', function()
|
|||||||
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)
|
||||||
|
@@ -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)
|
||||||
|
723
test/functional/legacy/increment_spec.lua
Normal file
723
test/functional/legacy/increment_spec.lua
Normal 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)
|
Reference in New Issue
Block a user