changeset 20613:9edb439adbea v8.2.0860

patch 8.2.0860: cannot use CTRL-A and CTRL-X on unsigned numbers Commit: https://github.com/vim/vim/commit/aaad995f8384a77a64efba6846c9c4ac99de0953 Author: Bram Moolenaar <Bram@vim.org> Date: Sun May 31 15:08:59 2020 +0200 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 https://github.com/vim/vim/issues/6144)
author Bram Moolenaar <Bram@vim.org>
date Sun, 31 May 2020 15:15:04 +0200
parents b2ad048307ef
children 78caf677340d
files runtime/doc/options.txt src/ops.c src/optionstr.c src/testdir/test_increment.vim src/version.c
diffstat 5 files changed, 97 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -5427,6 +5427,15 @@ A jump table for the options with a shor
 	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".
+	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
 	considered decimal.  This also happens for numbers that are not
 	recognized as octal or hex.
--- a/src/ops.c
+++ b/src/ops.c
@@ -2428,10 +2428,11 @@ do_addsub(
     char_u	*ptr;
     int		c;
     int		todel;
-    int		dohex;
-    int		dooct;
-    int		dobin;
-    int		doalp;
+    int		do_hex;
+    int		do_oct;
+    int		do_bin;
+    int		do_alpha;
+    int		do_unsigned;
     int		firstdigit;
     int		subtract;
     int		negative = FALSE;
@@ -2443,10 +2444,11 @@ do_addsub(
     pos_T	startpos;
     pos_T	endpos;
 
-    dohex = (vim_strchr(curbuf->b_p_nf, 'x') != NULL);	// "heX"
-    dooct = (vim_strchr(curbuf->b_p_nf, 'o') != NULL);	// "Octal"
-    dobin = (vim_strchr(curbuf->b_p_nf, 'b') != NULL);	// "Bin"
-    doalp = (vim_strchr(curbuf->b_p_nf, 'p') != NULL);	// "alPha"
+    do_hex = (vim_strchr(curbuf->b_p_nf, 'x') != NULL);	// "heX"
+    do_oct = (vim_strchr(curbuf->b_p_nf, 'o') != NULL);	// "Octal"
+    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"
 
     curwin->w_cursor = *pos;
     ptr = ml_get(pos->lnum);
@@ -2460,7 +2462,7 @@ do_addsub(
      */
     if (!VIsual_active)
     {
-	if (dobin)
+	if (do_bin)
 	    while (col > 0 && vim_isbdigit(ptr[col]))
 	    {
 		--col;
@@ -2468,7 +2470,7 @@ do_addsub(
 		    col -= (*mb_head_off)(ptr, ptr + col);
 	    }
 
-	if (dohex)
+	if (do_hex)
 	    while (col > 0 && vim_isxdigit(ptr[col]))
 	    {
 		--col;
@@ -2476,8 +2478,8 @@ do_addsub(
 		    col -= (*mb_head_off)(ptr, ptr + col);
 	    }
 
-	if (       dobin
-		&& dohex
+	if (       do_bin
+		&& do_hex
 		&& ! ((col > 0
 		    && (ptr[col] == 'X'
 			|| ptr[col] == 'x')
@@ -2499,7 +2501,7 @@ do_addsub(
 	    }
 	}
 
-	if ((       dohex
+	if ((       do_hex
 		&& col > 0
 		&& (ptr[col] == 'X'
 		    || ptr[col] == 'x')
@@ -2507,7 +2509,7 @@ do_addsub(
 		&& (!has_mbyte ||
 		    !(*mb_head_off)(ptr, ptr + col - 1))
 		&& vim_isxdigit(ptr[col + 1])) ||
-	    (       dobin
+	    (       do_bin
 		&& col > 0
 		&& (ptr[col] == 'B'
 		    || ptr[col] == 'b')
@@ -2530,12 +2532,12 @@ do_addsub(
 
 	    while (ptr[col] != NUL
 		    && !vim_isdigit(ptr[col])
-		    && !(doalp && ASCII_ISALPHA(ptr[col])))
+		    && !(do_alpha && ASCII_ISALPHA(ptr[col])))
 		col += mb_ptr2len(ptr + col);
 
 	    while (col > 0
 		    && vim_isdigit(ptr[col - 1])
-		    && !(doalp && ASCII_ISALPHA(ptr[col])))
+		    && !(do_alpha && ASCII_ISALPHA(ptr[col])))
 	    {
 		--col;
 		if (has_mbyte)
@@ -2548,7 +2550,7 @@ do_addsub(
     {
 	while (ptr[col] != NUL && length > 0
 		&& !vim_isdigit(ptr[col])
-		&& !(doalp && ASCII_ISALPHA(ptr[col])))
+		&& !(do_alpha && ASCII_ISALPHA(ptr[col])))
 	{
 	    int mb_len = mb_ptr2len(ptr + col);
 
@@ -2560,7 +2562,8 @@ do_addsub(
 	    goto theend;
 
 	if (col > pos->col && ptr[col - 1] == '-'
-		&& (!has_mbyte || !(*mb_head_off)(ptr, ptr + col - 1)))
+		&& (!has_mbyte || !(*mb_head_off)(ptr, ptr + col - 1))
+		&& !do_unsigned)
 	{
 	    negative = TRUE;
 	    was_positive = FALSE;
@@ -2571,13 +2574,13 @@ do_addsub(
      * If a number was found, and saving for undo works, replace the number.
      */
     firstdigit = ptr[col];
-    if (!VIM_ISDIGIT(firstdigit) && !(doalp && ASCII_ISALPHA(firstdigit)))
+    if (!VIM_ISDIGIT(firstdigit) && !(do_alpha && ASCII_ISALPHA(firstdigit)))
     {
 	beep_flush();
 	goto theend;
     }
 
-    if (doalp && ASCII_ISALPHA(firstdigit))
+    if (do_alpha && ASCII_ISALPHA(firstdigit))
     {
 	// decrement or increment alphabetic character
 	if (op_type == OP_NR_SUB)
@@ -2626,7 +2629,8 @@ do_addsub(
 	if (col > 0 && ptr[col - 1] == '-'
 		&& (!has_mbyte ||
 		    !(*mb_head_off)(ptr, ptr + col - 1))
-		&& !visual)
+		&& !visual
+		&& !do_unsigned)
 	{
 	    // negative number
 	    --col;
@@ -2639,9 +2643,9 @@ do_addsub(
 		    : length);
 
 	vim_str2nr(ptr + col, &pre, &length,
-		0 + (dobin ? STR2NR_BIN : 0)
-		    + (dooct ? STR2NR_OCT : 0)
-		    + (dohex ? STR2NR_HEX : 0),
+		0 + (do_bin ? STR2NR_BIN : 0)
+		    + (do_oct ? STR2NR_OCT : 0)
+		    + (do_hex ? STR2NR_HEX : 0),
 		NULL, &n, maxlen, FALSE);
 
 	// ignore leading '-' for hex and octal and bin numbers
@@ -2687,6 +2691,17 @@ do_addsub(
 		negative = FALSE;
 	}
 
+	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)
 	{
 	    // need to remove the '-'
@@ -2780,7 +2795,7 @@ do_addsub(
 	 * Don't do this when
 	 * the result may look like an octal number.
 	 */
-	if (firstdigit == '0' && !(dooct && pre == 0))
+	if (firstdigit == '0' && !(do_oct && pre == 0))
 	    while (length-- > 0)
 		*ptr++ = '0';
 	*ptr = NUL;
--- a/src/optionstr.c
+++ b/src/optionstr.c
@@ -21,7 +21,7 @@ static char *(p_bo_values[]) = {"all", "
 				 "hangul", "insertmode", "lang", "mess",
 				 "showmatch", "operator", "register", "shell",
 				 "spell", "wildmode", 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};
 #ifdef FEAT_CRYPT
 static char *(p_cm_values[]) = {"zip", "blowfish", "blowfish2", NULL};
--- a/src/testdir/test_increment.vim
+++ b/src/testdir/test_increment.vim
@@ -1,4 +1,4 @@
-" Tests for using Ctrl-A/Ctrl-X on visual selections
+" Tests for using Ctrl-A/Ctrl-X
 
 func SetUp()
   new dummy
@@ -796,4 +796,48 @@ func Test_increment_special_char()
   call assert_beeps("normal \<C-X>")
 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
+
 " vim: shiftwidth=2 sts=2 expandtab
--- a/src/version.c
+++ b/src/version.c
@@ -747,6 +747,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    860,
+/**/
     859,
 /**/
     858,