# HG changeset patch # User Bram Moolenaar # Date 1628430303 -7200 # Node ID 763ea8f075db144fae4ff1be1dfcd72e96092cb9 # Parent 5b91b4fa6cc74bbf0a2044a0cf3719c71f063546 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 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) diff --git a/src/float.c b/src/float.c --- 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; diff --git a/src/json.c b/src/json.c --- 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 diff --git a/src/proto/float.pro b/src/proto/float.pro --- 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); diff --git a/src/testdir/test_float_func.vim b/src/testdir/test_float_func.vim --- 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)) diff --git a/src/typval.c b/src/typval.c --- 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) diff --git a/src/version.c b/src/version.c --- 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, diff --git a/src/viminfo.c b/src/viminfo.c --- 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 {