From 6e6386716f9494ae86027c6d34f657fd03dfec42 Mon Sep 17 00:00:00 2001 From: Illia Bobyr Date: Tue, 17 Oct 2023 11:09:45 +0200 Subject: [PATCH] patch 9.0.2040: trim(): hard to use default mask Problem: trim(): hard to use default mask Solution: Use default 'mask' when it is v:none The default 'mask' value is pretty complex, as it includes many characters. Yet, if one needs to specify the trimming direction, the third argument, 'trim()' currently requires the 'mask' value to be provided explicitly. 'v:none' is already used to mean "use the default argument value" in user defined functions. See |none-function_argument| in help. closes: #13363 Signed-off-by: Christian Brabandt Co-authored-by: Illia Bobyr --- runtime/doc/builtin.txt | 7 ++++--- src/errors.h | 2 ++ src/proto/typval.pro | 1 + src/strings.c | 28 +++++++++++++--------------- src/testdir/test_functions.vim | 6 +++++- src/testdir/test_vim9_builtin.vim | 2 +- src/typval.c | 31 +++++++++++++++++++++++++++++++ src/version.c | 2 ++ 8 files changed, 59 insertions(+), 20 deletions(-) diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt index a9bba86d8..38c4b6f68 100644 --- a/runtime/doc/builtin.txt +++ b/runtime/doc/builtin.txt @@ -10119,9 +10119,10 @@ trim({text} [, {mask} [, {dir}]]) *trim()* Return {text} as a String where any character in {mask} is removed from the beginning and/or end of {text}. - If {mask} is not given, {mask} is all characters up to 0x20, - which includes Tab, space, NL and CR, plus the non-breaking - space character 0xa0. + If {mask} is not given, or is |v:none| (see + |none-function_argument|), {mask} is all characters up to + 0x20, which includes Tab, space, NL and CR, plus the + non-breaking space character 0xa0. The optional {dir} argument specifies where to remove the characters: diff --git a/src/errors.h b/src/errors.h index 7b1181ae9..d7ed81a16 100644 --- a/src/errors.h +++ b/src/errors.h @@ -3539,6 +3539,8 @@ EXTERN char e_cannot_lock_object_variable_str[] EXTERN char e_cannot_lock_class_variable_str[] INIT(= N_("E1392: Cannot (un)lock class variable \"%s\" in class \"%s\"")); #endif +EXTERN char e_string_or_none_required_for_argument_nr[] + INIT(= N_("E1393: String or v:none required for argument %d")); // E1393 - E1499 unused (reserved for Vim9 class support) EXTERN char e_cannot_mix_positional_and_non_positional_str[] INIT(= N_("E1500: Cannot mix positional and non-positional arguments: %s")); diff --git a/src/proto/typval.pro b/src/proto/typval.pro index db8f94ebb..10f6e6711 100644 --- a/src/proto/typval.pro +++ b/src/proto/typval.pro @@ -14,6 +14,7 @@ int check_for_unknown_arg(typval_T *args, int idx); int check_for_string_arg(typval_T *args, int idx); int check_for_nonempty_string_arg(typval_T *args, int idx); int check_for_opt_string_arg(typval_T *args, int idx); +int check_for_opt_string_or_none_arg(typval_T *args, int idx, int *is_none); int check_for_number_arg(typval_T *args, int idx); int check_for_opt_number_arg(typval_T *args, int idx); int check_for_float_or_nr_arg(typval_T *args, int idx); diff --git a/src/strings.c b/src/strings.c index c04cbe84f..f1c8af8f9 100644 --- a/src/strings.c +++ b/src/strings.c @@ -1962,7 +1962,7 @@ f_trim(typval_T *argvars, typval_T *rettv) if (in_vim9script() && (check_for_string_arg(argvars, 0) == FAIL - || check_for_opt_string_arg(argvars, 1) == FAIL + || check_for_opt_string_or_none_arg(argvars, 1, NULL) == FAIL || (argvars[1].v_type != VAR_UNKNOWN && check_for_opt_number_arg(argvars, 2) == FAIL))) return; @@ -1971,26 +1971,24 @@ f_trim(typval_T *argvars, typval_T *rettv) if (head == NULL) return; - if (check_for_opt_string_arg(argvars, 1) == FAIL) + if (check_for_opt_string_or_none_arg(argvars, 1, NULL) == FAIL) return; if (argvars[1].v_type == VAR_STRING) - { mask = tv_get_string_buf_chk(&argvars[1], buf2); - if (argvars[2].v_type != VAR_UNKNOWN) - { - int error = 0; + if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN) + { + int error = 0; - // leading or trailing characters to trim - dir = (int)tv_get_number_chk(&argvars[2], &error); - if (error) - return; - if (dir < 0 || dir > 2) - { - semsg(_(e_invalid_argument_str), tv_get_string(&argvars[2])); - return; - } + // leading or trailing characters to trim + dir = (int)tv_get_number_chk(&argvars[2], &error); + if (error) + return; + if (dir < 0 || dir > 2) + { + semsg(_(e_invalid_argument_str), tv_get_string(&argvars[2])); + return; } } diff --git a/src/testdir/test_functions.vim b/src/testdir/test_functions.vim index d59896697..85d1d22ee 100644 --- a/src/testdir/test_functions.vim +++ b/src/testdir/test_functions.vim @@ -2231,11 +2231,15 @@ func Test_trim() call assert_fails('eval trim(" vim ", " ", [])', 'E745:') call assert_fails('eval trim(" vim ", " ", -1)', 'E475:') call assert_fails('eval trim(" vim ", " ", 3)', 'E475:') - call assert_fails('eval trim(" vim ", 0)', 'E1174:') + call assert_fails('eval trim(" vim ", 0)', 'E1393:') let chars = join(map(range(1, 0x20) + [0xa0], {n -> n->nr2char()}), '') call assert_equal("x", trim(chars . "x" . chars)) + call assert_equal("x", trim(chars . "x" . chars, v:none, 0)) + call assert_equal("x" . chars, trim(chars . "x" . chars, v:none, 1)) + call assert_equal(chars . "x", trim(chars . "x" . chars, v:none, 2)) + call assert_fails('let c=trim([])', 'E730:') endfunc diff --git a/src/testdir/test_vim9_builtin.vim b/src/testdir/test_vim9_builtin.vim index 1efc47a07..206f97f2e 100644 --- a/src/testdir/test_vim9_builtin.vim +++ b/src/testdir/test_vim9_builtin.vim @@ -4786,7 +4786,7 @@ enddef def Test_trim() v9.CheckDefAndScriptFailure(['trim(["a"])'], ['E1013: Argument 1: type mismatch, expected string but got list', 'E1174: String required for argument 1']) - v9.CheckDefAndScriptFailure(['trim("a", ["b"])'], ['E1013: Argument 2: type mismatch, expected string but got list', 'E1174: String required for argument 2']) + v9.CheckDefAndScriptFailure(['trim("a", ["b"])'], ['E1013: Argument 2: type mismatch, expected string but got list', 'E1393: String or v:none required for argument 2']) v9.CheckDefAndScriptFailure(['trim("a", "b", "c")'], ['E1013: Argument 3: type mismatch, expected number but got string', 'E1210: Number required for argument 3']) trim('')->assert_equal('') trim('', '')->assert_equal('') diff --git a/src/typval.c b/src/typval.c index 08dd2313f..b6371aaa4 100644 --- a/src/typval.c +++ b/src/typval.c @@ -450,6 +450,37 @@ check_for_opt_string_arg(typval_T *args, int idx) || check_for_string_arg(args, idx) != FAIL) ? OK : FAIL; } +/* + * Check for an optional string argument at 'idx', that can also be 'v:none' to + * use the default value. + * + * If 'is_none' is non-NULL it is set to 0 and updated to 1 when "args[idx]" is + * 'v:none'. + */ + int +check_for_opt_string_or_none_arg(typval_T *args, int idx, int *is_none) +{ + if (is_none != NULL) + *is_none = 0; + + if (args[idx].v_type == VAR_UNKNOWN) + return OK; + + if (args[idx].v_type == VAR_SPECIAL + && args[idx].vval.v_number == VVAL_NONE) + { + if (is_none != NULL) + *is_none = 1; + return OK; + } + + if (args[idx].v_type == VAR_STRING) + return OK; + + semsg(_(e_string_or_none_required_for_argument_nr), idx + 1); + return FAIL; +} + /* * Give an error and return FAIL unless "args[idx]" is a number. */ diff --git a/src/version.c b/src/version.c index 208d7a881..0896c643f 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 */ +/**/ + 2040, /**/ 2039, /**/