mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
vim-patch:8.1.1807: more functions can be used as a method
Problem: More functions can be used as a method.
Solution: Add append(), appendbufline(), assert_equal(), etc.
Also add the :eval command.
25e42231d3
:eval is already ported.
This commit is contained in:
parent
e6be6c307a
commit
003c8acc8a
@ -669,12 +669,14 @@ Expression syntax summary, from least to most significant:
|
|||||||
expr8[expr1 : expr1] substring of a String or sublist of a |List|
|
expr8[expr1 : expr1] substring of a String or sublist of a |List|
|
||||||
expr8.name entry in a |Dictionary|
|
expr8.name entry in a |Dictionary|
|
||||||
expr8(expr1, ...) function call with |Funcref| variable
|
expr8(expr1, ...) function call with |Funcref| variable
|
||||||
|
expr8->name(expr1, ...) |method| call
|
||||||
|
|
||||||
|expr9| number number constant
|
|expr9| number number constant
|
||||||
"string" string constant, backslash is special
|
"string" string constant, backslash is special
|
||||||
'string' string constant, ' is doubled
|
'string' string constant, ' is doubled
|
||||||
[expr1, ...] |List|
|
[expr1, ...] |List|
|
||||||
{expr1: expr1, ...} |Dictionary|
|
{expr1: expr1, ...} |Dictionary|
|
||||||
|
#{key: expr1, ...} |Dictionary|
|
||||||
&option option value
|
&option option value
|
||||||
(expr1) nested expression
|
(expr1) nested expression
|
||||||
variable internal variable
|
variable internal variable
|
||||||
@ -939,10 +941,10 @@ expr8 *expr8*
|
|||||||
-----
|
-----
|
||||||
This expression is either |expr9| or a sequence of the alternatives below,
|
This expression is either |expr9| or a sequence of the alternatives below,
|
||||||
in any order. E.g., these are all possible:
|
in any order. E.g., these are all possible:
|
||||||
expr9[expr1].name
|
expr8[expr1].name
|
||||||
expr9.name[expr1]
|
expr8.name[expr1]
|
||||||
expr9(expr1, ...)[expr1].name
|
expr8(expr1, ...)[expr1].name
|
||||||
expr9->(expr1, ...)[expr1]
|
expr8->(expr1, ...)[expr1]
|
||||||
Evaluation is always from left to right.
|
Evaluation is always from left to right.
|
||||||
|
|
||||||
|
|
||||||
@ -1047,10 +1049,17 @@ When expr8 is a |Funcref| type variable, invoke the function it refers to.
|
|||||||
|
|
||||||
expr8->name([args]) method call *method*
|
expr8->name([args]) method call *method*
|
||||||
|
|
||||||
For global methods this is the same as: >
|
For methods that are also available as global functions this is the same as: >
|
||||||
name(expr8 [, args])
|
name(expr8 [, args])
|
||||||
There can also be methods specifically for the type of "expr8".
|
There can also be methods specifically for the type of "expr8".
|
||||||
|
|
||||||
|
"->name(" must not contain white space. There can be white space before "->"
|
||||||
|
and after the "(".
|
||||||
|
|
||||||
|
This allows for chaining, using the type that the method returns: >
|
||||||
|
mylist->filter(filterexpr)->map(mapexpr)->sort()->join()
|
||||||
|
<
|
||||||
|
|
||||||
*expr9*
|
*expr9*
|
||||||
number
|
number
|
||||||
------
|
------
|
||||||
@ -2637,6 +2646,9 @@ append({lnum}, {text}) *append()*
|
|||||||
:let failed = append(line('$'), "# THE END")
|
:let failed = append(line('$'), "# THE END")
|
||||||
:let failed = append(0, ["Chapter 1", "the beginning"])
|
:let failed = append(0, ["Chapter 1", "the beginning"])
|
||||||
|
|
||||||
|
< Can also be used as a |method| after a List: >
|
||||||
|
mylist->append(lnum)
|
||||||
|
|
||||||
appendbufline({expr}, {lnum}, {text}) *appendbufline()*
|
appendbufline({expr}, {lnum}, {text}) *appendbufline()*
|
||||||
Like |append()| but append the text in buffer {expr}.
|
Like |append()| but append the text in buffer {expr}.
|
||||||
|
|
||||||
@ -2655,8 +2667,10 @@ appendbufline({expr}, {lnum}, {text}) *appendbufline()*
|
|||||||
error message is given. Example: >
|
error message is given. Example: >
|
||||||
:let failed = appendbufline(13, 0, "# THE START")
|
:let failed = appendbufline(13, 0, "# THE START")
|
||||||
<
|
<
|
||||||
*argc()*
|
Can also be used as a |method| after a List: >
|
||||||
argc([{winid}])
|
mylist->appendbufline(buf, lnum)
|
||||||
|
|
||||||
|
argc([{winid}]) *argc()*
|
||||||
The result is the number of files in the argument list. See
|
The result is the number of files in the argument list. See
|
||||||
|arglist|.
|
|arglist|.
|
||||||
If {winid} is not supplied, the argument list of the current
|
If {winid} is not supplied, the argument list of the current
|
||||||
@ -3518,6 +3532,9 @@ eval({string}) Evaluate {string} and return the result. Especially useful to
|
|||||||
them. Also works for |Funcref|s that refer to existing
|
them. Also works for |Funcref|s that refer to existing
|
||||||
functions.
|
functions.
|
||||||
|
|
||||||
|
Can also be used as a |method|: >
|
||||||
|
argv->join()->eval()
|
||||||
|
|
||||||
eventhandler() *eventhandler()*
|
eventhandler() *eventhandler()*
|
||||||
Returns 1 when inside an event handler. That is that Vim got
|
Returns 1 when inside an event handler. That is that Vim got
|
||||||
interrupted while waiting for the user to type a character,
|
interrupted while waiting for the user to type a character,
|
||||||
@ -3864,7 +3881,11 @@ filereadable({file}) *filereadable()*
|
|||||||
expression, which is used as a String.
|
expression, which is used as a String.
|
||||||
If you don't care about the file being readable you can use
|
If you don't care about the file being readable you can use
|
||||||
|glob()|.
|
|glob()|.
|
||||||
|
{file} is used as-is, you may want to expand wildcards first: >
|
||||||
|
echo filereadable('~/.vimrc')
|
||||||
|
0
|
||||||
|
echo filereadable(expand('~/.vimrc'))
|
||||||
|
1
|
||||||
|
|
||||||
filewritable({file}) *filewritable()*
|
filewritable({file}) *filewritable()*
|
||||||
The result is a Number, which is 1 when a file with the
|
The result is a Number, which is 1 when a file with the
|
||||||
@ -10006,7 +10027,9 @@ This function can then be called with: >
|
|||||||
The recursiveness of user functions is restricted with the |'maxfuncdepth'|
|
The recursiveness of user functions is restricted with the |'maxfuncdepth'|
|
||||||
option.
|
option.
|
||||||
|
|
||||||
It is also possible to use `:eval`. It does not support a range.
|
It is also possible to use `:eval`. It does not support a range, but does
|
||||||
|
allow for method chaining, e.g.: >
|
||||||
|
eval GetList()->Filter()->append('$')
|
||||||
|
|
||||||
|
|
||||||
AUTOMATICALLY LOADING FUNCTIONS ~
|
AUTOMATICALLY LOADING FUNCTIONS ~
|
||||||
@ -10749,7 +10772,7 @@ text...
|
|||||||
<
|
<
|
||||||
*:eval*
|
*:eval*
|
||||||
:eval {expr} Evaluate {expr} and discard the result. Example: >
|
:eval {expr} Evaluate {expr} and discard the result. Example: >
|
||||||
:eval append(Filter(Getlist()), '$')
|
:eval Getlist()->Filter()->append('$')
|
||||||
|
|
||||||
< The expression is supposed to have a side effect,
|
< The expression is supposed to have a side effect,
|
||||||
since the resulting value is not used. In the example
|
since the resulting value is not used. In the example
|
||||||
|
@ -69,7 +69,10 @@ assert_equal({expected}, {actual} [, {msg}])
|
|||||||
< Will result in a string to be added to |v:errors|:
|
< Will result in a string to be added to |v:errors|:
|
||||||
test.vim line 12: Expected 'foo' but got 'bar' ~
|
test.vim line 12: Expected 'foo' but got 'bar' ~
|
||||||
|
|
||||||
*assert_equalfile()*
|
Can also be used as a |method|: >
|
||||||
|
mylist->assert_equal([1, 2, 3])
|
||||||
|
|
||||||
|
< *assert_equalfile()*
|
||||||
assert_equalfile({fname-one}, {fname-two})
|
assert_equalfile({fname-one}, {fname-two})
|
||||||
When the files {fname-one} and {fname-two} do not contain
|
When the files {fname-one} and {fname-two} do not contain
|
||||||
exactly the same text an error message is added to |v:errors|.
|
exactly the same text an error message is added to |v:errors|.
|
||||||
@ -145,7 +148,10 @@ assert_notequal({expected}, {actual} [, {msg}])
|
|||||||
|v:errors| when {expected} and {actual} are equal.
|
|v:errors| when {expected} and {actual} are equal.
|
||||||
Also see |assert-return|.
|
Also see |assert-return|.
|
||||||
|
|
||||||
*assert_notmatch()*
|
Can also be used as a |method|: >
|
||||||
|
mylist->assert_notequal([1, 2, 3])
|
||||||
|
|
||||||
|
< *assert_notmatch()*
|
||||||
assert_notmatch({pattern}, {actual} [, {msg}])
|
assert_notmatch({pattern}, {actual} [, {msg}])
|
||||||
The opposite of `assert_match()`: add an error message to
|
The opposite of `assert_match()`: add an error message to
|
||||||
|v:errors| when {pattern} matches {actual}.
|
|v:errors| when {pattern} matches {actual}.
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
-- arguments.
|
-- arguments.
|
||||||
-- base For methods: the argument to use as the base argument (1-indexed):
|
-- base For methods: the argument to use as the base argument (1-indexed):
|
||||||
-- base->method()
|
-- base->method()
|
||||||
-- Defaults to zero (function cannot be used as a method).
|
-- Defaults to BASE_NONE (function cannot be used as a method).
|
||||||
-- func Name of the C function which implements the VimL function. Defaults to
|
-- func Name of the C function which implements the VimL function. Defaults to
|
||||||
-- `f_{funcname}`.
|
-- `f_{funcname}`.
|
||||||
|
|
||||||
@ -15,6 +15,10 @@ local varargs = function(nr)
|
|||||||
return {nr}
|
return {nr}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Usable with the base key: use the last function argument as the method base.
|
||||||
|
-- Value is from funcs.h file. "BASE_" prefix is omitted.
|
||||||
|
local LAST = "BASE_LAST"
|
||||||
|
|
||||||
return {
|
return {
|
||||||
funcs={
|
funcs={
|
||||||
abs={args=1},
|
abs={args=1},
|
||||||
@ -22,15 +26,15 @@ return {
|
|||||||
add={args=2, base=1},
|
add={args=2, base=1},
|
||||||
['and']={args=2},
|
['and']={args=2},
|
||||||
api_info={},
|
api_info={},
|
||||||
append={args=2},
|
append={args=2, base=LAST},
|
||||||
appendbufline={args=3},
|
appendbufline={args=3, base=LAST},
|
||||||
argc={args={0, 1}},
|
argc={args={0, 1}},
|
||||||
argidx={},
|
argidx={},
|
||||||
arglistid={args={0, 2}},
|
arglistid={args={0, 2}},
|
||||||
argv={args={0, 2}},
|
argv={args={0, 2}},
|
||||||
asin={args=1, func="float_op_wrapper", data="&asin"}, -- WJMc
|
asin={args=1, func="float_op_wrapper", data="&asin"}, -- WJMc
|
||||||
assert_beeps={args={1}},
|
assert_beeps={args={1}},
|
||||||
assert_equal={args={2, 3}},
|
assert_equal={args={2, 3}, base=2},
|
||||||
assert_equalfile={args={2, 3}},
|
assert_equalfile={args={2, 3}},
|
||||||
assert_exception={args={1, 2}},
|
assert_exception={args={1, 2}},
|
||||||
assert_fails={args={1, 3}},
|
assert_fails={args={1, 3}},
|
||||||
@ -38,7 +42,7 @@ return {
|
|||||||
assert_inrange={args={3, 4}},
|
assert_inrange={args={3, 4}},
|
||||||
assert_match={args={2, 3}},
|
assert_match={args={2, 3}},
|
||||||
assert_nobeep={args={1}},
|
assert_nobeep={args={1}},
|
||||||
assert_notequal={args={2, 3}},
|
assert_notequal={args={2, 3}, base=2},
|
||||||
assert_notmatch={args={2, 3}},
|
assert_notmatch={args={2, 3}},
|
||||||
assert_report={args=1},
|
assert_report={args=1},
|
||||||
assert_true={args={1, 2}},
|
assert_true={args={1, 2}},
|
||||||
@ -99,7 +103,7 @@ return {
|
|||||||
empty={args=1, base=1},
|
empty={args=1, base=1},
|
||||||
environ={},
|
environ={},
|
||||||
escape={args=2},
|
escape={args=2},
|
||||||
eval={args=1},
|
eval={args=1, base=1},
|
||||||
eventhandler={},
|
eventhandler={},
|
||||||
executable={args=1},
|
executable={args=1},
|
||||||
execute={args={1, 2}},
|
execute={args={1, 2}},
|
||||||
|
@ -199,7 +199,7 @@ int call_internal_method(const char_u *const fname, const int argcount,
|
|||||||
FUNC_ATTR_NONNULL_ALL
|
FUNC_ATTR_NONNULL_ALL
|
||||||
{
|
{
|
||||||
const VimLFuncDef *const fdef = find_internal_func((const char *)fname);
|
const VimLFuncDef *const fdef = find_internal_func((const char *)fname);
|
||||||
if (fdef == NULL || fdef->base_arg == 0) {
|
if (fdef == NULL || fdef->base_arg == BASE_NONE) {
|
||||||
return ERROR_UNKNOWN;
|
return ERROR_UNKNOWN;
|
||||||
} else if (argcount + 1 < fdef->min_argc) {
|
} else if (argcount + 1 < fdef->min_argc) {
|
||||||
return ERROR_TOOFEW;
|
return ERROR_TOOFEW;
|
||||||
@ -208,7 +208,8 @@ int call_internal_method(const char_u *const fname, const int argcount,
|
|||||||
}
|
}
|
||||||
|
|
||||||
typval_T argv[MAX_FUNC_ARGS + 1];
|
typval_T argv[MAX_FUNC_ARGS + 1];
|
||||||
const ptrdiff_t base_index = fdef->base_arg - 1;
|
const ptrdiff_t base_index
|
||||||
|
= fdef->base_arg == BASE_LAST ? argcount : fdef->base_arg - 1;
|
||||||
memcpy(argv, argvars, base_index * sizeof(typval_T));
|
memcpy(argv, argvars, base_index * sizeof(typval_T));
|
||||||
argv[base_index] = *basetv;
|
argv[base_index] = *basetv;
|
||||||
memcpy(argv + base_index + 1, argvars + base_index,
|
memcpy(argv + base_index + 1, argvars + base_index,
|
||||||
|
@ -9,12 +9,16 @@ typedef void (*FunPtr)(void);
|
|||||||
/// Prototype of C function that implements VimL function
|
/// Prototype of C function that implements VimL function
|
||||||
typedef void (*VimLFunc)(typval_T *args, typval_T *rvar, FunPtr data);
|
typedef void (*VimLFunc)(typval_T *args, typval_T *rvar, FunPtr data);
|
||||||
|
|
||||||
|
/// Special flags for base_arg @see VimLFuncDef
|
||||||
|
#define BASE_NONE 0 ///< Not a method (no base argument).
|
||||||
|
#define BASE_LAST UINT8_MAX ///< Use the last argument as the method base.
|
||||||
|
|
||||||
/// Structure holding VimL function definition
|
/// Structure holding VimL function definition
|
||||||
typedef struct fst {
|
typedef struct fst {
|
||||||
char *name; ///< Name of the function.
|
char *name; ///< Name of the function.
|
||||||
uint8_t min_argc; ///< Minimal number of arguments.
|
uint8_t min_argc; ///< Minimal number of arguments.
|
||||||
uint8_t max_argc; ///< Maximal number of arguments.
|
uint8_t max_argc; ///< Maximal number of arguments.
|
||||||
uint8_t base_arg; ///< Method base arg # (1-indexed), or 0 if not a method.
|
uint8_t base_arg; ///< Method base arg # (1-indexed), BASE_NONE or BASE_LAST.
|
||||||
VimLFunc func; ///< Function implementation.
|
VimLFunc func; ///< Function implementation.
|
||||||
FunPtr data; ///< Userdata for function implementation.
|
FunPtr data; ///< Userdata for function implementation.
|
||||||
} VimLFuncDef;
|
} VimLFuncDef;
|
||||||
|
@ -42,7 +42,7 @@ gperfpipe:write([[
|
|||||||
%language=ANSI-C
|
%language=ANSI-C
|
||||||
%global-table
|
%global-table
|
||||||
%readonly-tables
|
%readonly-tables
|
||||||
%define initializer-suffix ,0,0,0,NULL,NULL
|
%define initializer-suffix ,0,0,BASE_NONE,NULL,NULL
|
||||||
%define word-array-name functions
|
%define word-array-name functions
|
||||||
%define hash-function-name hash_internal_func_gperf
|
%define hash-function-name hash_internal_func_gperf
|
||||||
%define lookup-function-name find_internal_func_gperf
|
%define lookup-function-name find_internal_func_gperf
|
||||||
@ -59,7 +59,7 @@ for name, def in pairs(funcs) do
|
|||||||
elseif #args == 1 then
|
elseif #args == 1 then
|
||||||
args[2] = 'MAX_FUNC_ARGS'
|
args[2] = 'MAX_FUNC_ARGS'
|
||||||
end
|
end
|
||||||
local base = def.base or 0
|
local base = def.base or "BASE_NONE"
|
||||||
local func = def.func or ('f_' .. name)
|
local func = def.func or ('f_' .. name)
|
||||||
local data = def.data or "NULL"
|
local data = def.data or "NULL"
|
||||||
gperfpipe:write(('%s, %s, %s, %s, &%s, (FunPtr)%s\n')
|
gperfpipe:write(('%s, %s, %s, %s, &%s, (FunPtr)%s\n')
|
||||||
|
@ -3,18 +3,23 @@
|
|||||||
func Test_list()
|
func Test_list()
|
||||||
let l = [1, 2, 3]
|
let l = [1, 2, 3]
|
||||||
call assert_equal([1, 2, 3, 4], [1, 2, 3]->add(4))
|
call assert_equal([1, 2, 3, 4], [1, 2, 3]->add(4))
|
||||||
|
eval l->assert_equal(l)
|
||||||
|
eval l->assert_equal(l, 'wrong')
|
||||||
|
eval l->assert_notequal([3, 2, 1])
|
||||||
|
eval l->assert_notequal([3, 2, 1], 'wrong')
|
||||||
call assert_equal(l, l->copy())
|
call assert_equal(l, l->copy())
|
||||||
call assert_equal(1, l->count(2))
|
call assert_equal(1, l->count(2))
|
||||||
call assert_false(l->empty())
|
call assert_false(l->empty())
|
||||||
call assert_true([]->empty())
|
call assert_true([]->empty())
|
||||||
|
call assert_equal(579, ['123', '+', '456']->join()->eval())
|
||||||
call assert_equal([1, 2, 3, 4, 5], [1, 2, 3]->extend([4, 5]))
|
call assert_equal([1, 2, 3, 4, 5], [1, 2, 3]->extend([4, 5]))
|
||||||
call assert_equal([1, 3], [1, 2, 3]->filter('v:val != 2'))
|
call assert_equal([1, 3], [1, 2, 3]->filter('v:val != 2'))
|
||||||
call assert_equal(2, l->get(1))
|
call assert_equal(2, l->get(1))
|
||||||
call assert_equal(1, l->index(2))
|
call assert_equal(1, l->index(2))
|
||||||
call assert_equal([0, 1, 2, 3], [1, 2, 3]->insert(0))
|
call assert_equal([0, 1, 2, 3], [1, 2, 3]->insert(0))
|
||||||
call assert_fails('let x = l->items()', 'E715:')
|
call assert_fails('eval l->items()', 'E715:')
|
||||||
call assert_equal('1 2 3', l->join())
|
call assert_equal('1 2 3', l->join())
|
||||||
call assert_fails('let x = l->keys()', 'E715:')
|
call assert_fails('eval l->keys()', 'E715:')
|
||||||
call assert_equal(3, l->len())
|
call assert_equal(3, l->len())
|
||||||
call assert_equal([2, 3, 4], [1, 2, 3]->map('v:val + 1'))
|
call assert_equal([2, 3, 4], [1, 2, 3]->map('v:val + 1'))
|
||||||
call assert_equal(3, l->max())
|
call assert_equal(3, l->max())
|
||||||
@ -26,7 +31,7 @@ func Test_list()
|
|||||||
call assert_equal('[1, 2, 3]', l->string())
|
call assert_equal('[1, 2, 3]', l->string())
|
||||||
call assert_equal(v:t_list, l->type())
|
call assert_equal(v:t_list, l->type())
|
||||||
call assert_equal([1, 2, 3], [1, 1, 2, 3, 3]->uniq())
|
call assert_equal([1, 2, 3], [1, 1, 2, 3, 3]->uniq())
|
||||||
call assert_fails('let x = l->values()', 'E715:')
|
call assert_fails('eval l->values()', 'E715:')
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
func Test_dict()
|
func Test_dict()
|
||||||
@ -65,4 +70,18 @@ func Test_dict()
|
|||||||
call assert_equal([1, 2, 3], d->values())
|
call assert_equal([1, 2, 3], d->values())
|
||||||
endfunc
|
endfunc
|
||||||
|
|
||||||
|
func Test_append()
|
||||||
|
new
|
||||||
|
eval ['one', 'two', 'three']->append(1)
|
||||||
|
call assert_equal(['', 'one', 'two', 'three'], getline(1, '$'))
|
||||||
|
|
||||||
|
%del
|
||||||
|
let bnr = bufnr('')
|
||||||
|
wincmd w
|
||||||
|
eval ['one', 'two', 'three']->appendbufline(bnr, 1)
|
||||||
|
call assert_equal(['', 'one', 'two', 'three'], getbufline(bnr, 1, '$'))
|
||||||
|
|
||||||
|
exe 'bwipe! ' .. bnr
|
||||||
|
endfunc
|
||||||
|
|
||||||
" vim: shiftwidth=2 sts=2 expandtab
|
" vim: shiftwidth=2 sts=2 expandtab
|
||||||
|
Loading…
Reference in New Issue
Block a user