Merge pull request #24787 from zeertzjq/vim-9.0.1515

vim-patch:9.0.{1515,1540,1738}
This commit is contained in:
zeertzjq
2023-08-19 18:33:44 +08:00
committed by GitHub
10 changed files with 76 additions and 27 deletions

View File

@@ -5666,11 +5666,13 @@ resolve({filename}) *resolve()* *E65
path name) and also keeps a trailing path separator. path name) and also keeps a trailing path separator.
reverse({object}) *reverse()* reverse({object}) *reverse()*
Reverse the order of items in {object} in-place. Reverse the order of items in {object}. {object} can be a
{object} can be a |List| or a |Blob|. |List|, a |Blob| or a |String|. For a List and a Blob the
Returns {object}. items are reversed in-place and {object} is returned.
Returns zero if {object} is not a List or a Blob. For a String a new String is returned.
If you want an object to remain unmodified make a copy first: >vim Returns zero if {object} is not a List, Blob or a String.
If you want a List or Blob to remain unmodified make a copy
first: >vim
let revlist = reverse(copy(mylist)) let revlist = reverse(copy(mylist))
< <

View File

@@ -626,6 +626,7 @@ String manipulation: *string-functions*
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
getcellwidths() get character cell width overrides getcellwidths() get character cell width overrides
reverse() reverse the order of characters in a string
substitute() substitute a pattern match with a string substitute() substitute a pattern match with a string
submatch() get a specific match in ":s" and substitute() submatch() get a specific match in ":s" and substitute()
strpart() get part of a string using byte index strpart() get part of a string using byte index
@@ -664,7 +665,7 @@ List manipulation: *list-functions*
reduce() reduce a List to a value reduce() reduce a List to a value
slice() take a slice of a List slice() take a slice of a List
sort() sort a List sort() sort a List
reverse() reverse the order of a List or Blob reverse() reverse the order of items in a List
uniq() remove copies of repeated adjacent items uniq() remove copies of repeated adjacent items
split() split a String into a List split() split a String into a List
join() join List items into a String join() join List items into a String
@@ -731,6 +732,7 @@ Floating point computation: *float-functions*
Blob manipulation: *blob-functions* Blob manipulation: *blob-functions*
blob2list() get a list of numbers from a blob blob2list() get a list of numbers from a blob
list2blob() get a blob from a list of numbers list2blob() get a blob from a list of numbers
reverse() reverse the order of numbers in a blob
Other computation: *bitwise-function* Other computation: *bitwise-function*
and() bitwise AND and() bitwise AND

View File

@@ -6762,11 +6762,13 @@ vim.fn['repeat'] = function(expr, count) end
--- @return any --- @return any
function vim.fn.resolve(filename) end function vim.fn.resolve(filename) end
--- Reverse the order of items in {object} in-place. --- Reverse the order of items in {object}. {object} can be a
--- {object} can be a |List| or a |Blob|. --- |List|, a |Blob| or a |String|. For a List and a Blob the
--- Returns {object}. --- items are reversed in-place and {object} is returned.
--- Returns zero if {object} is not a List or a Blob. --- For a String a new String is returned.
--- If you want an object to remain unmodified make a copy first: >vim --- Returns zero if {object} is not a List, Blob or a String.
--- If you want a List or Blob to remain unmodified make a copy
--- first: >vim
--- let revlist = reverse(copy(mylist)) --- let revlist = reverse(copy(mylist))
--- < --- <
--- ---

View File

