Merge pull request #20774 from zeertzjq/vim-8.2.4679

vim-patch:8.2.{1506,1600,1624,1626,1751,2606,4679}
This commit is contained in:
zeertzjq
2022-11-05 18:51:03 +08:00
committed by GitHub
12 changed files with 137 additions and 37 deletions

View File

@@ -134,7 +134,8 @@ exists({expr}) Number |TRUE| if {expr} exists
exp({expr}) Float exponential of {expr} exp({expr}) Float exponential of {expr}
expand({expr} [, {nosuf} [, {list}]]) expand({expr} [, {nosuf} [, {list}]])
any expand special keywords in {expr} any expand special keywords in {expr}
expandcmd({expr}) String expand {expr} like with `:edit` expandcmd({string} [, {options}])
String expand {string} like with `:edit`
extend({expr1}, {expr2} [, {expr3}]) extend({expr1}, {expr2} [, {expr3}])
List/Dict insert items of {expr2} into {expr1} List/Dict insert items of {expr2} into {expr1}
feedkeys({string} [, {mode}]) Number add key sequence to typeahead buffer feedkeys({string} [, {mode}]) Number add key sequence to typeahead buffer
@@ -466,10 +467,11 @@ str2list({expr} [, {utf8}]) List convert each character of {expr} to
ASCII/UTF-8 value ASCII/UTF-8 value
str2nr({expr} [, {base} [, {quoted}]]) str2nr({expr} [, {base} [, {quoted}]])
Number convert String to Number Number convert String to Number
strcharlen({expr}) Number character length of the String {expr}
strcharpart({str}, {start} [, {len}]) strcharpart({str}, {start} [, {len}])
String {len} characters of {str} at String {len} characters of {str} at
character {start} character {start}
strchars({expr} [, {skipcc}]) Number character length of the String {expr} strchars({expr} [, {skipcc}]) Number character count of the String {expr}
strdisplaywidth({expr} [, {col}]) Number display length of the String {expr} strdisplaywidth({expr} [, {col}]) Number display length of the String {expr}
strftime({format} [, {time}]) String format time with a specified format strftime({format} [, {time}]) String format time with a specified format
strgetchar({str}, {index}) Number get char {index} from {str} strgetchar({str}, {index}) Number get char {index} from {str}
@@ -2043,18 +2045,27 @@ expand({string} [, {nosuf} [, {list}]]) *expand()*
Can also be used as a |method|: > Can also be used as a |method|: >
Getpattern()->expand() Getpattern()->expand()
expandcmd({string}) *expandcmd()* expandcmd({string} [, {options}]) *expandcmd()*
Expand special items in String {string} like what is done for Expand special items in String {string} like what is done for
an Ex command such as `:edit`. This expands special keywords, an Ex command such as `:edit`. This expands special keywords,
like with |expand()|, and environment variables, anywhere in like with |expand()|, and environment variables, anywhere in
{string}. "~user" and "~/path" are only expanded at the {string}. "~user" and "~/path" are only expanded at the
start. start.
The following items are supported in the {options} Dict
argument:
errmsg If set to TRUE, error messages are displayed
if an error is encountered during expansion.
By default, error messages are not displayed.
Returns the expanded string. If an error is encountered Returns the expanded string. If an error is encountered
during expansion, the unmodified {string} is returned. during expansion, the unmodified {string} is returned.
Example: > Example: >
:echo expandcmd('make %<.o') :echo expandcmd('make %<.o')
< make /path/runtime/doc/builtin.o ~ make /path/runtime/doc/builtin.o
:echo expandcmd('make %<.o', {'errmsg': v:true})
<
Can also be used as a |method|: > Can also be used as a |method|: >
GetCommand()->expandcmd() GetCommand()->expandcmd()
< <
@@ -7836,6 +7847,21 @@ str2nr({string} [, {base}]) *str2nr()*
Can also be used as a |method|: > Can also be used as a |method|: >
GetText()->str2nr() GetText()->str2nr()
strcharlen({string}) *strcharlen()*
The result is a Number, which is the number of characters
in String {string}. Composing characters are ignored.
|strchars()| can count the number of characters, counting
composing characters separately.
Returns 0 if {string} is empty or on error.
Also see |strlen()|, |strdisplaywidth()| and |strwidth()|.
Can also be used as a |method|: >
GetText()->strcharlen()
strcharpart({src}, {start} [, {len}]) *strcharpart()* strcharpart({src}, {start} [, {len}]) *strcharpart()*
Like |strpart()| but using character index and length instead Like |strpart()| but using character index and length instead
of byte index and length. Composing characters are counted of byte index and length. Composing characters are counted
@@ -7850,12 +7876,14 @@ strcharpart({src}, {start} [, {len}]) *strcharpart()*
Can also be used as a |method|: > Can also be used as a |method|: >
GetText()->strcharpart(5) GetText()->strcharpart(5)
strchars({string} [, {skipcc}]) *strchars()* strchars({string} [, {skipcc}]) *strchars()*
The result is a Number, which is the number of characters The result is a Number, which is the number of characters
in String {string}. in String {string}.
When {skipcc} is omitted or zero, composing characters are When {skipcc} is omitted or zero, composing characters are
counted separately. counted separately.
When {skipcc} set to 1, Composing characters are ignored. When {skipcc} set to 1, Composing characters are ignored.
|strcharlen()| always does this.
Returns zero on error. Returns zero on error.

