vim-patch:8.2.0860: cannot use CTRL-A and CTRL-X on unsigned numbers

Problem:    Cannot use CTRL-A and CTRL-X on unsigned numbers.
Solution:   Add "unsigned" to 'nrformats'. (Naruhiko Nishino, closes vim/vim#6144)
aaad995f83
This commit is contained in:
Jan Edmund Lazo
2021-04-28 09:06:05 -04:00
parent 65821cc1b9
commit 04a4bbbe56
4 changed files with 94 additions and 29 deletions

View File

@@ -4208,6 +4208,15 @@ A jump table for the options with a short description can be found at |Q_op|.
bin If included, numbers starting with "0b" or "0B" will be bin If included, numbers starting with "0b" or "0B" will be
considered to be binary. Example: Using CTRL-X on considered to be binary. Example: Using CTRL-X on
"0b1000" subtracts one, resulting in "0b0111". "0b1000" subtracts one, resulting in "0b0111".
unsigned If included, numbers are recognized as unsigned. Thus a
leading dash or negative sign won't be considered as part of
the number. Examples:
Using CTRL-X on "2020" in "9-2020" results in "9-2019"
(without "unsigned" it would become "9-2021").
Using CTRL-A on "2020" in "9-2020" results in "9-2021"
(without "unsigned" it would become "9-2019").
Using CTRL-X on "0" or "18446744073709551615" (2^64) has
no effect, overflow is prevented.
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

@@ -4731,12 +4731,7 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
char_u *ptr; char_u *ptr;
int c; int c;
int todel; int todel;
bool dohex;
bool dooct;
bool dobin;
bool doalp;
int firstdigit; int firstdigit;
bool subtract;
bool negative = false; bool negative = false;
bool was_positive = true; bool was_positive = true;
bool visual = VIsual_active; bool visual = VIsual_active;
@@ -4747,10 +4742,12 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
pos_T endpos; pos_T endpos;
colnr_T save_coladd = 0; colnr_T save_coladd = 0;
dohex = (vim_strchr(curbuf->b_p_nf, 'x') != NULL); // "heX" const bool do_hex = vim_strchr(curbuf->b_p_nf, 'x') != NULL; // "heX"
dooct = (vim_strchr(curbuf->b_p_nf, 'o') != NULL); // "Octal" const bool do_oct = vim_strchr(curbuf->b_p_nf, 'o') != NULL; // "Octal"
dobin = (vim_strchr(curbuf->b_p_nf, 'b') != NULL); // "Bin" const bool do_bin = vim_strchr(curbuf->b_p_nf, 'b') != NULL; // "Bin"
doalp = (vim_strchr(curbuf->b_p_nf, 'p') != NULL); // "alPha" const bool do_alpha = vim_strchr(curbuf->b_p_nf, 'p') != NULL; // "alPha"
// "Unsigned"
const bool do_unsigned = vim_strchr(curbuf->b_p_nf, 'u') != NULL;
if (virtual_active()) { if (virtual_active()) {
save_coladd = pos->coladd; save_coladd = pos->coladd;
@@ -4767,21 +4764,21 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
// First check if we are on a hexadecimal number, after the "0x". // First check if we are on a hexadecimal number, after the "0x".
if (!VIsual_active) { if (!VIsual_active) {
if (dobin) { if (do_bin) {
while (col > 0 && ascii_isbdigit(ptr[col])) { while (col > 0 && ascii_isbdigit(ptr[col])) {
col--; col--;
col -= utf_head_off(ptr, ptr + col); col -= utf_head_off(ptr, ptr + col);
} }
} }
if (dohex) { if (do_hex) {
while (col > 0 && ascii_isxdigit(ptr[col])) { while (col > 0 && ascii_isxdigit(ptr[col])) {
col--; col--;
col -= utf_head_off(ptr, ptr + col); col -= utf_head_off(ptr, ptr + col);
} }
} }
if (dobin if (do_bin
&& dohex && do_hex
&& !((col > 0 && !((col > 0
&& (ptr[col] == 'X' || ptr[col] == 'x') && (ptr[col] == 'X' || ptr[col] == 'x')
&& ptr[col - 1] == '0' && ptr[col - 1] == '0'
@@ -4797,13 +4794,13 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
} }
} }
if ((dohex if ((do_hex
&& col > 0 && col > 0
&& (ptr[col] == 'X' || ptr[col] == 'x') && (ptr[col] == 'X' || ptr[col] == 'x')
&& ptr[col - 1] == '0' && ptr[col - 1] == '0'
&& !utf_head_off(ptr, ptr + col - 1) && !utf_head_off(ptr, ptr + col - 1)
&& ascii_isxdigit(ptr[col + 1])) && ascii_isxdigit(ptr[col + 1]))
|| (dobin || (do_bin
&& col > 0 && col > 0
&& (ptr[col] == 'B' || ptr[col] == 'b') && (ptr[col] == 'B' || ptr[col] == 'b')
&& ptr[col - 1] == '0' && ptr[col - 1] == '0'
@@ -4818,13 +4815,13 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
while (ptr[col] != NUL while (ptr[col] != NUL
&& !ascii_isdigit(ptr[col]) && !ascii_isdigit(ptr[col])
&& !(doalp && ASCII_ISALPHA(ptr[col]))) { && !(do_alpha && ASCII_ISALPHA(ptr[col]))) {
col++; col++;
} }
while (col > 0 while (col > 0
&& ascii_isdigit(ptr[col - 1]) && ascii_isdigit(ptr[col - 1])
&& !(doalp && ASCII_ISALPHA(ptr[col]))) { && !(do_alpha && ASCII_ISALPHA(ptr[col]))) {
col--; col--;
} }
} }
@@ -4832,7 +4829,7 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
if (visual) { if (visual) {
while (ptr[col] != NUL && length > 0 && !ascii_isdigit(ptr[col]) while (ptr[col] != NUL && length > 0 && !ascii_isdigit(ptr[col])
&& !(doalp && ASCII_ISALPHA(ptr[col]))) { && !(do_alpha && ASCII_ISALPHA(ptr[col]))) {
int mb_len = utfc_ptr2len(ptr + col); int mb_len = utfc_ptr2len(ptr + col);
col += mb_len; col += mb_len;
@@ -4844,7 +4841,8 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
} }
if (col > pos->col && ptr[col - 1] == '-' if (col > pos->col && ptr[col - 1] == '-'
&& !utf_head_off(ptr, ptr + col - 1)) { && !utf_head_off(ptr, ptr + col - 1)
&& !do_unsigned) {
negative = true; negative = true;
was_positive = false; was_positive = false;
} }
@@ -4852,12 +4850,12 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
// 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];
if (!ascii_isdigit(firstdigit) && !(doalp && ASCII_ISALPHA(firstdigit))) { if (!ascii_isdigit(firstdigit) && !(do_alpha && ASCII_ISALPHA(firstdigit))) {
beep_flush(); beep_flush();
goto theend; goto theend;
} }
if (doalp && ASCII_ISALPHA(firstdigit)) { if (do_alpha && ASCII_ISALPHA(firstdigit)) {
// decrement or increment alphabetic character // decrement or increment alphabetic character
if (op_type == OP_NR_SUB) { if (op_type == OP_NR_SUB) {
if (CharOrd(firstdigit) < Prenum1) { if (CharOrd(firstdigit) < Prenum1) {
@@ -4889,7 +4887,9 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
curwin->w_cursor.col = col; curwin->w_cursor.col = col;
} else { } else {
if (col > 0 && ptr[col - 1] == '-' if (col > 0 && ptr[col - 1] == '-'
&& !utf_head_off(ptr, ptr + col - 1) && !visual) { && !utf_head_off(ptr, ptr + col - 1)
&& !visual
&& !do_unsigned) {
// negative number // negative number
col--; col--;
negative = true; negative = true;
@@ -4903,9 +4903,9 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
} }
vim_str2nr(ptr + col, &pre, &length, vim_str2nr(ptr + col, &pre, &length,
0 + (dobin ? STR2NR_BIN : 0) 0 + (do_bin ? STR2NR_BIN : 0)
+ (dooct ? STR2NR_OCT : 0) + (do_oct ? STR2NR_OCT : 0)
+ (dohex ? STR2NR_HEX : 0), + (do_hex ? STR2NR_HEX : 0),
NULL, &n, maxlen); NULL, &n, maxlen);
// ignore leading '-' for hex, octal and bin numbers // ignore leading '-' for hex, octal and bin numbers
@@ -4916,7 +4916,7 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
} }
// add or subtract // add or subtract
subtract = false; bool subtract = false;
if (op_type == OP_NR_SUB) { if (op_type == OP_NR_SUB) {
subtract ^= true; subtract ^= true;
} }
@@ -4948,6 +4948,17 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
} }
} }
if (do_unsigned && negative) {
if (subtract) {
// sticking at zero.
n = (uvarnumber_T)0;
} else {
// sticking at 2^64 - 1.
n = (uvarnumber_T)(-1);
}
negative = false;
}
if (visual && !was_positive && !negative && col > 0) { if (visual && !was_positive && !negative && col > 0) {
// need to remove the '-' // need to remove the '-'
col--; col--;
@@ -5029,7 +5040,7 @@ int do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
// total length of the number remains the same. // total length of the number remains the same.
// Don't do this when // Don't do this when
// the result may look like an octal number. // the result may look like an octal number.
if (firstdigit == '0' && !(dooct && pre == 0)) { if (firstdigit == '0' && !(do_oct && pre == 0)) {
while (length-- > 0) { while (length-- > 0) {
*ptr++ = '0'; *ptr++ = '0';
} }

View File

@@ -292,7 +292,8 @@ typedef struct vimoption {
static char *(p_ambw_values[]) = { "single", "double", NULL }; static char *(p_ambw_values[]) = { "single", "double", NULL };
static char *(p_bg_values[]) = { "light", "dark", NULL }; static char *(p_bg_values[]) = { "light", "dark", NULL };
static char *(p_nf_values[]) = { "bin", "octal", "hex", "alpha", NULL }; static char *(p_nf_values[]) = { "bin", "octal", "hex", "alpha",
"unsigned", NULL };
static char *(p_ff_values[]) = { FF_UNIX, FF_DOS, FF_MAC, NULL }; static char *(p_ff_values[]) = { FF_UNIX, FF_DOS, FF_MAC, NULL };
static char *(p_wak_values[]) = { "yes", "menu", "no", NULL }; static char *(p_wak_values[]) = { "yes", "menu", "no", NULL };
static char *(p_mousem_values[]) = { "extend", "popup", "popup_setpos", static char *(p_mousem_values[]) = { "extend", "popup", "popup_setpos",

View File

@@ -1,4 +1,4 @@
" Tests for using Ctrl-A/Ctrl-X on visual selections " Tests for using Ctrl-A/Ctrl-X
func SetUp() func SetUp()
new dummy new dummy
@@ -779,6 +779,50 @@ func Test_increment_empty_line()
bwipe! bwipe!
endfunc endfunc
" Try incrementing/decrementing a number when nrformats contains unsigned
func Test_increment_unsigned()
set nrformats+=unsigned
call setline(1, '0')
exec "norm! gg0\<C-X>"
call assert_equal('0', getline(1))
call setline(1, '3')
exec "norm! gg010\<C-X>"
call assert_equal('0', getline(1))
call setline(1, '-0')
exec "norm! gg0\<C-X>"
call assert_equal("-0", getline(1))
call setline(1, '-11')
exec "norm! gg08\<C-X>"
call assert_equal('-3', getline(1))
" NOTE: 18446744073709551615 == 2^64 - 1
call setline(1, '18446744073709551615')
exec "norm! gg0\<C-A>"
call assert_equal('18446744073709551615', getline(1))
call setline(1, '-18446744073709551615')
exec "norm! gg0\<C-A>"
call assert_equal('-18446744073709551615', getline(1))
call setline(1, '-18446744073709551614')
exec "norm! gg08\<C-A>"
call assert_equal('-18446744073709551615', getline(1))
call setline(1, '-1')
exec "norm! gg0\<C-A>"
call assert_equal('-2', getline(1))
call setline(1, '-3')
exec "norm! gg08\<C-A>"
call assert_equal('-11', getline(1))
set nrformats-=unsigned
endfunc
func Test_normal_increment_with_virtualedit() func Test_normal_increment_with_virtualedit()
set virtualedit=all set virtualedit=all