From 25ac6d67d92e0adda53b8d44b81c15031643ca1e Mon Sep 17 00:00:00 2001 From: distobs Date: Sat, 6 Jul 2024 17:50:09 +0200 Subject: patch 9.1.0537: signed number detection for CTRL-X/A can be improved 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: #15033 closes: #15110 Signed-off-by: distobs Signed-off-by: Christian Brabandt --- runtime/doc/options.txt | 16 +++++++++++++++- runtime/doc/version9.txt | 4 +++- src/ops.c | 26 ++++++++++++++++++++------ src/optionstr.c | 2 +- src/testdir/test_increment.vim | 38 ++++++++++++++++++++++++++++++++++++++ src/version.c | 2 ++ 6 files changed, 79 insertions(+), 9 deletions(-) diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 62d6ded111..e9c94aa8e5 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -1,4 +1,4 @@ -*options.txt* For Vim version 9.1. Last change: 2024 Jun 19 +*options.txt* For Vim version 9.1. Last change: 2024 Jul 06 VIM REFERENCE MANUAL by Bram Moolenaar @@ -5918,6 +5918,20 @@ A jump table for the options with a short description can be found at |Q_op|. (without "unsigned" it would become "9-2019"). Using CTRL-X on "0" or CTRL-A on "18446744073709551615" (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 considered decimal. This also happens for numbers that are not recognized as octal or hex. diff --git a/runtime/doc/version9.txt b/runtime/doc/version9.txt index b60f3869a5..d70c3b19e3 100644 --- a/runtime/doc/version9.txt +++ b/runtime/doc/version9.txt @@ -1,4 +1,4 @@ -*version9.txt* For Vim version 9.1. Last change: 2024 Jun 20 +*version9.txt* For Vim version 9.1. Last change: 2024 Jul 06 VIM REFERENCE MANUAL by Bram Moolenaar @@ -41574,6 +41574,8 @@ Changed~ - the default for 'commentstring' contains whitespace padding to have automatic comments look nicer |comment-install| - 'completeopt' is now a |global-local| option. +- 'nrformat' accepts the new "blank" suboption, to determine a signed or + unsigned number based on whitespace in front of a minus sign. *added-9.2* Added ~ diff --git a/src/ops.c b/src/ops.c index eb75c34b1b..dcb48d3233 100644 --- a/src/ops.c +++ b/src/ops.c @@ -2673,6 +2673,8 @@ do_addsub( int do_bin; int do_alpha; int do_unsigned; + int do_blank; + int blank_unsigned = FALSE; // blank: treat as unsigned? int firstdigit; int subtract; int negative = FALSE; @@ -2690,6 +2692,7 @@ do_addsub( do_bin = (vim_strchr(curbuf->b_p_nf, 'b') != NULL); // "Bin" do_alpha = (vim_strchr(curbuf->b_p_nf, 'p') != NULL); // "alPha" do_unsigned = (vim_strchr(curbuf->b_p_nf, 'u') != NULL); // "Unsigned" + do_blank = (vim_strchr(curbuf->b_p_nf, 'k') != NULL); // "blanK" if (virtual_active()) { @@ -2813,8 +2816,13 @@ do_addsub( && (!has_mbyte || !(*mb_head_off)(ptr, ptr + col - 1)) && !do_unsigned) { - negative = TRUE; - was_positive = FALSE; + if (do_blank && col >= 2 && !VIM_ISWHITE(ptr[col - 2])) + blank_unsigned = TRUE; + else + { + negative = TRUE; + was_positive = FALSE; + } } } @@ -2875,10 +2883,16 @@ do_addsub( && !visual && !do_unsigned) { - // negative number - --col; - negative = TRUE; + if (do_blank && col >= 2 && !VIM_ISWHITE(ptr[col - 2])) + blank_unsigned = TRUE; + else + { + // negative number + --col; + negative = TRUE; + } } + // get the number value (unsigned) if (visual && VIsual_mode != 'V') maxlen = (curbuf->b_visual.vi_curswant == MAXCOL @@ -2938,7 +2952,7 @@ do_addsub( negative = FALSE; } - if (do_unsigned && negative) + if ((do_unsigned || blank_unsigned) && negative) { if (subtract) // sticking at zero. diff --git a/src/optionstr.c b/src/optionstr.c index 170d48e9a2..9adb77dff5 100644 --- a/src/optionstr.c +++ b/src/optionstr.c @@ -33,7 +33,7 @@ static char *(p_briopt_values[]) = {"shift:", "min:", "sbr", "list:", "column:", static char *(p_dip_values[]) = {"filler", "context:", "iblank", "icase", "iwhite", "iwhiteall", "iwhiteeol", "horizontal", "vertical", "closeoff", "hiddenoff", "foldcolumn:", "followwrap", "internal", "indent-heuristic", "algorithm:", NULL}; static char *(p_dip_algorithm_values[]) = {"myers", "minimal", "patience", "histogram", NULL}; #endif -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}; #ifdef FEAT_CLIPBOARD // Note: Keep this in sync with did_set_clipboard() diff --git a/src/testdir/test_increment.vim b/src/testdir/test_increment.vim index fdd7c0ce01..3a5f5ee028 100644 --- a/src/testdir/test_increment.vim +++ b/src/testdir/test_increment.vim @@ -840,6 +840,44 @@ func Test_increment_unsigned() set nrformats-=unsigned 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\" + call assert_equal('-1', getline(1)) + + call setline(1, '3') + exec "norm! gg010\" + call assert_equal('-7', getline(1)) + + call setline(1, '-0') + exec "norm! gg0\" + call assert_equal("-1", getline(1)) + + " Unsigned + " NOTE: 18446744073709551615 == 2^64 - 1 + call setline(1, 'a-18446744073709551615') + exec "norm! gg0\" + call assert_equal('a-18446744073709551615', getline(1)) + + call setline(1, 'a-18446744073709551615') + exec "norm! gg0\" + call assert_equal('a-18446744073709551615', getline(1)) + + call setline(1, 'a-18446744073709551614') + exec "norm! gg08\" + call assert_equal('a-18446744073709551615', getline(1)) + + call setline(1, 'a-1') + exec "norm! gg0\" + call assert_equal('a-2', getline(1)) + + set nrformats-=blank +endfunc + func Test_in_decrement_large_number() " NOTE: 18446744073709551616 == 2^64 call setline(1, '18446744073709551616') diff --git a/src/version.c b/src/version.c index 359605b8c2..6b1da3ea7c 100644 --- a/src/version.c +++ b/src/version.c @@ -704,6 +704,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 537, /**/ 536, /**/ -- cgit v1.2.3