vim-patch:9.1.0537: signed number detection for CTRL-X/A can be improved (#29590)

Problem:  signed number detection for CTRL-X/A can be improved
          (Chris Patuzzo)
Solution: Add the new "blank" value for the 'nrformat' setting. This
          will make Vim assume a signed number only if there is a blank
          in front of the sign.
          (distobs)

fixes: vim/vim#15033
closes: vim/vim#15110

25ac6d67d9

Co-authored-by: distobs <cuppotatocake@gmail.com>
This commit is contained in:
zeertzjq
2024-07-07 06:32:54 +08:00
committed by GitHub
parent 7a54d707fa
commit 5da9b49b19
6 changed files with 102 additions and 13 deletions

View File

@@ -4430,6 +4430,20 @@ A jump table for the options with a short description can be found at |Q_op|.
(without "unsigned" it would become "9-2019"). (without "unsigned" it would become "9-2019").
Using CTRL-X on "0" or CTRL-A on "18446744073709551615" Using CTRL-X on "0" or CTRL-A on "18446744073709551615"
(2^64 - 1) has no effect, overflow is prevented. (2^64 - 1) has no effect, overflow is prevented.
blank If included, treat numbers as signed or unsigned based on
preceding whitespace. If a number with a leading dash has its
dash immediately preceded by a non-whitespace character (i.e.,
not a tab or a " "), the negative sign won't be considered as
part of the number. For example:
Using CTRL-A on "14" in "Carbon-14" results in "Carbon-15"
(without "blank" it would become "Carbon-13").
Using CTRL-X on "8" in "Carbon -8" results in "Carbon -9"
(because -8 is preceded by whitespace. If "unsigned" was
set, it would result in "Carbon -7").
If this format is included, overflow is prevented as if
"unsigned" were set. If both this format and "unsigned" are
included, "unsigned" will take precedence.
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

@@ -4549,6 +4549,20 @@ vim.go.mouset = vim.go.mousetime
--- (without "unsigned" it would become "9-2019"). --- (without "unsigned" it would become "9-2019").
--- Using CTRL-X on "0" or CTRL-A on "18446744073709551615" --- Using CTRL-X on "0" or CTRL-A on "18446744073709551615"
--- (2^64 - 1) has no effect, overflow is prevented. --- (2^64 - 1) has no effect, overflow is prevented.
--- blank If included, treat numbers as signed or unsigned based on
--- preceding whitespace. If a number with a leading dash has its
--- dash immediately preceded by a non-whitespace character (i.e.,
--- not a tab or a " "), the negative sign won't be considered as
--- part of the number. For example:
--- Using CTRL-A on "14" in "Carbon-14" results in "Carbon-15"
--- (without "blank" it would become "Carbon-13").
--- Using CTRL-X on "8" in "Carbon -8" results in "Carbon -9"
--- (because -8 is preceded by whitespace. If "unsigned" was
--- set, it would result in "Carbon -7").
--- If this format is included, overflow is prevented as if
--- "unsigned" were set. If both this format and "unsigned" are
--- included, "unsigned" will take precedence.
---
--- 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

@@ -4420,6 +4420,7 @@ bool do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
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 bool hexupper = false; // 0xABC static bool hexupper = false; // 0xABC
uvarnumber_T n; uvarnumber_T n;
bool blank_unsigned = false; // blank: treat as unsigned?
bool negative = false; bool negative = false;
bool was_positive = true; bool was_positive = true;
bool visual = VIsual_active; bool visual = VIsual_active;
@@ -4430,12 +4431,12 @@ bool 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;
const bool do_hex = vim_strchr(curbuf->b_p_nf, 'x') != NULL; // "heX" const bool do_hex = vim_strchr(curbuf->b_p_nf, 'x') != NULL; // "heX"
const bool do_oct = vim_strchr(curbuf->b_p_nf, 'o') != NULL; // "Octal" const bool do_oct = vim_strchr(curbuf->b_p_nf, 'o') != NULL; // "Octal"
const bool do_bin = vim_strchr(curbuf->b_p_nf, 'b') != NULL; // "Bin" const bool do_bin = vim_strchr(curbuf->b_p_nf, 'b') != NULL; // "Bin"
const bool do_alpha = 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; // "Unsigned"
const bool do_unsigned = vim_strchr(curbuf->b_p_nf, 'u') != NULL; const bool do_blank = vim_strchr(curbuf->b_p_nf, 'k') != NULL; // "blanK"
if (virtual_active(curwin)) { if (virtual_active(curwin)) {
save_coladd = pos->coladd; save_coladd = pos->coladd;
@@ -4532,8 +4533,12 @@ bool 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) { && !do_unsigned) {
negative = true; if (do_blank && col >= 2 && !ascii_iswhite(ptr[col - 2])) {
was_positive = false; blank_unsigned = true;
} else {
negative = true;
was_positive = false;
}
} }
} }
@@ -4579,9 +4584,13 @@ bool do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
&& !utf_head_off(ptr, ptr + col - 1) && !utf_head_off(ptr, ptr + col - 1)
&& !visual && !visual
&& !do_unsigned) { && !do_unsigned) {
// negative number if (do_blank && col >= 2 && !ascii_iswhite(ptr[col - 2])) {
col--; blank_unsigned = true;
negative = true; } else {
// negative number
col--;
negative = true;
}
} }
// get the number value (unsigned) // get the number value (unsigned)
@@ -4638,7 +4647,7 @@ bool do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1)
} }
} }
if (do_unsigned && negative) { if ((do_unsigned || blank_unsigned) && negative) {
if (subtract) { if (subtract) {
// sticking at zero. // sticking at zero.
n = 0; n = 0;

View File

@@ -5717,6 +5717,20 @@ return {
(without "unsigned" it would become "9-2019"). (without "unsigned" it would become "9-2019").
Using CTRL-X on "0" or CTRL-A on "18446744073709551615" Using CTRL-X on "0" or CTRL-A on "18446744073709551615"
(2^64 - 1) has no effect, overflow is prevented. (2^64 - 1) has no effect, overflow is prevented.
blank If included, treat numbers as signed or unsigned based on
preceding whitespace. If a number with a leading dash has its
dash immediately preceded by a non-whitespace character (i.e.,
not a tab or a " "), the negative sign won't be considered as
part of the number. For example:
Using CTRL-A on "14" in "Carbon-14" results in "Carbon-15"
(without "blank" it would become "Carbon-13").
Using CTRL-X on "8" in "Carbon -8" results in "Carbon -9"
(because -8 is preceded by whitespace. If "unsigned" was
set, it would result in "Carbon -7").
If this format is included, overflow is prevented as if
"unsigned" were set. If both this format and "unsigned" are
included, "unsigned" will take precedence.
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

@@ -82,7 +82,7 @@ static char *(p_dip_values[]) = { "filler", "context:", "iblank", "icase",
"closeoff", "hiddenoff", "foldcolumn:", "followwrap", "internal", "closeoff", "hiddenoff", "foldcolumn:", "followwrap", "internal",
"indent-heuristic", "linematch:", "algorithm:", NULL }; "indent-heuristic", "linematch:", "algorithm:", NULL };
static char *(p_dip_algorithm_values[]) = { "myers", "minimal", "patience", "histogram", NULL }; static char *(p_dip_algorithm_values[]) = { "myers", "minimal", "patience", "histogram", NULL };
static char *(p_nf_values[]) = { "bin", "octal", "hex", "alpha", "unsigned", NULL }; static char *(p_nf_values[]) = { "bin", "octal", "hex", "alpha", "unsigned", "blank", 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_cb_values[]) = { "unnamed", "unnamedplus", NULL }; static char *(p_cb_values[]) = { "unnamed", "unnamedplus", NULL };
static char *(p_cmp_values[]) = { "internal", "keepascii", NULL }; static char *(p_cmp_values[]) = { "internal", "keepascii", NULL };

View File

@@ -841,6 +841,44 @@ func Test_increment_unsigned()
set nrformats-=unsigned set nrformats-=unsigned
endfunc endfunc
" Try incrementing/decrementing a number when nrformats contains blank
func Test_increment_blank()
set nrformats+=blank
" Signed
call setline(1, '0')
exec "norm! gg0\<C-X>"
call assert_equal('-1', getline(1))
call setline(1, '3')
exec "norm! gg010\<C-X>"
call assert_equal('-7', getline(1))
call setline(1, '-0')
exec "norm! gg0\<C-X>"
call assert_equal("-1", getline(1))
" Unsigned
" NOTE: 18446744073709551615 == 2^64 - 1
call setline(1, 'a-18446744073709551615')
exec "norm! gg0\<C-A>"
call assert_equal('a-18446744073709551615', getline(1))
call setline(1, 'a-18446744073709551615')
exec "norm! gg0\<C-A>"
call assert_equal('a-18446744073709551615', getline(1))
call setline(1, 'a-18446744073709551614')
exec "norm! gg08\<C-A>"
call assert_equal('a-18446744073709551615', getline(1))
call setline(1, 'a-1')
exec "norm! gg0\<C-A>"
call assert_equal('a-2', getline(1))
set nrformats-=blank
endfunc
func Test_in_decrement_large_number() func Test_in_decrement_large_number()
" NOTE: 18446744073709551616 == 2^64 " NOTE: 18446744073709551616 == 2^64
call setline(1, '18446744073709551616') call setline(1, '18446744073709551616')