View File

@@ -619,7 +619,8 @@ String manipulation: *string-functions*
stridx() first index of a short string in a long string stridx() first index of a short string in a long string
strridx() last index of a short string in a long string strridx() last index of a short string in a long string
strlen() length of a string in bytes strlen() length of a string in bytes
strchars() length of a string in characters strcharlen() length of a string in characters
strchars() number of characters in a string
strwidth() size of string when displayed strwidth() size of string when displayed
strdisplaywidth() size of string when displayed, deals with tabs strdisplaywidth() size of string when displayed, deals with tabs
setcellwidths() set character cell width overrides setcellwidths() set character cell width overrides

View File

@@ -118,7 +118,7 @@ return {
exists={args=1, base=1}, exists={args=1, base=1},
exp={args=1, base=1, float_func="exp"}, exp={args=1, base=1, float_func="exp"},
expand={args={1, 3}, base=1}, expand={args={1, 3}, base=1},
expandcmd={args=1, base=1}, expandcmd={args={1, 2}, base=1},
extend={args={2, 3}, base=1}, extend={args={2, 3}, base=1},
feedkeys={args={1, 2}, base=1}, feedkeys={args={1, 2}, base=1},
file_readable={args=1, base=1, func='f_filereadable'}, -- obsolete file_readable={args=1, base=1, func='f_filereadable'}, -- obsolete
@@ -376,6 +376,7 @@ return {
str2float={args=1, base=1}, str2float={args=1, base=1},
str2list={args={1, 2}, base=1}, str2list={args={1, 2}, base=1},
str2nr={args={1, 3}, base=1}, str2nr={args={1, 3}, base=1},
strcharlen={args=1, base=1},
strcharpart={args={2, 3}, base=1}, strcharpart={args={2, 3}, base=1},
strchars={args={1, 2}, base=1}, strchars={args={1, 2}, base=1},
strdisplaywidth={args={1, 2}, base=1}, strdisplaywidth={args={1, 2}, base=1},

View File

@@ -112,6 +112,8 @@ PRAGMA_DIAG_POP
static char *e_listblobarg = N_("E899: Argument of %s must be a List or Blob"); static char *e_listblobarg = N_("E899: Argument of %s must be a List or Blob");
static char *e_invalwindow = N_("E957: Invalid window number"); static char *e_invalwindow = N_("E957: Invalid window number");
static char *e_reduceempty = N_("E998: Reduce of an empty %s with no initial value"); static char *e_reduceempty = N_("E998: Reduce of an empty %s with no initial value");
static char e_using_number_as_bool_nr[]
= N_("E1023: Using a Number as a Bool: %d");
static char e_cannot_resize_window_in_another_tab_page[] static char e_cannot_resize_window_in_another_tab_page[]
= N_("E1308: Cannot resize a window in another tab page"); = N_("E1308: Cannot resize a window in another tab page");
@@ -906,7 +908,7 @@ static void f_charidx(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
countcc = (int)tv_get_number(&argvars[2]); countcc = (int)tv_get_number(&argvars[2]);
} }
if (countcc < 0 || countcc > 1) { if (countcc < 0 || countcc > 1) {
emsg(_(e_invarg)); semsg(_(e_using_number_as_bool_nr), countcc);
return; return;
} }
@@ -1358,10 +1360,10 @@ static void f_deepcopy(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
int noref = 0; int noref = 0;
if (argvars[1].v_type != VAR_UNKNOWN) { if (argvars[1].v_type != VAR_UNKNOWN) {
noref = (int)tv_get_number_chk(&argvars[1], NULL); noref = (int)tv_get_bool_chk(&argvars[1], NULL);
} }
if (noref < 0 || noref > 1) { if (noref < 0 || noref > 1) {
emsg(_(e_invarg)); semsg(_(e_using_number_as_bool_nr), noref);
} else { } else {
var_item_copy(NULL, &argvars[0], rettv, true, (noref == 0 var_item_copy(NULL, &argvars[0], rettv, true, (noref == 0
? get_copyID() ? get_copyID()
@@ -2056,6 +2058,12 @@ static void f_menu_get(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
static void f_expandcmd(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) static void f_expandcmd(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
char *errormsg = NULL; char *errormsg = NULL;
bool emsgoff = true;
if (argvars[1].v_type == VAR_DICT
&& tv_dict_get_bool(argvars[1].vval.v_dict, "errmsg", kBoolVarFalse)) {
emsgoff = false;
}
rettv->v_type = VAR_STRING; rettv->v_type = VAR_STRING;
char *cmdstr = xstrdup(tv_get_string(&argvars[0])); char *cmdstr = xstrdup(tv_get_string(&argvars[0]));
@@ -2069,9 +2077,17 @@ static void f_expandcmd(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
}; };
eap.argt |= EX_NOSPC; eap.argt |= EX_NOSPC;
if (emsgoff) {
emsg_off++; emsg_off++;
expand_filename(&eap, &cmdstr, &errormsg); }
if (expand_filename(&eap, &cmdstr, &errormsg) == FAIL) {
if (!emsgoff && errormsg != NULL && *errormsg != NUL) {
emsg(errormsg);
}
}
if (emsgoff) {
emsg_off--; emsg_off--;
}
rettv->vval.v_string = cmdstr; rettv->vval.v_string = cmdstr;
} }
@@ -8160,7 +8176,7 @@ static void f_split(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
typeerr = true; typeerr = true;
} }
if (argvars[2].v_type != VAR_UNKNOWN) { if (argvars[2].v_type != VAR_UNKNOWN) {
keepempty = (bool)tv_get_number_chk(&argvars[2], &typeerr); keepempty = (bool)tv_get_bool_chk(&argvars[2], &typeerr);
} }
} }
if (pat == NULL || *pat == NUL) { if (pat == NULL || *pat == NUL) {
@@ -8290,7 +8306,7 @@ static void f_str2nr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
emsg(_(e_invarg)); emsg(_(e_invarg));
return; return;
} }
if (argvars[2].v_type != VAR_UNKNOWN && tv_get_number(&argvars[2])) { if (argvars[2].v_type != VAR_UNKNOWN && tv_get_bool(&argvars[2])) {
what |= STR2NR_QUOTE; what |= STR2NR_QUOTE;
} }
} }
@@ -8445,26 +8461,38 @@ static void f_strlen(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
rettv->vval.v_number = (varnumber_T)strlen(tv_get_string(&argvars[0])); rettv->vval.v_number = (varnumber_T)strlen(tv_get_string(&argvars[0]));
} }
/// "strchars()" function static void strchar_common(typval_T *argvars, typval_T *rettv, bool skipcc)
static void f_strchars(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
const char *s = tv_get_string(&argvars[0]); const char *s = tv_get_string(&argvars[0]);
int skipcc = 0;
varnumber_T len = 0; varnumber_T len = 0;
int (*func_mb_ptr2char_adv)(const char_u **pp); int (*func_mb_ptr2char_adv)(const char_u **pp);
if (argvars[1].v_type != VAR_UNKNOWN) {
skipcc = (int)tv_get_number_chk(&argvars[1], NULL);
}
if (skipcc < 0 || skipcc > 1) {
emsg(_(e_invarg));
} else {
func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv; func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
while (*s != NUL) { while (*s != NUL) {
func_mb_ptr2char_adv((const char_u **)&s); func_mb_ptr2char_adv((const char_u **)&s);
len++; len++;
} }
rettv->vval.v_number = len; rettv->vval.v_number = len;
}
/// "strcharlen()" function
static void f_strcharlen(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
strchar_common(argvars, rettv, true);
}
/// "strchars()" function
static void f_strchars(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{
int skipcc = false;
if (argvars[1].v_type != VAR_UNKNOWN) {
skipcc = (int)tv_get_bool(&argvars[1]);
}
if (skipcc < 0 || skipcc > 1) {
semsg(_(e_using_number_as_bool_nr), skipcc);
} else {
strchar_common(argvars, rettv, skipcc);
} }
} }

View File

@@ -2060,10 +2060,25 @@ int tv_dict_get_tv(dict_T *d, const char *const key, typval_T *rettv)
/// @return Dictionary item. /// @return Dictionary item.
varnumber_T tv_dict_get_number(const dict_T *const d, const char *const key) varnumber_T tv_dict_get_number(const dict_T *const d, const char *const key)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
return tv_dict_get_number_def(d, key, 0);
}
/// Get a number item from a dictionary.
///
/// Returns "def" if the entry doesn't exist.
///
/// @param[in] d Dictionary to get item from.
/// @param[in] key Key to find in dictionary.
/// @param[in] def Default value.
///
/// @return Dictionary item.
varnumber_T tv_dict_get_number_def(const dict_T *const d, const char *const key, const int def)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{ {
dictitem_T *const di = tv_dict_find(d, key, -1); dictitem_T *const di = tv_dict_find(d, key, -1);
if (di == NULL) { if (di == NULL) {
return 0; return def;
} }
return tv_get_number(&di->di_tv); return tv_get_number(&di->di_tv);
} }