@@ -8151,11 +8151,13 @@ M.funcs = {
args = 1, args = 1,
base = 1, base = 1,
desc = [=[ desc = [=[
Reverse the order of items in {object} in-place. Reverse the order of items in {object}. {object} can be a
{object} can be a |List| or a |Blob|. |List|, a |Blob| or a |String|. For a List and a Blob the
Returns {object}. items are reversed in-place and {object} is returned.
Returns zero if {object} is not a List or a Blob. For a String a new String is returned.
If you want an object to remain unmodified make a copy first: >vim Returns zero if {object} is not a List, Blob or a String.
If you want a List or Blob to remain unmodified make a copy
first: >vim
let revlist = reverse(copy(mylist)) let revlist = reverse(copy(mylist))
< <
]=], ]=],

View File

@@ -6199,6 +6199,10 @@ static void f_resolve(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
/// "reverse({list})" function /// "reverse({list})" function
static void f_reverse(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) static void f_reverse(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
{ {
if (tv_check_for_string_or_list_or_blob_arg(argvars, 0) == FAIL) {
return;
}
if (argvars[0].v_type == VAR_BLOB) { if (argvars[0].v_type == VAR_BLOB) {
blob_T *const b = argvars[0].vval.v_blob; blob_T *const b = argvars[0].vval.v_blob;
const int len = tv_blob_len(b); const int len = tv_blob_len(b);
@@ -6209,9 +6213,14 @@ static void f_reverse(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
tv_blob_set(b, len - i - 1, tmp); tv_blob_set(b, len - i - 1, tmp);
} }
tv_blob_set_ret(rettv, b); tv_blob_set_ret(rettv, b);
} else if (argvars[0].v_type != VAR_LIST) { } else if (argvars[0].v_type == VAR_STRING) {
semsg(_(e_listblobarg), "reverse()"); rettv->v_type = VAR_STRING;
} else { if (argvars[0].vval.v_string != NULL) {
rettv->vval.v_string = reverse_text(argvars[0].vval.v_string);
} else {
rettv->vval.v_string = NULL;
}
} else if (argvars[0].v_type == VAR_LIST) {
list_T *const l = argvars[0].vval.v_list; list_T *const l = argvars[0].vval.v_list;
if (!value_check_lock(tv_list_locked(l), N_("reverse() argument"), if (!value_check_lock(tv_list_locked(l), N_("reverse() argument"),
TV_TRANSLATE)) { TV_TRANSLATE)) {

View File

@@ -81,6 +81,8 @@ static const char e_blob_required_for_argument_nr[]
= N_("E1238: Blob required for argument %d"); = N_("E1238: Blob required for argument %d");
static const char e_invalid_value_for_blob_nr[] static const char e_invalid_value_for_blob_nr[]
= N_("E1239: Invalid value for blob: %d"); = N_("E1239: Invalid value for blob: %d");
static const char e_string_list_or_blob_required_for_argument_nr[]
= N_("E1252: String, List or Blob required for argument %d");
static const char e_string_or_function_required_for_argument_nr[] static const char e_string_or_function_required_for_argument_nr[]
= N_("E1256: String or function required for argument %d"); = N_("E1256: String or function required for argument %d");
static const char e_non_null_dict_required_for_argument_nr[] static const char e_non_null_dict_required_for_argument_nr[]
@@ -4350,7 +4352,20 @@ int tv_check_for_string_or_list_arg(const typval_T *const args, const int idx)
return OK; return OK;
} }
/// Check for an optional string or list argument at 'idx' /// Give an error and return FAIL unless "args[idx]" is a string, a list or a blob.
int tv_check_for_string_or_list_or_blob_arg(const typval_T *const args, const int idx)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE
{
if (args[idx].v_type != VAR_STRING
&& args[idx].v_type != VAR_LIST
&& args[idx].v_type != VAR_BLOB) {
semsg(_(e_string_list_or_blob_required_for_argument_nr), idx + 1);
return FAIL;
}
return OK;
}
/// Check for an optional string or list argument at "idx"
int tv_check_for_opt_string_or_list_arg(const typval_T *const args, const int idx) int tv_check_for_opt_string_or_list_arg(const typval_T *const args, const int idx)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE
{ {

View File

@@ -2168,20 +2168,17 @@ int kv_do_printf(StringBuilder *str, const char *fmt, ...)
/// ///
/// @return the allocated string. /// @return the allocated string.
char *reverse_text(char *s) char *reverse_text(char *s)
FUNC_ATTR_NONNULL_RET FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET
{ {
// Reverse the pattern.
size_t len = strlen(s); size_t len = strlen(s);
char *rev = xmalloc(len + 1); char *rev = xmalloc(len + 1);
size_t rev_i = len; for (size_t s_i = 0, rev_i = len; s_i < len; s_i++) {
for (size_t s_i = 0; s_i < len; s_i++) {
const int mb_len = utfc_ptr2len(s + s_i); const int mb_len = utfc_ptr2len(s + s_i);
rev_i -= (size_t)mb_len; rev_i -= (size_t)mb_len;
memmove(rev + rev_i, s + s_i, (size_t)mb_len); memmove(rev + rev_i, s + s_i, (size_t)mb_len);
s_i += (size_t)mb_len - 1; s_i += (size_t)mb_len - 1;
} }
rev[len] = NUL; rev[len] = NUL;
return rev; return rev;
} }

View File

@@ -3148,4 +3148,24 @@ func Test_delfunc_while_listing()
call StopVimInTerminal(buf) call StopVimInTerminal(buf)
endfunc endfunc
" Test for the reverse() function with a string
func Test_string_reverse()
let lines =<< trim END
call assert_equal('', reverse(v:_null_string))
for [s1, s2] in [['', ''], ['a', 'a'], ['ab', 'ba'], ['abc', 'cba'],
\ ['abcd', 'dcba'], ['«-«-»-»', '»-»-«-«'],
\ ['🇦', '🇦'], ['🇦🇧', '🇧🇦'], ['🇦🇧🇨', '🇨🇧🇦'],
\ ['🇦«🇧-🇨»🇩', '🇩»🇨-🇧«🇦']]
call assert_equal(s2, reverse(s1))
endfor
END
call CheckLegacyAndVim9Success(lines)
" test in latin1 encoding
let save_enc = &encoding
" set encoding=latin1
call assert_equal('dcba', reverse('abcd'))
let &encoding = save_enc
endfunc
" vim: shiftwidth=2 sts=2 expandtab " vim: shiftwidth=2 sts=2 expandtab

View File

@@ -894,7 +894,7 @@ func Test_reverse_sort_uniq()
END END
call CheckLegacyAndVim9Success(lines) call CheckLegacyAndVim9Success(lines)
call assert_fails('call reverse("")', 'E899:') call assert_fails('call reverse({})', 'E1252:')
call assert_fails('call uniq([1, 2], {x, y -> []})', 'E745:') call assert_fails('call uniq([1, 2], {x, y -> []})', 'E745:')
call assert_fails("call sort([1, 2], function('min'), 1)", "E1206:") call assert_fails("call sort([1, 2], function('min'), 1)", "E1206:")
call assert_fails("call sort([1, 2], function('invalid_func'))", "E700:") call assert_fails("call sort([1, 2], function('invalid_func'))", "E700:")

View File

@@ -63,7 +63,7 @@ func Test_dict_method()
call assert_equal(2, d->remove("two")) call assert_equal(2, d->remove("two"))
let d.two = 2 let d.two = 2
call assert_fails('let x = d->repeat(2)', 'E731:') call assert_fails('let x = d->repeat(2)', 'E731:')
call assert_fails('let x = d->reverse()', 'E899:') call assert_fails('let x = d->reverse()', 'E1252:')
call assert_fails('let x = d->sort()', 'E686:') call assert_fails('let x = d->sort()', 'E686:')
call assert_equal("{'one': 1, 'two': 2, 'three': 3}", d->string()) call assert_equal("{'one': 1, 'two': 2, 'three': 3}", d->string())
call assert_equal(v:t_dict, d->type()) call assert_equal(v:t_dict, d->type())