changeset 25557:763ea8f075db v8.2.3315

patch 8.2.3315: cannot use single quote in a float number for readability Commit: https://github.com/vim/vim/commit/2950065e18649d234b16e60dd0e3d75adeca4513 Author: Bram Moolenaar <Bram@vim.org> Date: Sun Aug 8 15:43:34 2021 +0200 patch 8.2.3315: cannot use single quote in a float number for readability Problem: Cannot use single quote in a float number for readability. Solution: Support single quotes like in numbers. (closes https://github.com/vim/vim/issues/8713)
author Bram Moolenaar <Bram@vim.org>
date Sun, 08 Aug 2021 15:45:03 +0200
parents 5b91b4fa6cc7
children 5a872c10a85c
files src/float.c src/json.c src/proto/float.pro src/testdir/test_float_func.vim src/typval.c src/version.c src/viminfo.c
diffstat 7 files changed, 72 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/src/float.c
+++ b/src/float.c
@@ -29,7 +29,8 @@
     int
 string2float(
     char_u	*text,
-    float_T	*value)	    // result stored here
+    float_T	*value,	    // result stored here
+    int		skip_quotes)
 {
     char	*s = (char *)text;
     float_T	f;
@@ -50,6 +51,32 @@ string2float(
 	*value = NAN;
 	return 3;
     }
+    if (skip_quotes && vim_strchr((char_u *)s, '\'') != NULL)
+    {
+	char_u	    buf[100];
+	char_u	    *p = buf;
+	int	    quotes = 0;
+
+	vim_strncpy(buf, (char_u *)s, 99);
+	p = buf;
+	for (;;)
+	{
+	    // remove single quotes between digits, not in the exponent
+	    if (*p == '\'')
+	    {
+		++quotes;
+		mch_memmove(p, p + 1, STRLEN(p));
+	    }
+	    if (!vim_isdigit(*p))
+		break;
+	    p = skipdigits(p);
+	}
+	s = (char *)buf;
+	f = strtod(s, &s);
+	*value = f;
+	return (int)((char_u *)s - buf) + quotes;
+    }
+
     f = strtod(s, &s);
     *value = f;
     return (int)((char_u *)s - text);
@@ -488,16 +515,19 @@ f_str2float(typval_T *argvars, typval_T 
 {
     char_u *p;
     int     isneg;
+    int	    skip_quotes;
 
     if (in_vim9script() && check_for_string_arg(argvars, 0) == FAIL)
 	return;
 
+    skip_quotes = argvars[1].v_type != VAR_UNKNOWN && tv_get_bool(&argvars[1]);
+
     p = skipwhite(tv_get_string_strict(&argvars[0]));
     isneg = (*p == '-');
 
     if (*p == '+' || *p == '-')
 	p = skipwhite(p + 1);
-    (void)string2float(p, &rettv->vval.v_float);
+    (void)string2float(p, &rettv->vval.v_float, skip_quotes);
     if (isneg)
 	rettv->vval.v_float *= -1;
     rettv->v_type = VAR_FLOAT;
--- a/src/json.c
+++ b/src/json.c
@@ -791,12 +791,13 @@ json_decode_item(js_read_T *reader, typv
 			    {
 				float_T f;
 
-				len = string2float(p, &f);
+				len = string2float(p, &f, FALSE);
 			    }
 			    else
 			    {
 				cur_item->v_type = VAR_FLOAT;
-				len = string2float(p, &cur_item->vval.v_float);
+				len = string2float(p, &cur_item->vval.v_float,
+									FALSE);
 			    }
 			}
 			else
--- a/src/proto/float.pro
+++ b/src/proto/float.pro
@@ -1,5 +1,5 @@
 /* float.c */
-int string2float(char_u *text, float_T *value);
+int string2float(char_u *text, float_T *value, int skip_quotes);
 void f_abs(typval_T *argvars, typval_T *rettv);
 void f_acos(typval_T *argvars, typval_T *rettv);
 void f_asin(typval_T *argvars, typval_T *rettv);
--- a/src/testdir/test_float_func.vim
+++ b/src/testdir/test_float_func.vim
@@ -239,13 +239,28 @@ func Test_str2float()
   call assert_equal('nan', string(str2float('NaN')))
   call assert_equal('nan', string(str2float('  nan  ')))
 
-  call assert_equal(1.2, str2float(1.2))
+  call assert_equal('123456.789', string(str2float("123'456.789", 1)))
+  call assert_equal('123456.789', string(str2float("12'34'56.789", 1)))
+  call assert_equal('123456.789', string(str2float("1'2'3'4'5'6.789", 1)))
+  call assert_equal('1.0', string(str2float("1''2.3", 1)))
+  call assert_equal('123456.7', string(str2float("123'456.7'89", 1)))
+
+  call assert_equal(1.2, str2float(1.2, 0))
   call CheckDefAndScriptFailure2(['str2float(1.2)'], 'E1013: Argument 1: type mismatch, expected string but got float', 'E1174: String required for argument 1')
   call assert_fails("call str2float([])", 'E730:')
   call assert_fails("call str2float({})", 'E731:')
   call assert_fails("call str2float(function('string'))", 'E729:')
 endfunc
 
+def Test_float_quotes()
+  call assert_equal('123456.789', string(123'456.789))
+  call assert_equal('123456.789', string(12'34'56.789))
+  call assert_equal('123456.789', string(1'2'3'4'5'6.789))
+
+  call assert_fails("echo string(1''2.3)", 'E116:')
+  call assert_fails("echo string(123'456.7'89)", 'E116:')
+enddef
+
 func Test_float2nr()
   call assert_equal(1, float2nr(1.234))
   call assert_equal(123, float2nr(1.234e2))
--- a/src/typval.c
+++ b/src/typval.c
@@ -1704,6 +1704,7 @@ eval_number(
 	int	    want_string UNUSED)
 {
     int		len;
+    int		skip_quotes = current_sctx.sc_version >= 4;
 #ifdef FEAT_FLOAT
     char_u	*p;
     int		get_float = FALSE;
@@ -1718,7 +1719,20 @@ eval_number(
     if (**arg == '.')
 	p = *arg;
     else
-	p = skipdigits(*arg + 1);
+    {
+	p = *arg + 1;
+	if (skip_quotes)
+	    for (;;)
+	    {
+		if (*p == '\'')
+		    ++p;
+		if (!vim_isdigit(*p))
+		    break;
+		p = skipdigits(p);
+	    }
+	else
+	    p = skipdigits(p);
+    }
     if (!want_string && p[0] == '.' && vim_isdigit(p[1]))
     {
 	get_float = TRUE;
@@ -1740,7 +1754,7 @@ eval_number(
     {
 	float_T	f;
 
-	*arg += string2float(*arg, &f);
+	*arg += string2float(*arg, &f, skip_quotes);
 	if (evaluate)
 	{
 	    rettv->v_type = VAR_FLOAT;
@@ -1784,7 +1798,7 @@ eval_number(
 	varnumber_T	n;
 
 	// decimal, hex or octal number
-	vim_str2nr(*arg, NULL, &len, current_sctx.sc_version >= 4
+	vim_str2nr(*arg, NULL, &len, skip_quotes
 		      ? STR2NR_NO_OCT + STR2NR_QUOTE
 		      : STR2NR_ALL, &n, NULL, 0, TRUE);
 	if (len == 0)
--- a/src/version.c
+++ b/src/version.c
@@ -756,6 +756,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    3315,
+/**/
     3314,
 /**/
     3313,
--- a/src/viminfo.c
+++ b/src/viminfo.c
@@ -1247,7 +1247,7 @@ read_viminfo_varlist(vir_T *virp, int wr
 				       (int)(tab - virp->vir_line + 1), TRUE);
 #ifdef FEAT_FLOAT
 		else if (type == VAR_FLOAT)
-		    (void)string2float(tab + 1, &tv.vval.v_float);
+		    (void)string2float(tab + 1, &tv.vval.v_float, FALSE);
 #endif
 		else
 		{