View File

@@ -559,4 +559,9 @@ EXTERN const size_t kTVTranslate INIT(= TV_TRANSLATE);
#ifdef INCLUDE_GENERATED_DECLARATIONS #ifdef INCLUDE_GENERATED_DECLARATIONS
# include "eval/typval.h.generated.h" # include "eval/typval.h.generated.h"
#endif #endif
#define tv_get_bool tv_get_number
#define tv_get_bool_chk tv_get_number_chk
#define tv_dict_get_bool tv_dict_get_number_def
#endif // NVIM_EVAL_TYPVAL_H #endif // NVIM_EVAL_TYPVAL_H

View File

@@ -1244,7 +1244,7 @@ int gen_expand_wildcards(int num_pat, char **pat, int *num_file, char ***file, i
add_pat = expand_backtick(&ga, (char *)p, flags); add_pat = expand_backtick(&ga, (char *)p, flags);
if (add_pat == -1) { if (add_pat == -1) {
recursive = false; recursive = false;
FreeWild(ga.ga_len, ga.ga_data); ga_clear_strings(&ga);
*num_file = 0; *num_file = 0;
*file = NULL; *file = NULL;
return FAIL; return FAIL;

View File

@@ -90,14 +90,26 @@ func Test_expandcmd()
" Test for expression expansion `= " Test for expression expansion `=
let $FOO= "blue" let $FOO= "blue"
call assert_equal("blue sky", expandcmd("`=$FOO .. ' sky'`")) call assert_equal("blue sky", expandcmd("`=$FOO .. ' sky'`"))
let x = expandcmd("`=axbycz`")
call assert_equal('`=axbycz`', x)
call assert_fails('let x = expandcmd("`=axbycz`", #{errmsg: 1})', 'E121:')
let x = expandcmd("`=axbycz`", #{abc: []})
call assert_equal('`=axbycz`', x)
" Test for env variable with spaces " Test for env variable with spaces
let $FOO= "foo bar baz" let $FOO= "foo bar baz"
call assert_equal("e foo bar baz", expandcmd("e $FOO")) call assert_equal("e foo bar baz", expandcmd("e $FOO"))
if has('unix') if has('unix') && executable('bash')
" test for using the shell to expand a command argument " test for using the shell to expand a command argument.
call assert_equal('{1..4}', expandcmd('{1..4}')) " only bash supports the {..} syntax
set shell=bash
let x = expandcmd('{1..4}')
call assert_equal('{1..4}', x)
call assert_fails("let x = expandcmd('{1..4}', #{errmsg: v:true})", 'E77:')
let x = expandcmd('{1..4}', #{error: v:true})
call assert_equal('{1..4}', x)
set shell&
endif endif
unlet $FOO unlet $FOO

View File

@@ -1101,8 +1101,8 @@ func Test_charidx()
call assert_fails('let x = charidx([], 1)', 'E474:') call assert_fails('let x = charidx([], 1)', 'E474:')
call assert_fails('let x = charidx("abc", [])', 'E474:') call assert_fails('let x = charidx("abc", [])', 'E474:')
call assert_fails('let x = charidx("abc", 1, [])', 'E474:') call assert_fails('let x = charidx("abc", 1, [])', 'E474:')
call assert_fails('let x = charidx("abc", 1, -1)', 'E474:') call assert_fails('let x = charidx("abc", 1, -1)', 'E1023:')
call assert_fails('let x = charidx("abc", 1, 2)', 'E474:') call assert_fails('let x = charidx("abc", 1, 2)', 'E1023:')
endfunc endfunc
func Test_count() func Test_count()

View File

@@ -336,12 +336,12 @@ func Test_dict_deepcopy()
let l = [4, d, 6] let l = [4, d, 6]
let d[3] = l let d[3] = l
let dc = deepcopy(d) let dc = deepcopy(d)
call assert_fails('call deepcopy(d, 1)', 'E698') call assert_fails('call deepcopy(d, 1)', 'E698:')
let l2 = [0, l, l, 3] let l2 = [0, l, l, 3]
let l[1] = l2 let l[1] = l2
let l3 = deepcopy(l2) let l3 = deepcopy(l2)
call assert_true(l3[1] is l3[2]) call assert_true(l3[1] is l3[2])
call assert_fails("call deepcopy([1, 2], 2)", 'E474:') call assert_fails("call deepcopy([1, 2], 2)", 'E1023:')
endfunc endfunc
" Locked variables " Locked variables

View File

@@ -294,6 +294,9 @@ func Test_searchpair()
new new
call setline(1, ['other code', 'here [', ' [', ' " cursor here', ' ]]']) call setline(1, ['other code', 'here [', ' [', ' " cursor here', ' ]]'])
" should not give an error for using "42"
call assert_equal(0, searchpair('a', 'b', 'c', '', 42))
4 4
call assert_equal(3, searchpair('\[', '', ']', 'bW')) call assert_equal(3, searchpair('\[', '', ']', 'bW'))
call assert_equal([0, 3, 2, 0], getpos('.')) call assert_equal([0, 3, 2, 0], getpos('.'))

View File

@@ -12,7 +12,7 @@ func Test_visual_block_insert()
bwipeout! bwipeout!
endfunc endfunc
" Test for built-in function strchars() " Test for built-in functions strchars() and strcharlen()
func Test_strchars() func Test_strchars()
let inp = ["a", "あいa", "A\u20dd", "A\u20dd\u20dd", "\u20dd"] let inp = ["a", "あいa", "A\u20dd", "A\u20dd\u20dd", "\u20dd"]
let exp = [[1, 1, 1], [3, 3, 3], [2, 2, 1], [3, 3, 1], [1, 1, 1]] let exp = [[1, 1, 1], [3, 3, 3], [2, 2, 1], [3, 3, 1], [1, 1, 1]]
@@ -21,8 +21,15 @@ func Test_strchars()
call assert_equal(exp[i][1], inp[i]->strchars(0)) call assert_equal(exp[i][1], inp[i]->strchars(0))
call assert_equal(exp[i][2], strchars(inp[i], 1)) call assert_equal(exp[i][2], strchars(inp[i], 1))
endfor endfor
let exp = [1, 3, 1, 1, 1]
for i in range(len(inp))
call assert_equal(exp[i], inp[i]->strcharlen())
call assert_equal(exp[i], strcharlen(inp[i]))
endfor
call assert_fails("let v=strchars('abc', [])", 'E745:') call assert_fails("let v=strchars('abc', [])", 'E745:')
call assert_fails("let v=strchars('abc', 2)", 'E474:') call assert_fails("let v=strchars('abc', 2)", 'E1023:')
endfunc endfunc
" Test for customlist completion " Test for customlist completion