mirror of
https://github.com/neovim/neovim.git
synced 2024-12-23 20:55:18 -07:00
Merge #15293 Vimscript "method" syntax
Port VimL's method call syntax - vim-patch:8.1.{1638,1800,1803,1807,1809,1816,1820,1821,1828,1834,1835,1861,1863,1878,1879,1888,1909,1911,1912}
This commit is contained in:
commit
4c499899b2
@ -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.name entry in a |Dictionary|
|
||||
expr8(expr1, ...) function call with |Funcref| variable
|
||||
expr8->name(expr1, ...) |method| call
|
||||
|
||||
|expr9| number number constant
|
||||
"string" string constant, backslash is special
|
||||
'string' string constant, ' is doubled
|
||||
[expr1, ...] |List|
|
||||
{expr1: expr1, ...} |Dictionary|
|
||||
#{key: expr1, ...} |Dictionary|
|
||||
&option option value
|
||||
(expr1) nested expression
|
||||
variable internal variable
|
||||
@ -939,9 +941,11 @@ expr8 *expr8*
|
||||
-----
|
||||
This expression is either |expr9| or a sequence of the alternatives below,
|
||||
in any order. E.g., these are all possible:
|
||||
expr9[expr1].name
|
||||
expr9.name[expr1]
|
||||
expr9(expr1, ...)[expr1].name
|
||||
expr8[expr1].name
|
||||
expr8.name[expr1]
|
||||
expr8(expr1, ...)[expr1].name
|
||||
expr8->(expr1, ...)[expr1]
|
||||
Evaluation is always from left to right.
|
||||
|
||||
|
||||
expr8[expr1] item of String or |List| *expr-[]* *E111*
|
||||
@ -1043,6 +1047,36 @@ expr8(expr1, ...) |Funcref| function call
|
||||
When expr8 is a |Funcref| type variable, invoke the function it refers to.
|
||||
|
||||
|
||||
expr8->name([args]) method call *method* *->*
|
||||
expr8->{lambda}([args])
|
||||
|
||||
For methods that are also available as global functions this is the same as: >
|
||||
name(expr8 [, args])
|
||||
There can also be methods specifically for the type of "expr8".
|
||||
|
||||
This allows for chaining, passing the value that one method returns to the
|
||||
next method: >
|
||||
mylist->filter(filterexpr)->map(mapexpr)->sort()->join()
|
||||
<
|
||||
Example of using a lambda: >
|
||||
GetPercentage->{x -> x * 100}()->printf('%d%%')
|
||||
<
|
||||
When using -> the |expr7| operators will be applied first, thus: >
|
||||
-1.234->string()
|
||||
Is equivalent to: >
|
||||
(-1.234)->string()
|
||||
And NOT: >
|
||||
-(1.234->string())
|
||||
<
|
||||
*E274*
|
||||
"->name(" must not contain white space. There can be white space before the
|
||||
"->" and after the "(", thus you can split the lines like this: >
|
||||
mylist
|
||||
\ ->filter(filterexpr)
|
||||
\ ->map(mapexpr)
|
||||
\ ->sort()
|
||||
\ ->join()
|
||||
<
|
||||
|
||||
*expr9*
|
||||
number
|
||||
@ -2583,6 +2617,8 @@ abs({expr}) *abs()*
|
||||
echo abs(-4)
|
||||
< 4
|
||||
|
||||
Can also be used as a |method|: >
|
||||
Compute()->abs()
|
||||
|
||||
acos({expr}) *acos()*
|
||||
Return the arc cosine of {expr} measured in radians, as a
|
||||
@ -2595,6 +2631,8 @@ acos({expr}) *acos()*
|
||||
:echo acos(-0.5)
|
||||
< 2.094395
|
||||
|
||||
Can also be used as a |method|: >
|
||||
Compute()->acos()
|
||||
|
||||
add({list}, {expr}) *add()*
|
||||
Append the item {expr} to |List| {list}. Returns the
|
||||
@ -2605,12 +2643,16 @@ add({list}, {expr}) *add()*
|
||||
item. Use |extend()| to concatenate |Lists|.
|
||||
Use |insert()| to add an item at another position.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
mylist->add(val1)->add(val2)
|
||||
|
||||
and({expr}, {expr}) *and()*
|
||||
Bitwise AND on the two arguments. The arguments are converted
|
||||
to a number. A List, Dict or Float argument causes an error.
|
||||
Example: >
|
||||
:let flag = and(bits, 0x80)
|
||||
< Can also be used as a |method|: >
|
||||
:let flag = bits->and(0x80)
|
||||
|
||||
api_info() *api_info()*
|
||||
Returns Dictionary of |api-metadata|.
|
||||
@ -2629,6 +2671,9 @@ append({lnum}, {text}) *append()*
|
||||
:let failed = append(line('$'), "# THE END")
|
||||
: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()*
|
||||
Like |append()| but append the text in buffer {expr}.
|
||||
|
||||
@ -2647,8 +2692,10 @@ appendbufline({expr}, {lnum}, {text}) *appendbufline()*
|
||||
error message is given. Example: >
|
||||
:let failed = appendbufline(13, 0, "# THE START")
|
||||
<
|
||||
*argc()*
|
||||
argc([{winid}])
|
||||
Can also be used as a |method| after a List: >
|
||||
mylist->appendbufline(buf, lnum)
|
||||
|
||||
argc([{winid}]) *argc()*
|
||||
The result is the number of files in the argument list. See
|
||||
|arglist|.
|
||||
If {winid} is not supplied, the argument list of the current
|
||||
@ -2702,6 +2749,9 @@ asin({expr}) *asin()*
|
||||
:echo asin(-0.5)
|
||||
< -0.523599
|
||||
|
||||
Can also be used as a |method|: >
|
||||
Compute()->asin()
|
||||
|
||||
|
||||
assert_ functions are documented here: |assert-functions-details|
|
||||
|
||||
@ -2716,6 +2766,8 @@ atan({expr}) *atan()*
|
||||
:echo atan(-4.01)
|
||||
< -1.326405
|
||||
|
||||
Can also be used as a |method|: >
|
||||
Compute()->atan()
|
||||
|
||||
atan2({expr1}, {expr2}) *atan2()*
|
||||
Return the arc tangent of {expr1} / {expr2}, measured in
|
||||
@ -2727,6 +2779,8 @@ atan2({expr1}, {expr2}) *atan2()*
|
||||
:echo atan2(1, -1)
|
||||
< 2.356194
|
||||
|
||||
Can also be used as a |method|: >
|
||||
Compute()->atan2(1)
|
||||
|
||||
*browse()*
|
||||
browse({save}, {title}, {initdir}, {default})
|
||||
@ -2737,8 +2791,8 @@ browse({save}, {title}, {initdir}, {default})
|
||||
{title} title for the requester
|
||||
{initdir} directory to start browsing in
|
||||
{default} default file name
|
||||
When the "Cancel" button is hit, something went wrong, or
|
||||
browsing is not possible, an empty string is returned.
|
||||
An empty string is returned when the "Cancel" button is hit,
|
||||
something went wrong, or browsing is not possible.
|
||||
|
||||
*browsedir()*
|
||||
browsedir({title}, {initdir})
|
||||
@ -2760,6 +2814,8 @@ bufadd({name}) *bufadd()*
|
||||
created buffer. When {name} is an empty string then a new
|
||||
buffer is always created.
|
||||
The buffer will not have' 'buflisted' set.
|
||||
< Can also be used as a |method|: >
|
||||
let bufnr = 'somename'->bufadd()
|
||||
|
||||
bufexists({expr}) *bufexists()*
|
||||
The result is a Number, which is |TRUE| if a buffer called
|
||||
@ -2783,11 +2839,17 @@ bufexists({expr}) *bufexists()*
|
||||
Use "bufexists(0)" to test for the existence of an alternate
|
||||
file name.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
let exists = 'somename'->bufexists()
|
||||
|
||||
buflisted({expr}) *buflisted()*
|
||||
The result is a Number, which is |TRUE| if a buffer called
|
||||
{expr} exists and is listed (has the 'buflisted' option set).
|
||||
The {expr} argument is used like with |bufexists()|.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
let listed = 'somename'->buflisted()
|
||||
|
||||
bufload({expr}) *bufload()*
|
||||
Ensure the buffer {expr} is loaded. When the buffer name
|
||||
refers to an existing file then the file is read. Otherwise
|
||||
@ -2797,15 +2859,21 @@ bufload({expr}) *bufload()*
|
||||
there will be no dialog, the buffer will be loaded anyway.
|
||||
The {expr} argument is used like with |bufexists()|.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
eval 'somename'->bufload()
|
||||
|
||||
bufloaded({expr}) *bufloaded()*
|
||||
The result is a Number, which is |TRUE| if a buffer called
|
||||
{expr} exists and is loaded (shown in a window or hidden).
|
||||
The {expr} argument is used like with |bufexists()|.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
let loaded = 'somename'->bufloaded()
|
||||
|
||||
bufname([{expr}]) *bufname()*
|
||||
The result is the name of a buffer, as it is displayed by the
|
||||
":ls" command.
|
||||
+ If {expr} is omitted the current buffer is used.
|
||||
If {expr} is omitted the current buffer is used.
|
||||
If {expr} is a Number, that buffer number's name is given.
|
||||
Number zero is the alternate buffer for the current window.
|
||||
If {expr} is a String, it is used as a |file-pattern| to match
|
||||
@ -2824,6 +2892,9 @@ bufname([{expr}]) *bufname()*
|
||||
If the {expr} is a String, but you want to use it as a buffer
|
||||
number, force it to be a Number by adding zero to it: >
|
||||
:echo bufname("3" + 0)
|
||||
< Can also be used as a |method|: >
|
||||
echo bufnr->bufname()
|
||||
|
||||
< If the buffer doesn't exist, or doesn't have a name, an empty
|
||||
string is returned. >
|
||||
bufname("#") alternate buffer name
|
||||
@ -2846,6 +2917,9 @@ bufnr([{expr} [, {create}]])
|
||||
number necessarily exist, because ":bwipeout" may have removed
|
||||
them. Use bufexists() to test for the existence of a buffer.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
echo bufref->bufnr()
|
||||
|
||||
bufwinid({expr}) *bufwinid()*
|
||||
The result is a Number, which is the |window-ID| of the first
|
||||
window associated with buffer {expr}. For the use of {expr},
|
||||
@ -2856,18 +2930,22 @@ bufwinid({expr}) *bufwinid()*
|
||||
<
|
||||
Only deals with the current tab page.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
FindBuffer()->bufwinid()
|
||||
|
||||
bufwinnr({expr}) *bufwinnr()*
|
||||
The result is a Number, which is the number of the first
|
||||
window associated with buffer {expr}. For the use of {expr},
|
||||
see |bufname()| above. If buffer {expr} doesn't exist or
|
||||
there is no such window, -1 is returned. Example: >
|
||||
Like |bufwinid()| but return the window number instead of the
|
||||
|window-ID|.
|
||||
If buffer {expr} doesn't exist or there is no such window, -1
|
||||
is returned. Example: >
|
||||
|
||||
echo "A window containing buffer 1 is " . (bufwinnr(1))
|
||||
|
||||
< The number can be used with |CTRL-W_w| and ":wincmd w"
|
||||
|:wincmd|.
|
||||
Only deals with the current tab page.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
FindBuffer()->bufwinnr()
|
||||
|
||||
byte2line({byte}) *byte2line()*
|
||||
Return the line number that contains the character at byte
|
||||
@ -2877,6 +2955,9 @@ byte2line({byte}) *byte2line()*
|
||||
one.
|
||||
Also see |line2byte()|, |go| and |:goto|.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
GetOffset()->byte2line()
|
||||
|
||||
byteidx({expr}, {nr}) *byteidx()*
|
||||
Return byte index of the {nr}'th character in the string
|
||||
{expr}. Use zero for the first character, it then returns
|
||||
@ -2899,6 +2980,9 @@ byteidx({expr}, {nr}) *byteidx()*
|
||||
If there are exactly {nr} characters the length of the string
|
||||
in bytes is returned.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
GetName()->byteidx(idx)
|
||||
|
||||
byteidxcomp({expr}, {nr}) *byteidxcomp()*
|
||||
Like byteidx(), except that a composing character is counted
|
||||
as a separate character. Example: >
|
||||
@ -2912,6 +2996,9 @@ byteidxcomp({expr}, {nr}) *byteidxcomp()*
|
||||
Only works differently from byteidx() when 'encoding' is set to
|
||||
a Unicode encoding.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
GetName()->byteidxcomp(idx)
|
||||
|
||||
call({func}, {arglist} [, {dict}]) *call()* *E699*
|
||||
Call function {func} with the items in |List| {arglist} as
|
||||
arguments.
|
||||
@ -2921,6 +3008,9 @@ call({func}, {arglist} [, {dict}]) *call()* *E699*
|
||||
{dict} is for functions with the "dict" attribute. It will be
|
||||
used to set the local variable "self". |Dictionary-function|
|
||||
|
||||
Can also be used as a |method|: >
|
||||
GetFunc()->call([arg, arg], dict)
|
||||
|
||||
ceil({expr}) *ceil()*
|
||||
Return the smallest integral value greater than or equal to
|
||||
{expr} as a |Float| (round up).
|
||||
@ -2933,6 +3023,9 @@ ceil({expr}) *ceil()*
|
||||
echo ceil(4.0)
|
||||
< 4.0
|
||||
|
||||
Can also be used as a |method|: >
|
||||
Compute()->ceil()
|
||||
|
||||
changenr() *changenr()*
|
||||
Return the number of the most recent change. This is the same
|
||||
number as what is displayed with |:undolist| and can be used
|
||||
@ -2982,6 +3075,9 @@ char2nr({expr} [, {utf8}]) *char2nr()*
|
||||
A combining character is a separate character.
|
||||
|nr2char()| does the opposite.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
GetChar()->char2nr()
|
||||
|
||||
*charidx()*
|
||||
charidx({string}, {idx} [, {countcc}])
|
||||
Return the character index of the byte at {idx} in {string}.
|
||||
@ -3013,12 +3109,18 @@ cindent({lnum}) *cindent()*
|
||||
When {lnum} is invalid -1 is returned.
|
||||
See |C-indenting|.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
GetLnum()->cindent()
|
||||
|
||||
clearmatches([{win}]) *clearmatches()*
|
||||
Clears all matches previously defined for the current window
|
||||
by |matchadd()| and the |:match| commands.
|
||||
If {win} is specified, use the window with this number or
|
||||
window ID instead of the current window.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
GetWin()->clearmatches()
|
||||
<
|
||||
*col()*
|
||||
col({expr}) The result is a Number, which is the byte index of the column
|
||||
position given with {expr}. The accepted positions are:
|
||||
@ -3054,6 +3156,9 @@ col({expr}) The result is a Number, which is the byte index of the column
|
||||
\<C-O>:set ve=all<CR>
|
||||
\<C-O>:echo col(".") . "\n" <Bar>
|
||||
\let &ve = save_ve<CR>
|
||||
|
||||
< Can also be used as a |method|: >
|
||||
GetPos()->col()
|
||||
<
|
||||
|
||||
complete({startcol}, {matches}) *complete()* *E785*
|
||||
@ -3085,6 +3190,10 @@ complete({startcol}, {matches}) *complete()* *E785*
|
||||
< This isn't very useful, but it shows how it works. Note that
|
||||
an empty string is returned to avoid a zero being inserted.
|
||||
|
||||
Can also be used as a |method|, the second argument is passed
|
||||
in: >
|
||||
GetMatches()->complete(col('.'))
|
||||
|
||||
complete_add({expr}) *complete_add()*
|
||||
Add {expr} to the list of matches. Only to be used by the
|
||||
function specified with the 'completefunc' option.
|
||||
@ -3094,6 +3203,9 @@ complete_add({expr}) *complete_add()*
|
||||
See |complete-functions| for an explanation of {expr}. It is
|
||||
the same as one item in the list that 'omnifunc' would return.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
GetMoreMatches()->complete_add()
|
||||
|
||||
complete_check() *complete_check()*
|
||||
Check for a key typed while looking for completion matches.
|
||||
This is to be used when looking for matches takes some time.
|
||||
@ -3154,6 +3266,9 @@ complete_info([{what}])
|
||||
call complete_info(['mode'])
|
||||
" Get only 'mode' and 'pum_visible'
|
||||
call complete_info(['mode', 'pum_visible'])
|
||||
|
||||
< Can also be used as a |method|: >
|
||||
GetItems()->complete_info()
|
||||
<
|
||||
*confirm()*
|
||||
confirm({msg} [, {choices} [, {default} [, {type}]]])
|
||||
@ -3207,6 +3322,9 @@ confirm({msg} [, {choices} [, {default} [, {type}]]])
|
||||
don't fit, a vertical layout is used anyway. For some systems
|
||||
the horizontal layout is always used.
|
||||
|
||||
Can also be used as a |method|in: >
|
||||
BuildMessage()->confirm("&Yes\n&No")
|
||||
|
||||
*copy()*
|
||||
copy({expr}) Make a copy of {expr}. For Numbers and Strings this isn't
|
||||
different from using {expr} directly.
|
||||
@ -3216,6 +3334,8 @@ copy({expr}) Make a copy of {expr}. For Numbers and Strings this isn't
|
||||
changing an item changes the contents of both |Lists|.
|
||||
A |Dictionary| is copied in a similar way as a |List|.
|
||||
Also see |deepcopy()|.
|
||||
Can also be used as a |method|: >
|
||||
mylist->copy()
|
||||
|
||||
cos({expr}) *cos()*
|
||||
Return the cosine of {expr}, measured in radians, as a |Float|.
|
||||
@ -3226,6 +3346,8 @@ cos({expr}) *cos()*
|
||||
:echo cos(-4.01)
|
||||
< -0.646043
|
||||
|
||||
Can also be used as a |method|: >
|
||||
Compute()->cos()
|
||||
|
||||
cosh({expr}) *cosh()*
|
||||
Return the hyperbolic cosine of {expr} as a |Float| in the range
|
||||
@ -3237,6 +3359,8 @@ cosh({expr}) *cosh()*
|
||||
:echo cosh(-0.5)
|
||||
< -1.127626
|
||||
|
||||
Can also be used as a |method|: >
|
||||
Compute()->cosh()
|
||||
|
||||
count({comp}, {expr} [, {ic} [, {start}]]) *count()*
|
||||
Return the number of times an item with value {expr} appears
|
||||
@ -3251,6 +3375,9 @@ count({comp}, {expr} [, {ic} [, {start}]]) *count()*
|
||||
occurrences of {expr} is returned. Zero is returned when
|
||||
{expr} is an empty string.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
mylist->count(val)
|
||||
|
||||
*cscope_connection()*
|
||||
cscope_connection([{num} , {dbpath} [, {prepend}]])
|
||||
Checks for the existence of a |cscope| connection. If no
|
||||
@ -3346,6 +3473,8 @@ cursor({list})
|
||||
position within a <Tab> or after the last character.
|
||||
Returns 0 when the position could be set, -1 otherwise.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
GetCursorPos()->cursor()
|
||||
|
||||
deepcopy({expr}[, {noref}]) *deepcopy()* *E698*
|
||||
Make a copy of {expr}. For Numbers and Strings this isn't
|
||||
@ -3367,6 +3496,9 @@ deepcopy({expr}[, {noref}]) *deepcopy()* *E698*
|
||||
{noref} set to 1 will fail.
|
||||
Also see |copy()|.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
GetObject()->deepcopy()
|
||||
|
||||
delete({fname} [, {flags}]) *delete()*
|
||||
Without {flags} or with {flags} empty: Deletes the file by the
|
||||
name {fname}. This also works when {fname} is a symbolic link.
|
||||
@ -3384,6 +3516,9 @@ delete({fname} [, {flags}]) *delete()*
|
||||
operation was successful and -1/true when the deletion failed
|
||||
or partly failed.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
GetName()->delete()
|
||||
|
||||
deletebufline({expr}, {first}[, {last}]) *deletebufline()*
|
||||
Delete lines {first} to {last} (inclusive) from buffer {expr}.
|
||||
If {last} is omitted then delete line {first} only.
|
||||
@ -3398,6 +3533,9 @@ deletebufline({expr}, {first}[, {last}]) *deletebufline()*
|
||||
when using |line()| this refers to the current buffer. Use "$"
|
||||
to refer to the last line in buffer {expr}.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
GetBuffer()->deletebufline(1)
|
||||
|
||||
dictwatcheradd({dict}, {pattern}, {callback}) *dictwatcheradd()*
|
||||
Adds a watcher to a dictionary. A dictionary watcher is
|
||||
identified by three components:
|
||||
@ -3464,6 +3602,9 @@ diff_filler({lnum}) *diff_filler()*
|
||||
line, "'m" mark m, etc.
|
||||
Returns 0 if the current window is not in diff mode.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
GetLnum()->diff_filler()
|
||||
|
||||
diff_hlID({lnum}, {col}) *diff_hlID()*
|
||||
Returns the highlight ID for diff mode at line {lnum} column
|
||||
{col} (byte index). When the current line does not have a
|
||||
@ -3475,11 +3616,16 @@ diff_hlID({lnum}, {col}) *diff_hlID()*
|
||||
The highlight ID can be used with |synIDattr()| to obtain
|
||||
syntax information about the highlighting.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
GetLnum()->diff_hlID(col)
|
||||
|
||||
empty({expr}) *empty()*
|
||||
Return the Number 1 if {expr} is empty, zero otherwise.
|
||||
A |List| or |Dictionary| is empty when it does not have any
|
||||
items. A Number is empty when its value is zero. Special
|
||||
variable is empty when it is |v:false| or |v:null|.
|
||||
Can also be used as a |method|: >
|
||||
mylist->empty()
|
||||
|
||||
environ() *environ()*
|
||||
Return all of environment variables as dictionary. You can
|
||||
@ -3504,6 +3650,9 @@ eval({string}) Evaluate {string} and return the result. Especially useful to
|
||||
them. Also works for |Funcref|s that refer to existing
|
||||
functions.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
argv->join()->eval()
|
||||
|
||||
eventhandler() *eventhandler()*
|
||||
Returns 1 when inside an event handler. That is that Vim got
|
||||
interrupted while waiting for the user to type a character,
|
||||
@ -3661,12 +3810,18 @@ exp({expr}) *exp()*
|
||||
:echo exp(-1)
|
||||
< 0.367879
|
||||
|
||||
Can also be used as a |method|: >
|
||||
Compute()->exp()
|
||||
|
||||
debugbreak({pid}) *debugbreak()*
|
||||
Specifically used to interrupt a program being debugged. It
|
||||
will cause process {pid} to get a SIGTRAP. Behavior for other
|
||||
processes is undefined. See |terminal-debugger|.
|
||||
{Sends a SIGINT to a process {pid} other than MS-Windows}
|
||||
|
||||
Can also be used as a |method|: >
|
||||
GetPid()->debugbreak()
|
||||
|
||||
expand({expr} [, {nosuf} [, {list}]]) *expand()*
|
||||
Expand wildcards and the following special keywords in {expr}.
|
||||
'wildignorecase' applies.
|
||||
@ -3795,6 +3950,8 @@ extend({expr1}, {expr2} [, {expr3}]) *extend()*
|
||||
fails.
|
||||
Returns {expr1}.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
mylist->extend(otherlist)
|
||||
|
||||
feedkeys({string} [, {mode}]) *feedkeys()*
|
||||
Characters in {string} are queued for processing as if they
|
||||
@ -3848,7 +4005,11 @@ filereadable({file}) *filereadable()*
|
||||
expression, which is used as a String.
|
||||
If you don't care about the file being readable you can use
|
||||
|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()*
|
||||
The result is a Number, which is 1 when a file with the
|
||||
@ -3904,6 +4065,8 @@ filter({expr1}, {expr2}) *filter()*
|
||||
Funcref errors inside a function are ignored, unless it was
|
||||
defined with the "abort" flag.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
mylist->filter(expr2)
|
||||
|
||||
finddir({name} [, {path} [, {count}]]) *finddir()*
|
||||
Find directory {name} in {path}. Supports both downwards and
|
||||
@ -3966,6 +4129,8 @@ float2nr({expr}) *float2nr()*
|
||||
echo float2nr(1.0e-100)
|
||||
< 0
|
||||
|
||||
Can also be used as a |method|: >
|
||||
Compute()->float2nr()
|
||||
|
||||
floor({expr}) *floor()*
|
||||
Return the largest integral value less than or equal to
|
||||
@ -3979,6 +4144,8 @@ floor({expr}) *floor()*
|
||||
echo floor(4.0)
|
||||
< 4.0
|
||||
|
||||
Can also be used as a |method|: >
|
||||
Compute()->floor()
|
||||
|
||||
fmod({expr1}, {expr2}) *fmod()*
|
||||
Return the remainder of {expr1} / {expr2}, even if the
|
||||
@ -3994,6 +4161,8 @@ fmod({expr1}, {expr2}) *fmod()*
|
||||
:echo fmod(-12.33, 1.22)
|
||||
< -0.13
|
||||
|
||||
Can also be used as a |method|: >
|
||||
Compute()->fmod(1.22)
|
||||
|
||||
fnameescape({string}) *fnameescape()*
|
||||
Escape {string} for use as file name command argument. All
|
||||
@ -4160,6 +4329,8 @@ get({list}, {idx} [, {default}]) *get()*
|
||||
Get item {idx} from |List| {list}. When this item is not
|
||||
available return {default}. Return zero when {default} is
|
||||
omitted.
|
||||
Can also be used as a |method|: >
|
||||
mylist->get(idx)
|
||||
get({dict}, {key} [, {default}])
|
||||
Get item with key {key} from |Dictionary| {dict}. When this
|
||||
item is not available return {default}. Return zero when
|
||||
@ -5171,6 +5342,9 @@ has_key({dict}, {key}) *has_key()*
|
||||
The result is a Number, which is TRUE if |Dictionary| {dict}
|
||||
has an entry with key {key}. FALSE otherwise.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
mydict->has_key(key)
|
||||
|
||||
haslocaldir([{winnr}[, {tabnr}]]) *haslocaldir()*
|
||||
The result is a Number, which is 1 when the tabpage or window
|
||||
has set a local path via |:tcd| or |:lcd|, otherwise 0.
|
||||
@ -5514,6 +5688,9 @@ insert({list}, {item} [, {idx}]) *insert()*
|
||||
Note that when {item} is a |List| it is inserted as a single
|
||||
item. Use |extend()| to concatenate |Lists|.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
mylist->insert(item)
|
||||
|
||||
interrupt() *interrupt()*
|
||||
Interrupt script execution. It works more or less like the
|
||||
user typing CTRL-C, most commands won't execute and control
|
||||
@ -5531,6 +5708,8 @@ invert({expr}) *invert()*
|
||||
Bitwise invert. The argument is converted to a number. A
|
||||
List, Dict or Float argument causes an error. Example: >
|
||||
:let bits = invert(bits)
|
||||
< Can also be used as a |method|: >
|
||||
:let bits = bits->invert()
|
||||
|
||||
isdirectory({directory}) *isdirectory()*
|
||||
The result is a Number, which is |TRUE| when a directory
|
||||
@ -5546,6 +5725,9 @@ isinf({expr}) *isinf()*
|
||||
:echo isinf(-1.0 / 0.0)
|
||||
< -1
|
||||
|
||||
Can also be used as a |method|: >
|
||||
Compute()->isinf()
|
||||
|
||||
islocked({expr}) *islocked()* *E786*
|
||||
The result is a Number, which is |TRUE| when {expr} is the
|
||||
name of a locked variable.
|
||||
@ -5581,12 +5763,17 @@ items({dict}) *items()*
|
||||
|List| item is a list with two items: the key of a {dict}
|
||||
entry and the value of this entry. The |List| is in arbitrary
|
||||
order.
|
||||
Can also be used as a |method|: >
|
||||
mydict->items()
|
||||
|
||||
isnan({expr}) *isnan()*
|
||||
Return |TRUE| if {expr} is a float with value NaN. >
|
||||
echo isnan(0.0 / 0.0)
|
||||
< 1
|
||||
|
||||
Can also be used as a |method|: >
|
||||
Compute()->isnan()
|
||||
|
||||
jobpid({job}) *jobpid()*
|
||||
Return the PID (process id) of |job-id| {job}.
|
||||
|
||||
@ -5714,6 +5901,9 @@ join({list} [, {sep}]) *join()*
|
||||
converted into a string like with |string()|.
|
||||
The opposite function is |split()|.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
mylist->join()
|
||||
|
||||
json_decode({expr}) *json_decode()*
|
||||
Convert {expr} from JSON object. Accepts |readfile()|-style
|
||||
list as the input, as well as regular string. May output any
|
||||
@ -5744,8 +5934,10 @@ json_encode({expr}) *json_encode()*
|
||||
keys({dict}) *keys()*
|
||||
Return a |List| with all the keys of {dict}. The |List| is in
|
||||
arbitrary order.
|
||||
Can also be used as a |method|: >
|
||||
mydict->keys()
|
||||
|
||||
*len()* *E701*
|
||||
< *len()* *E701*
|
||||
len({expr}) The result is a Number, which is the length of the argument.
|
||||
When {expr} is a String or a Number the length in bytes is
|
||||
used, as with |strlen()|.
|
||||
@ -5756,7 +5948,10 @@ len({expr}) The result is a Number, which is the length of the argument.
|
||||
|Dictionary| is returned.
|
||||
Otherwise an error is given.
|
||||
|
||||
*libcall()* *E364* *E368*
|
||||
Can also be used as a |method|: >
|
||||
mylist->len()
|
||||
|
||||
< *libcall()* *E364* *E368*
|
||||
libcall({libname}, {funcname}, {argument})
|
||||
Call function {funcname} in the run-time library {libname}
|
||||
with single argument {argument}.
|
||||
@ -5881,6 +6076,8 @@ log({expr}) *log()*
|
||||
:echo log(exp(5))
|
||||
< 5.0
|
||||
|
||||
Can also be used as a |method|: >
|
||||
Compute()->log()
|
||||
|
||||
log10({expr}) *log10()*
|
||||
Return the logarithm of Float {expr} to base 10 as a |Float|.
|
||||
@ -5891,6 +6088,9 @@ log10({expr}) *log10()*
|
||||
:echo log10(0.01)
|
||||
< -2.0
|
||||
|
||||
Can also be used as a |method|: >
|
||||
Compute()->log10()
|
||||
|
||||
luaeval({expr}[, {expr}])
|
||||
Evaluate Lua expression {expr} and return its result converted
|
||||
to Vim data structures. See |lua-eval| for more details.
|
||||
@ -5939,6 +6139,8 @@ map({expr1}, {expr2}) *map()*
|
||||
Funcref errors inside a function are ignored, unless it was
|
||||
defined with the "abort" flag.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
mylist->map(expr2)
|
||||
|
||||
maparg({name} [, {mode} [, {abbr} [, {dict}]]]) *maparg()*
|
||||
When {dict} is omitted or zero: Return the rhs of mapping
|
||||
@ -6274,6 +6476,9 @@ max({expr}) Return the maximum value of all items in {expr}.
|
||||
items in {expr} cannot be used as a Number this results in
|
||||
an error. An empty |List| or |Dictionary| results in zero.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
mylist->max()
|
||||
|
||||
menu_get({path}, {modes}) *menu_get()*
|
||||
Returns a |List| of |Dictionaries| describing |menus| (defined
|
||||
by |:menu|, |:amenu|, …), including |hidden-menus|.
|
||||
@ -6328,7 +6533,10 @@ min({expr}) Return the minimum value of all items in {expr}.
|
||||
items in {expr} cannot be used as a Number this results in
|
||||
an error. An empty |List| or |Dictionary| results in zero.
|
||||
|
||||
*mkdir()* *E739*
|
||||
Can also be used as a |method|: >
|
||||
mylist->min()
|
||||
|
||||
< *mkdir()* *E739*
|
||||
mkdir({name} [, {path} [, {prot}]])
|
||||
Create directory {name}.
|
||||
If {path} is "p" then intermediate directories are created as
|
||||
@ -6523,7 +6731,8 @@ or({expr}, {expr}) *or()*
|
||||
to a number. A List, Dict or Float argument causes an error.
|
||||
Example: >
|
||||
:let bits = or(bits, 0x80)
|
||||
|
||||
< Can also be used as a |method|: >
|
||||
:let bits = bits->or(0x80)
|
||||
|
||||
pathshorten({expr}) *pathshorten()*
|
||||
Shorten directory names in the path {expr} and return the
|
||||
@ -6560,6 +6769,9 @@ pow({x}, {y}) *pow()*
|
||||
:echo pow(32, 0.20)
|
||||
< 2.0
|
||||
|
||||
Can also be used as a |method|: >
|
||||
Compute()->pow(3)
|
||||
|
||||
prevnonblank({lnum}) *prevnonblank()*
|
||||
Return the line number of the first line at or above {lnum}
|
||||
that is not blank. Example: >
|
||||
@ -6576,7 +6788,11 @@ printf({fmt}, {expr1} ...) *printf()*
|
||||
< May result in:
|
||||
" 99: E42 asdfasdfasdfasdfasdfasdfasdfas" ~
|
||||
|
||||
Often used items are:
|
||||
When used as a |method| the base is passed as the second
|
||||
argument: >
|
||||
Compute()->printf("result: %d")
|
||||
|
||||
< Often used items are:
|
||||
%s string
|
||||
%6S string right-aligned in 6 display cells
|
||||
%6s string right-aligned in 6 bytes
|
||||
@ -7086,6 +7302,10 @@ remove({list}, {idx} [, {end}]) *remove()*
|
||||
Example: >
|
||||
:echo "last item: " . remove(mylist, -1)
|
||||
:call remove(mylist, 0, 9)
|
||||
|
||||
< Can also be used as a |method|: >
|
||||
mylist->remove(idx)
|
||||
|
||||
remove({dict}, {key})
|
||||
Remove the entry from {dict} with key {key} and return it.
|
||||
Example: >
|
||||
@ -7112,6 +7332,8 @@ repeat({expr}, {count}) *repeat()*
|
||||
:let longlist = repeat(['a', 'b'], 3)
|
||||
< Results in ['a', 'b', 'a', 'b', 'a', 'b'].
|
||||
|
||||
Can also be used as a |method|: >
|
||||
mylist->repeat(count)
|
||||
|
||||
resolve({filename}) *resolve()* *E655*
|
||||
On MS-Windows, when {filename} is a shortcut (a .lnk file),
|
||||
@ -7131,6 +7353,8 @@ reverse({list}) Reverse the order of items in {list} in-place. Returns
|
||||
{list}.
|
||||
If you want a list to remain unmodified make a copy first: >
|
||||
:let revlist = reverse(copy(mylist))
|
||||
< Can also be used as a |method|: >
|
||||
mylist->reverse()
|
||||
|
||||
round({expr}) *round()*
|
||||
Round off {expr} to the nearest integral value and return it
|
||||
@ -7145,6 +7369,9 @@ round({expr}) *round()*
|
||||
echo round(-4.5)
|
||||
< -5.0
|
||||
|
||||
Can also be used as a |method|: >
|
||||
Compute()->round()
|
||||
|
||||
rpcnotify({channel}, {event}[, {args}...]) *rpcnotify()*
|
||||
Sends {event} to {channel} via |RPC| and returns immediately.
|
||||
If {channel} is 0, the event is broadcast to all channels.
|
||||
@ -8121,6 +8348,8 @@ sin({expr}) *sin()*
|
||||
:echo sin(-4.01)
|
||||
< 0.763301
|
||||
|
||||
Can also be used as a |method|: >
|
||||
Compute()->sin()
|
||||
|
||||
sinh({expr}) *sinh()*
|
||||
Return the hyperbolic sine of {expr} as a |Float| in the range
|
||||
@ -8132,6 +8361,9 @@ sinh({expr}) *sinh()*
|
||||
:echo sinh(-0.9)
|
||||
< -1.026517
|
||||
|
||||
Can also be used as a |method|: >
|
||||
Compute()->sinh()
|
||||
|
||||
sockconnect({mode}, {address}, {opts}) *sockconnect()*
|
||||
Connect a socket to an address. If {mode} is "pipe" then
|
||||
{address} should be the path of a named pipe. If {mode} is
|
||||
@ -8210,7 +8442,10 @@ sort({list} [, {func} [, {dict}]]) *sort()* *E702*
|
||||
on numbers, text strings will sort next to each other, in the
|
||||
same order as they were originally.
|
||||
|
||||
Also see |uniq()|.
|
||||
Can also be used as a |method|: >
|
||||
mylist->sort()
|
||||
|
||||
< Also see |uniq()|.
|
||||
|
||||
Example: >
|
||||
func MyCompare(i1, i2)
|
||||
@ -8303,6 +8538,8 @@ split({expr} [, {pattern} [, {keepempty}]]) *split()*
|
||||
:let items = split(line, ':', 1)
|
||||
< The opposite function is |join()|.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
GetString()->split()
|
||||
|
||||
sqrt({expr}) *sqrt()*
|
||||
Return the non-negative square root of Float {expr} as a
|
||||
@ -8316,6 +8553,8 @@ sqrt({expr}) *sqrt()*
|
||||
< nan
|
||||
"nan" may be different, it depends on system libraries.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
Compute()->sqrt()
|
||||
|
||||
stdioopen({opts}) *stdioopen()*
|
||||
With |--headless| this opens stdin and stdout as a |channel|.
|
||||
@ -8367,6 +8606,9 @@ str2float({expr}) *str2float()*
|
||||
12.0. You can strip out thousands separators with
|
||||
|substitute()|: >
|
||||
let f = str2float(substitute(text, ',', '', 'g'))
|
||||
<
|
||||
Can also be used as a |method|: >
|
||||
let f = text->substitute(',', '', 'g')->str2float()
|
||||
|
||||
str2list({expr} [, {utf8}]) *str2list()*
|
||||
Return a list containing the number values which represent
|
||||
@ -8381,12 +8623,18 @@ str2list({expr} [, {utf8}]) *str2list()*
|
||||
properly: >
|
||||
str2list("á") returns [97, 769]
|
||||
|
||||
< Can also be used as a |method|: >
|
||||
GetString()->str2list()
|
||||
|
||||
str2nr({expr} [, {base}]) *str2nr()*
|
||||
Convert string {expr} to a number.
|
||||
{base} is the conversion base, it can be 2, 8, 10 or 16.
|
||||
|
||||
When {base} is omitted base 10 is used. This also means that
|
||||
a leading zero doesn't cause octal conversion to be used, as
|
||||
with the default String to Number conversion.
|
||||
with the default String to Number conversion. Example: >
|
||||
let nr = str2nr('123')
|
||||
<
|
||||
When {base} is 16 a leading "0x" or "0X" is ignored. With a
|
||||
different base the result will be zero. Similarly, when {base}
|
||||
is 8 a leading "0" is ignored, and when {base} is 2 a leading
|
||||
@ -8505,6 +8753,9 @@ string({expr}) Return {expr} converted to a String. If {expr} is a Number,
|
||||
method, use |msgpackdump()| or |json_encode()| if you need to
|
||||
share data with other application.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
mylist->string()
|
||||
|
||||
*strlen()*
|
||||
strlen({expr}) The result is a Number, which is the length of the String
|
||||
{expr} in bytes.
|
||||
@ -8514,6 +8765,9 @@ strlen({expr}) The result is a Number, which is the length of the String
|
||||
|strchars()|.
|
||||
Also see |len()|, |strdisplaywidth()| and |strwidth()|.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
GetString()->strlen()
|
||||
|
||||
strpart({src}, {start} [, {len} [, {chars}]]) *strpart()*
|
||||
The result is a String, which is part of {src}, starting from
|
||||
byte {start}, with the byte length {len}.
|
||||
@ -8588,6 +8842,9 @@ strtrans({expr}) *strtrans()*
|
||||
< This displays a newline in register a as "^@" instead of
|
||||
starting a new line.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
GetString()->strtrans()
|
||||
|
||||
strwidth({expr}) *strwidth()*
|
||||
The result is a Number, which is the number of display cells
|
||||
String {expr} occupies. A Tab character is counted as one
|
||||
@ -8596,6 +8853,9 @@ strwidth({expr}) *strwidth()*
|
||||
Ambiguous, this function's return value depends on 'ambiwidth'.
|
||||
Also see |strlen()|, |strdisplaywidth()| and |strchars()|.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
GetString()->strwidth()
|
||||
|
||||
submatch({nr} [, {list}]) *submatch()* *E935*
|
||||
Only for an expression in a |:substitute| command or
|
||||
substitute() function.
|
||||
@ -8663,6 +8923,9 @@ substitute({expr}, {pat}, {sub}, {flags}) *substitute()*
|
||||
|submatch()| returns. Example: >
|
||||
:echo substitute(s, '%\(\x\x\)', {m -> '0x' . m[1]}, 'g')
|
||||
|
||||
< Can also be used as a |method|: >
|
||||
GetString()->substitute(pat, sub, flags)
|
||||
|
||||
swapinfo({fname}) *swapinfo()*
|
||||
The result is a dictionary, which holds information about the
|
||||
swapfile {fname}. The available fields are:
|
||||
@ -8747,12 +9010,18 @@ synIDattr({synID}, {what} [, {mode}]) *synIDattr()*
|
||||
cursor): >
|
||||
:echo synIDattr(synIDtrans(synID(line("."), col("."), 1)), "fg")
|
||||
<
|
||||
Can also be used as a |method|: >
|
||||
:echo synID(line("."), col("."), 1)->synIDtrans()->synIDattr("fg")
|
||||
|
||||
synIDtrans({synID}) *synIDtrans()*
|
||||
The result is a Number, which is the translated syntax ID of
|
||||
{synID}. This is the syntax group ID of what is being used to
|
||||
highlight the character. Highlight links given with
|
||||
":highlight link" are followed.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
:echo synID(line("."), col("."), 1)->synIDtrans()->synIDattr("fg")
|
||||
|
||||
synconcealed({lnum}, {col}) *synconcealed()*
|
||||
The result is a |List| with currently three items:
|
||||
1. The first item in the list is 0 if the character at the
|
||||
@ -8849,6 +9118,8 @@ system({cmd} [, {input}]) *system()* *E677*
|
||||
Unlike ":!cmd" there is no automatic check for changed files.
|
||||
Use |:checktime| to force a check.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
:echo GetCmd()->system()
|
||||
|
||||
systemlist({cmd} [, {input} [, {keepempty}]]) *systemlist()*
|
||||
Same as |system()|, but returns a |List| with lines (parts of
|
||||
@ -8864,6 +9135,8 @@ systemlist({cmd} [, {input} [, {keepempty}]]) *systemlist()*
|
||||
<
|
||||
Returns an empty string on error.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
:echo GetCmd()->systemlist()
|
||||
|
||||
tabpagebuflist([{arg}]) *tabpagebuflist()*
|
||||
The result is a |List|, where each item is the number of the
|
||||
@ -8987,6 +9260,8 @@ tan({expr}) *tan()*
|
||||
:echo tan(-4.01)
|
||||
< -1.181502
|
||||
|
||||
Can also be used as a |method|: >
|
||||
Compute()->tan()
|
||||
|
||||
tanh({expr}) *tanh()*
|
||||
Return the hyperbolic tangent of {expr} as a |Float| in the
|
||||
@ -8998,6 +9273,8 @@ tanh({expr}) *tanh()*
|
||||
:echo tanh(-1)
|
||||
< -0.761594
|
||||
|
||||
Can also be used as a |method|: >
|
||||
Compute()->tanh()
|
||||
|
||||
*timer_info()*
|
||||
timer_info([{id}])
|
||||
@ -9124,6 +9401,9 @@ trunc({expr}) *trunc()*
|
||||
echo trunc(4.0)
|
||||
< 4.0
|
||||
|
||||
Can also be used as a |method|: >
|
||||
Compute()->trunc()
|
||||
|
||||
type({expr}) *type()*
|
||||
The result is a Number representing the type of {expr}.
|
||||
Instead of using the number directly, it is better to use the
|
||||
@ -9150,6 +9430,9 @@ type({expr}) *type()*
|
||||
< To check if the v:t_ variables exist use this: >
|
||||
:if exists('v:t_number')
|
||||
|
||||
< Can also be used as a |method|: >
|
||||
mylist->type()
|
||||
|
||||
undofile({name}) *undofile()*
|
||||
Return the name of the undo file that would be used for a file
|
||||
with name {name} when writing. This uses the 'undodir'
|
||||
@ -9212,10 +9495,15 @@ uniq({list} [, {func} [, {dict}]]) *uniq()* *E882*
|
||||
< The default compare function uses the string representation of
|
||||
each item. For the use of {func} and {dict} see |sort()|.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
mylist->uniq()
|
||||
|
||||
values({dict}) *values()*
|
||||
Return a |List| with all the values of {dict}. The |List| is
|
||||
in arbitrary order.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
mydict->values()
|
||||
|
||||
virtcol({expr}) *virtcol()*
|
||||
The result is a Number, which is the screen column of the file
|
||||
@ -9392,6 +9680,9 @@ winbufnr({nr}) The result is a Number, which is the number of the buffer
|
||||
When window {nr} doesn't exist, -1 is returned.
|
||||
Example: >
|
||||
:echo "The file in the current window is " . bufname(winbufnr(0))
|
||||
<
|
||||
Can also be used as a |method|: >
|
||||
FindWindow()->winbufnr()->bufname()
|
||||
<
|
||||
*wincol()*
|
||||
wincol() The result is a Number, which is the virtual column of the
|
||||
@ -9606,6 +9897,8 @@ xor({expr}, {expr}) *xor()*
|
||||
to a number. A List, Dict or Float argument causes an error.
|
||||
Example: >
|
||||
:let bits = xor(bits, 0x80)
|
||||
< Can also be used as a |method|: >
|
||||
:let bits = bits->xor(0x80)
|
||||
<
|
||||
|
||||
|
||||
@ -9943,7 +10236,9 @@ This function can then be called with: >
|
||||
The recursiveness of user functions is restricted with the |'maxfuncdepth'|
|
||||
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 ~
|
||||
@ -10686,7 +10981,7 @@ text...
|
||||
<
|
||||
*:eval*
|
||||
: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,
|
||||
since the resulting value is not used. In the example
|
||||
|
@ -391,6 +391,10 @@ where the args are converted to Lua values. The expression >
|
||||
is equivalent to the Lua chunk >
|
||||
return somemod.func(...)
|
||||
|
||||
The `v:lua` prefix may be used to call Lua functions as |method|s. For
|
||||
example: >
|
||||
arg1->v:lua.somemod.func(arg2)
|
||||
|
||||
You can use `v:lua` in "func" options like 'tagfunc', 'omnifunc', etc.
|
||||
For example consider the following Lua omnifunc handler: >
|
||||
|
||||
|
@ -53,6 +53,9 @@ assert_beeps({cmd}) *assert_beeps()*
|
||||
Also see |assert_fails()|, |assert_nobeep()| and
|
||||
|assert-return|.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
GetCmd()->assert_beeps()
|
||||
<
|
||||
*assert_equal()*
|
||||
assert_equal({expected}, {actual} [, {msg}])
|
||||
When {expected} and {actual} are not equal an error message is
|
||||
@ -69,7 +72,10 @@ assert_equal({expected}, {actual} [, {msg}])
|
||||
< Will result in a string to be added to |v:errors|:
|
||||
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})
|
||||
When the files {fname-one} and {fname-two} do not contain
|
||||
exactly the same text an error message is added to |v:errors|.
|
||||
@ -77,6 +83,9 @@ assert_equalfile({fname-one}, {fname-two})
|
||||
When {fname-one} or {fname-two} does not exist the error will
|
||||
mention that.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
GetLog()->assert_equalfile('expected.log')
|
||||
|
||||
assert_exception({error} [, {msg}]) *assert_exception()*
|
||||
When v:exception does not contain the string {error} an error
|
||||
message is added to |v:errors|. Also see |assert-return|.
|
||||
@ -97,6 +106,9 @@ assert_fails({cmd} [, {error} [, {msg}]]) *assert_fails()*
|
||||
Note that beeping is not considered an error, and some failing
|
||||
commands only beep. Use |assert_beeps()| for those.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
GetCmd()->assert_fails('E99:')
|
||||
|
||||
assert_false({actual} [, {msg}]) *assert_false()*
|
||||
When {actual} is not false an error message is added to
|
||||
|v:errors|, like with |assert_equal()|.
|
||||
@ -106,6 +118,9 @@ assert_false({actual} [, {msg}]) *assert_false()*
|
||||
When {msg} is omitted an error in the form
|
||||
"Expected False but got {actual}" is produced.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
GetResult()->assert_false()
|
||||
|
||||
assert_inrange({lower}, {upper}, {actual} [, {msg}]) *assert_inrange()*
|
||||
This asserts number and |Float| values. When {actual} is lower
|
||||
than {lower} or higher than {upper} an error message is added
|
||||
@ -134,6 +149,9 @@ assert_match({pattern}, {actual} [, {msg}])
|
||||
< Will result in a string to be added to |v:errors|:
|
||||
test.vim line 12: Pattern '^f.*o$' does not match 'foobar' ~
|
||||
|
||||
Can also be used as a |method|: >
|
||||
getFile()->assert_match('foo.*')
|
||||
<
|
||||
assert_nobeep({cmd}) *assert_nobeep()*
|
||||
Run {cmd} and add an error message to |v:errors| if it
|
||||
produces a beep or visual bell.
|
||||
@ -145,16 +163,27 @@ assert_notequal({expected}, {actual} [, {msg}])
|
||||
|v:errors| when {expected} and {actual} are equal.
|
||||
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}])
|
||||
The opposite of `assert_match()`: add an error message to
|
||||
|v:errors| when {pattern} matches {actual}.
|
||||
Also see |assert-return|.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
getFile()->assert_notmatch('bar.*')
|
||||
|
||||
|
||||
assert_report({msg}) *assert_report()*
|
||||
Report a test failure directly, using {msg}.
|
||||
Always returns one.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
GetMessage()->assert_report()
|
||||
|
||||
|
||||
assert_true({actual} [, {msg}]) *assert_true()*
|
||||
When {actual} is not true an error message is added to
|
||||
|v:errors|, like with |assert_equal()|.
|
||||
@ -164,5 +193,8 @@ assert_true({actual} [, {msg}]) *assert_true()*
|
||||
When {msg} is omitted an error in the form "Expected True but
|
||||
got {actual}" is produced.
|
||||
|
||||
Can also be used as a |method|: >
|
||||
GetResult()->assert_true()
|
||||
<
|
||||
|
||||
vim:tw=78:ts=8:noet:ft=help:norl:
|
||||
|
@ -608,12 +608,15 @@ static Object _call_function(String fn, Array args, dict_T *self, Error *err)
|
||||
recursive++;
|
||||
try_start();
|
||||
typval_T rettv;
|
||||
int dummy;
|
||||
funcexe_T funcexe = FUNCEXE_INIT;
|
||||
funcexe.firstline = curwin->w_cursor.lnum;
|
||||
funcexe.lastline = curwin->w_cursor.lnum;
|
||||
funcexe.evaluate = true;
|
||||
funcexe.selfdict = self;
|
||||
// call_func() retval is deceptive, ignore it. Instead we set `msg_list`
|
||||
// (see above) to capture abort-causing non-exception errors.
|
||||
(void)call_func((char_u *)fn.data, (int)fn.size, &rettv, (int)args.size,
|
||||
vim_args, NULL, curwin->w_cursor.lnum, curwin->w_cursor.lnum,
|
||||
&dummy, true, NULL, self);
|
||||
vim_args, &funcexe);
|
||||
if (!try_end(err)) {
|
||||
rv = vim_to_object(&rettv);
|
||||
}
|
||||
|
531
src/nvim/eval.c
531
src/nvim/eval.c
@ -65,6 +65,8 @@ static char *e_missbrac = N_("E111: Missing ']'");
|
||||
static char *e_dictrange = N_("E719: Cannot use [:] with a Dictionary");
|
||||
static char *e_illvar = N_("E461: Illegal variable name: %s");
|
||||
static char *e_cannot_mod = N_("E995: Cannot modify existing variable");
|
||||
static char *e_nowhitespace
|
||||
= N_("E274: No white space allowed before parenthesis");
|
||||
static char *e_invalwindow = N_("E957: Invalid window number");
|
||||
static char *e_lock_unlock = N_("E940: Cannot lock or unlock variable %s");
|
||||
|
||||
@ -736,15 +738,15 @@ int eval_expr_typval(const typval_T *expr, typval_T *argv,
|
||||
int argc, typval_T *rettv)
|
||||
FUNC_ATTR_NONNULL_ARG(1, 2, 4)
|
||||
{
|
||||
int dummy;
|
||||
funcexe_T funcexe = FUNCEXE_INIT;
|
||||
|
||||
if (expr->v_type == VAR_FUNC) {
|
||||
const char_u *const s = expr->vval.v_string;
|
||||
if (s == NULL || *s == NUL) {
|
||||
return FAIL;
|
||||
}
|
||||
if (call_func(s, -1, rettv, argc, argv, NULL,
|
||||
0L, 0L, &dummy, true, NULL, NULL) == FAIL) {
|
||||
funcexe.evaluate = true;
|
||||
if (call_func(s, -1, rettv, argc, argv, &funcexe) == FAIL) {
|
||||
return FAIL;
|
||||
}
|
||||
} else if (expr->v_type == VAR_PARTIAL) {
|
||||
@ -753,8 +755,9 @@ int eval_expr_typval(const typval_T *expr, typval_T *argv,
|
||||
if (s == NULL || *s == NUL) {
|
||||
return FAIL;
|
||||
}
|
||||
if (call_func(s, -1, rettv, argc, argv, NULL,
|
||||
0L, 0L, &dummy, true, partial, NULL) == FAIL) {
|
||||
funcexe.evaluate = true;
|
||||
funcexe.partial = partial;
|
||||
if (call_func(s, -1, rettv, argc, argv, &funcexe) == FAIL) {
|
||||
return FAIL;
|
||||
}
|
||||
} else {
|
||||
@ -1050,7 +1053,6 @@ int call_vim_function(
|
||||
)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
int doesrange;
|
||||
int ret;
|
||||
int len = (int)STRLEN(func);
|
||||
partial_T *pt = NULL;
|
||||
@ -1066,9 +1068,12 @@ int call_vim_function(
|
||||
}
|
||||
|
||||
rettv->v_type = VAR_UNKNOWN; // tv_clear() uses this.
|
||||
ret = call_func(func, len, rettv, argc, argv, NULL,
|
||||
curwin->w_cursor.lnum, curwin->w_cursor.lnum,
|
||||
&doesrange, true, pt, NULL);
|
||||
funcexe_T funcexe = FUNCEXE_INIT;
|
||||
funcexe.firstline = curwin->w_cursor.lnum;
|
||||
funcexe.lastline = curwin->w_cursor.lnum;
|
||||
funcexe.evaluate = true;
|
||||
funcexe.partial = pt;
|
||||
ret = call_func(func, len, rettv, argc, argv, &funcexe);
|
||||
|
||||
fail:
|
||||
if (ret == FAIL) {
|
||||
@ -1724,7 +1729,9 @@ static const char *list_arg_vars(exarg_T *eap, const char *arg, int *first)
|
||||
} else {
|
||||
// handle d.key, l[idx], f(expr)
|
||||
const char *const arg_subsc = arg;
|
||||
if (handle_subscript(&arg, &tv, true, true) == FAIL) {
|
||||
if (handle_subscript(&arg, &tv, true, true, (const char_u *)name,
|
||||
(const char_u **)&name)
|
||||
== FAIL) {
|
||||
error = true;
|
||||
} else {
|
||||
if (arg == arg_subsc && len == 2 && name[1] == ':') {
|
||||
@ -3142,6 +3149,65 @@ static int pattern_match(char_u *pat, char_u *text, bool ic)
|
||||
return matches;
|
||||
}
|
||||
|
||||
/// Handle a name followed by "(". Both for just "name(arg)" and for
|
||||
/// "expr->name(arg)".
|
||||
//
|
||||
/// @param arg Points to "(", will be advanced
|
||||
/// @param basetv "expr" for "expr->name(arg)"
|
||||
//
|
||||
/// @return OK or FAIL.
|
||||
static int eval_func(char_u **const arg, char_u *const name, const int name_len,
|
||||
typval_T *const rettv, const bool evaluate,
|
||||
typval_T *const basetv)
|
||||
FUNC_ATTR_NONNULL_ARG(1, 2, 4)
|
||||
{
|
||||
char_u *s = name;
|
||||
int len = name_len;
|
||||
|
||||
if (!evaluate) {
|
||||
check_vars((const char *)s, len);
|
||||
}
|
||||
|
||||
// If "s" is the name of a variable of type VAR_FUNC
|
||||
// use its contents.
|
||||
partial_T *partial;
|
||||
s = deref_func_name((const char *)s, &len, &partial, !evaluate);
|
||||
|
||||
// Need to make a copy, in case evaluating the arguments makes
|
||||
// the name invalid.
|
||||
s = xmemdupz(s, len);
|
||||
|
||||
// Invoke the function.
|
||||
funcexe_T funcexe = FUNCEXE_INIT;
|
||||
funcexe.firstline = curwin->w_cursor.lnum;
|
||||
funcexe.lastline = curwin->w_cursor.lnum;
|
||||
funcexe.evaluate = evaluate;
|
||||
funcexe.partial = partial;
|
||||
funcexe.basetv = basetv;
|
||||
int ret = get_func_tv(s, len, rettv, arg, &funcexe);
|
||||
|
||||
xfree(s);
|
||||
|
||||
// If evaluate is false rettv->v_type was not set in
|
||||
// get_func_tv, but it's needed in handle_subscript() to parse
|
||||
// what follows. So set it here.
|
||||
if (rettv->v_type == VAR_UNKNOWN && !evaluate && **arg == '(') {
|
||||
rettv->vval.v_string = (char_u *)tv_empty_string;
|
||||
rettv->v_type = VAR_FUNC;
|
||||
}
|
||||
|
||||
// Stop the expression evaluation when immediately
|
||||
// aborting on error, or when an interrupt occurred or
|
||||
// an exception was thrown but not caught.
|
||||
if (evaluate && aborting()) {
|
||||
if (ret == OK) {
|
||||
tv_clear(rettv);
|
||||
}
|
||||
ret = FAIL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// TODO(ZyX-I): move to eval/expressions
|
||||
|
||||
/*
|
||||
@ -3161,6 +3227,8 @@ int eval0(char_u *arg, typval_T *rettv, char_u **nextcmd, int evaluate)
|
||||
{
|
||||
int ret;
|
||||
char_u *p;
|
||||
const int did_emsg_before = did_emsg;
|
||||
const int called_emsg_before = called_emsg;
|
||||
|
||||
p = skipwhite(arg);
|
||||
ret = eval1(&p, rettv, evaluate);
|
||||
@ -3170,8 +3238,10 @@ int eval0(char_u *arg, typval_T *rettv, char_u **nextcmd, int evaluate)
|
||||
}
|
||||
// Report the invalid expression unless the expression evaluation has
|
||||
// been cancelled due to an aborting error, an interrupt, or an
|
||||
// exception.
|
||||
if (!aborting()) {
|
||||
// exception, or we already gave a more specific error.
|
||||
// Also check called_emsg for when using assert_fails().
|
||||
if (!aborting() && did_emsg == did_emsg_before
|
||||
&& called_emsg == called_emsg_before) {
|
||||
emsgf(_(e_invexpr2), arg);
|
||||
}
|
||||
ret = FAIL;
|
||||
@ -3801,6 +3871,7 @@ static int eval6(char_u **arg, typval_T *rettv, int evaluate, int want_string)
|
||||
// + in front unary plus (ignored)
|
||||
// trailing [] subscript in String or List
|
||||
// trailing .name entry in Dictionary
|
||||
// trailing ->name() method call
|
||||
//
|
||||
// "arg" must point to the first non-white of the expression.
|
||||
// "arg" is advanced to the next non-white after the recognized expression.
|
||||
@ -3815,10 +3886,10 @@ static int eval7(
|
||||
{
|
||||
varnumber_T n;
|
||||
int len;
|
||||
char_u *s;
|
||||
char_u *start_leader, *end_leader;
|
||||
char_u *s;
|
||||
const char_u *start_leader, *end_leader;
|
||||
int ret = OK;
|
||||
char_u *alias;
|
||||
char_u *alias;
|
||||
|
||||
// Initialise variable so that tv_clear() can't mistake this for a
|
||||
// string and free a string that isn't there.
|
||||
@ -3968,44 +4039,7 @@ static int eval7(
|
||||
ret = FAIL;
|
||||
} else {
|
||||
if (**arg == '(') { // recursive!
|
||||
partial_T *partial;
|
||||
|
||||
if (!evaluate) {
|
||||
check_vars((const char *)s, len);
|
||||
}
|
||||
|
||||
// If "s" is the name of a variable of type VAR_FUNC
|
||||
// use its contents.
|
||||
s = deref_func_name((const char *)s, &len, &partial, !evaluate);
|
||||
|
||||
// Need to make a copy, in case evaluating the arguments makes
|
||||
// the name invalid.
|
||||
s = xmemdupz(s, len);
|
||||
|
||||
// Invoke the function.
|
||||
ret = get_func_tv(s, len, rettv, arg,
|
||||
curwin->w_cursor.lnum, curwin->w_cursor.lnum,
|
||||
&len, evaluate, partial, NULL);
|
||||
|
||||
xfree(s);
|
||||
|
||||
// If evaluate is false rettv->v_type was not set in
|
||||
// get_func_tv, but it's needed in handle_subscript() to parse
|
||||
// what follows. So set it here.
|
||||
if (rettv->v_type == VAR_UNKNOWN && !evaluate && **arg == '(') {
|
||||
rettv->vval.v_string = (char_u *)tv_empty_string;
|
||||
rettv->v_type = VAR_FUNC;
|
||||
}
|
||||
|
||||
// Stop the expression evaluation when immediately
|
||||
// aborting on error, or when an interrupt occurred or
|
||||
// an exception was thrown but not caught.
|
||||
if (evaluate && aborting()) {
|
||||
if (ret == OK) {
|
||||
tv_clear(rettv);
|
||||
}
|
||||
ret = FAIL;
|
||||
}
|
||||
ret = eval_func(arg, s, len, rettv, evaluate, NULL);
|
||||
} else if (evaluate) {
|
||||
ret = get_var_tv((const char *)s, len, rettv, NULL, true, false);
|
||||
} else {
|
||||
@ -4019,51 +4053,230 @@ static int eval7(
|
||||
*arg = skipwhite(*arg);
|
||||
|
||||
// Handle following '[', '(' and '.' for expr[expr], expr.name,
|
||||
// expr(expr).
|
||||
// expr(expr), expr->name(expr)
|
||||
if (ret == OK) {
|
||||
ret = handle_subscript((const char **)arg, rettv, evaluate, true);
|
||||
ret = handle_subscript((const char **)arg, rettv, evaluate, true,
|
||||
start_leader, &end_leader);
|
||||
}
|
||||
|
||||
// Apply logical NOT and unary '-', from right to left, ignore '+'.
|
||||
if (ret == OK && evaluate && end_leader > start_leader) {
|
||||
bool error = false;
|
||||
varnumber_T val = 0;
|
||||
float_T f = 0.0;
|
||||
ret = eval7_leader(rettv, start_leader, &end_leader);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (rettv->v_type == VAR_FLOAT) {
|
||||
f = rettv->vval.v_float;
|
||||
} else {
|
||||
val = tv_get_number_chk(rettv, &error);
|
||||
}
|
||||
if (error) {
|
||||
tv_clear(rettv);
|
||||
ret = FAIL;
|
||||
} else {
|
||||
while (end_leader > start_leader) {
|
||||
--end_leader;
|
||||
if (*end_leader == '!') {
|
||||
if (rettv->v_type == VAR_FLOAT) {
|
||||
f = !f;
|
||||
} else {
|
||||
val = !val;
|
||||
}
|
||||
} else if (*end_leader == '-') {
|
||||
if (rettv->v_type == VAR_FLOAT) {
|
||||
f = -f;
|
||||
} else {
|
||||
val = -val;
|
||||
}
|
||||
/// Apply the leading "!" and "-" before an eval7 expression to "rettv".
|
||||
/// Adjusts "end_leaderp" until it is at "start_leader".
|
||||
/// @return OK on success, FAIL on failure.
|
||||
static int eval7_leader(typval_T *const rettv, const char_u *const start_leader,
|
||||
const char_u **const end_leaderp)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
const char_u *end_leader = *end_leaderp;
|
||||
int ret = OK;
|
||||
bool error = false;
|
||||
varnumber_T val = 0;
|
||||
float_T f = 0.0;
|
||||
|
||||
if (rettv->v_type == VAR_FLOAT) {
|
||||
f = rettv->vval.v_float;
|
||||
} else {
|
||||
val = tv_get_number_chk(rettv, &error);
|
||||
}
|
||||
if (error) {
|
||||
tv_clear(rettv);
|
||||
ret = FAIL;
|
||||
} else {
|
||||
while (end_leader > start_leader) {
|
||||
end_leader--;
|
||||
if (*end_leader == '!') {
|
||||
if (rettv->v_type == VAR_FLOAT) {
|
||||
f = !f;
|
||||
} else {
|
||||
val = !val;
|
||||
}
|
||||
} else if (*end_leader == '-') {
|
||||
if (rettv->v_type == VAR_FLOAT) {
|
||||
f = -f;
|
||||
} else {
|
||||
val = -val;
|
||||
}
|
||||
}
|
||||
if (rettv->v_type == VAR_FLOAT) {
|
||||
tv_clear(rettv);
|
||||
rettv->vval.v_float = f;
|
||||
}
|
||||
if (rettv->v_type == VAR_FLOAT) {
|
||||
tv_clear(rettv);
|
||||
rettv->vval.v_float = f;
|
||||
} else {
|
||||
tv_clear(rettv);
|
||||
rettv->v_type = VAR_NUMBER;
|
||||
rettv->vval.v_number = val;
|
||||
}
|
||||
}
|
||||
|
||||
*end_leaderp = end_leader;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// Call the function referred to in "rettv".
|
||||
/// @param lua_funcname If `rettv` refers to a v:lua function, this must point
|
||||
/// to the name of the Lua function to call (after the
|
||||
/// "v:lua." prefix).
|
||||
/// @return OK on success, FAIL on failure.
|
||||
static int call_func_rettv(char_u **const arg,
|
||||
typval_T *const rettv,
|
||||
const bool evaluate,
|
||||
dict_T *const selfdict,
|
||||
typval_T *const basetv,
|
||||
const char_u *const lua_funcname)
|
||||
FUNC_ATTR_NONNULL_ARG(1, 2)
|
||||
{
|
||||
partial_T *pt = NULL;
|
||||
typval_T functv;
|
||||
const char_u *funcname;
|
||||
bool is_lua = false;
|
||||
|
||||
// need to copy the funcref so that we can clear rettv
|
||||
if (evaluate) {
|
||||
functv = *rettv;
|
||||
rettv->v_type = VAR_UNKNOWN;
|
||||
|
||||
// Invoke the function. Recursive!
|
||||
if (functv.v_type == VAR_PARTIAL) {
|
||||
pt = functv.vval.v_partial;
|
||||
is_lua = is_luafunc(pt);
|
||||
funcname = is_lua ? lua_funcname : partial_name(pt);
|
||||
} else {
|
||||
funcname = functv.vval.v_string;
|
||||
}
|
||||
} else {
|
||||
funcname = (char_u *)"";
|
||||
}
|
||||
|
||||
funcexe_T funcexe = FUNCEXE_INIT;
|
||||
funcexe.firstline = curwin->w_cursor.lnum;
|
||||
funcexe.lastline = curwin->w_cursor.lnum;
|
||||
funcexe.evaluate = evaluate;
|
||||
funcexe.partial = pt;
|
||||
funcexe.selfdict = selfdict;
|
||||
funcexe.basetv = basetv;
|
||||
const int ret = get_func_tv(funcname, is_lua ? *arg - funcname : -1, rettv,
|
||||
(char_u **)arg, &funcexe);
|
||||
|
||||
// Clear the funcref afterwards, so that deleting it while
|
||||
// evaluating the arguments is possible (see test55).
|
||||
if (evaluate) {
|
||||
tv_clear(&functv);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// Evaluate "->method()".
|
||||
/// @param verbose if true, give error messages.
|
||||
/// @note "*arg" points to the '-'.
|
||||
/// @return FAIL or OK. @note "*arg" is advanced to after the ')'.
|
||||
static int eval_lambda(char_u **const arg, typval_T *const rettv,
|
||||
const bool evaluate, const bool verbose)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
// Skip over the ->.
|
||||
*arg += 2;
|
||||
typval_T base = *rettv;
|
||||
rettv->v_type = VAR_UNKNOWN;
|
||||
|
||||
int ret = get_lambda_tv(arg, rettv, evaluate);
|
||||
if (ret == NOTDONE) {
|
||||
return FAIL;
|
||||
} else if (**arg != '(') {
|
||||
if (verbose) {
|
||||
if (*skipwhite(*arg) == '(') {
|
||||
EMSG(_(e_nowhitespace));
|
||||
} else {
|
||||
tv_clear(rettv);
|
||||
rettv->v_type = VAR_NUMBER;
|
||||
rettv->vval.v_number = val;
|
||||
EMSG2(_(e_missingparen), "lambda");
|
||||
}
|
||||
}
|
||||
tv_clear(rettv);
|
||||
ret = FAIL;
|
||||
} else {
|
||||
ret = call_func_rettv(arg, rettv, evaluate, NULL, &base, NULL);
|
||||
}
|
||||
|
||||
// Clear the funcref afterwards, so that deleting it while
|
||||
// evaluating the arguments is possible (see test55).
|
||||
if (evaluate) {
|
||||
tv_clear(&base);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// Evaluate "->method()" or "->v:lua.method()".
|
||||
/// @note "*arg" points to the '-'.
|
||||
/// @return FAIL or OK. "*arg" is advanced to after the ')'.
|
||||
static int eval_method(char_u **const arg, typval_T *const rettv,
|
||||
const bool evaluate, const bool verbose)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
// Skip over the ->.
|
||||
*arg += 2;
|
||||
typval_T base = *rettv;
|
||||
rettv->v_type = VAR_UNKNOWN;
|
||||
|
||||
// Locate the method name.
|
||||
int len;
|
||||
char_u *name = *arg;
|
||||
char_u *lua_funcname = NULL;
|
||||
if (STRNCMP(name, "v:lua.", 6) == 0) {
|
||||
lua_funcname = name + 6;
|
||||
*arg = (char_u *)skip_luafunc_name((const char *)lua_funcname);
|
||||
*arg = skipwhite(*arg); // to detect trailing whitespace later
|
||||
len = *arg - lua_funcname;
|
||||
} else {
|
||||
char_u *alias;
|
||||
len = get_name_len((const char **)arg, (char **)&alias, evaluate, true);
|
||||
if (alias != NULL) {
|
||||
name = alias;
|
||||
}
|
||||
}
|
||||
|
||||
int ret;
|
||||
if (len <= 0) {
|
||||
if (verbose) {
|
||||
if (lua_funcname == NULL) {
|
||||
EMSG(_("E260: Missing name after ->"));
|
||||
} else {
|
||||
EMSG2(_(e_invexpr2), name);
|
||||
}
|
||||
}
|
||||
ret = FAIL;
|
||||
} else {
|
||||
if (**arg != '(') {
|
||||
if (verbose) {
|
||||
EMSG2(_(e_missingparen), name);
|
||||
}
|
||||
ret = FAIL;
|
||||
} else if (ascii_iswhite((*arg)[-1])) {
|
||||
if (verbose) {
|
||||
EMSG(_(e_nowhitespace));
|
||||
}
|
||||
ret = FAIL;
|
||||
} else if (lua_funcname != NULL) {
|
||||
if (evaluate) {
|
||||
rettv->v_type = VAR_PARTIAL;
|
||||
rettv->vval.v_partial = vvlua_partial;
|
||||
rettv->vval.v_partial->pt_refcount++;
|
||||
}
|
||||
ret = call_func_rettv(arg, rettv, evaluate, NULL, &base, lua_funcname);
|
||||
} else {
|
||||
ret = eval_func(arg, name, len, rettv, evaluate, &base);
|
||||
}
|
||||
}
|
||||
|
||||
// Clear the funcref afterwards, so that deleting it while
|
||||
// evaluating the arguments is possible (see test55).
|
||||
if (evaluate) {
|
||||
tv_clear(&base);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -7255,10 +7468,12 @@ bool callback_call(Callback *const callback, const int argcount_in,
|
||||
abort();
|
||||
}
|
||||
|
||||
int dummy;
|
||||
return call_func(name, -1, rettv, argcount_in, argvars_in,
|
||||
NULL, curwin->w_cursor.lnum, curwin->w_cursor.lnum, &dummy,
|
||||
true, partial, NULL);
|
||||
funcexe_T funcexe = FUNCEXE_INIT;
|
||||
funcexe.firstline = curwin->w_cursor.lnum;
|
||||
funcexe.lastline = curwin->w_cursor.lnum;
|
||||
funcexe.evaluate = true;
|
||||
funcexe.partial = partial;
|
||||
return call_func(name, -1, rettv, argcount_in, argvars_in, &funcexe);
|
||||
}
|
||||
|
||||
static bool set_ref_in_callback(Callback *callback, int copyID,
|
||||
@ -8393,13 +8608,23 @@ static bool tv_is_luafunc(typval_T *tv)
|
||||
return tv->v_type == VAR_PARTIAL && is_luafunc(tv->vval.v_partial);
|
||||
}
|
||||
|
||||
/// check the function name after "v:lua."
|
||||
int check_luafunc_name(const char *str, bool paren)
|
||||
/// Skips one character past the end of the name of a v:lua function.
|
||||
/// @param p Pointer to the char AFTER the "v:lua." prefix.
|
||||
/// @return Pointer to the char one past the end of the function's name.
|
||||
const char *skip_luafunc_name(const char *p)
|
||||
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
|
||||
{
|
||||
const char *p = str;
|
||||
while (ASCII_ISALNUM(*p) || *p == '_' || *p == '.' || *p == '\'') {
|
||||
p++;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/// check the function name after "v:lua."
|
||||
int check_luafunc_name(const char *const str, const bool paren)
|
||||
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
|
||||
{
|
||||
const char *const p = skip_luafunc_name(str);
|
||||
if (*p != (paren ? '(' : NUL)) {
|
||||
return 0;
|
||||
} else {
|
||||
@ -8407,24 +8632,26 @@ int check_luafunc_name(const char *str, bool paren)
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle expr[expr], expr[expr:expr] subscript and .name lookup.
|
||||
/// Also handle function call with Funcref variable: func(expr)
|
||||
/// Can all be combined: dict.func(expr)[idx]['func'](expr)
|
||||
/// Handle:
|
||||
/// - expr[expr], expr[expr:expr] subscript
|
||||
/// - ".name" lookup
|
||||
/// - function call with Funcref variable: func(expr)
|
||||
/// - method call: var->method()
|
||||
///
|
||||
/// Can all be combined in any order: dict.func(expr)[idx]['func'](expr)->len()
|
||||
int
|
||||
handle_subscript(
|
||||
const char **const arg,
|
||||
typval_T *rettv,
|
||||
int evaluate, // do more than finding the end
|
||||
int verbose // give error messages
|
||||
int evaluate, // do more than finding the end
|
||||
int verbose, // give error messages
|
||||
const char_u *const start_leader, // start of '!' and '-' prefixes
|
||||
const char_u **const end_leaderp // end of '!' and '-' prefixes
|
||||
)
|
||||
{
|
||||
int ret = OK;
|
||||
dict_T *selfdict = NULL;
|
||||
const char_u *s;
|
||||
int len;
|
||||
typval_T functv;
|
||||
int slen = 0;
|
||||
bool lua = false;
|
||||
dict_T *selfdict = NULL;
|
||||
const char_u *lua_funcname = NULL;
|
||||
|
||||
if (tv_is_luafunc(rettv)) {
|
||||
if (**arg != '.') {
|
||||
@ -8433,55 +8660,28 @@ handle_subscript(
|
||||
} else {
|
||||
(*arg)++;
|
||||
|
||||
lua = true;
|
||||
s = (char_u *)(*arg);
|
||||
slen = check_luafunc_name(*arg, true);
|
||||
if (slen == 0) {
|
||||
lua_funcname = (char_u *)(*arg);
|
||||
const int len = check_luafunc_name(*arg, true);
|
||||
if (len == 0) {
|
||||
tv_clear(rettv);
|
||||
ret = FAIL;
|
||||
}
|
||||
(*arg) += slen;
|
||||
(*arg) += len;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
while (ret == OK
|
||||
&& (**arg == '['
|
||||
|| (**arg == '.' && rettv->v_type == VAR_DICT)
|
||||
|| (**arg == '(' && (!evaluate || tv_is_func(*rettv))))
|
||||
&& !ascii_iswhite(*(*arg - 1))) {
|
||||
&& (((**arg == '[' || (**arg == '.' && rettv->v_type == VAR_DICT)
|
||||
|| (**arg == '(' && (!evaluate || tv_is_func(*rettv))))
|
||||
&& !ascii_iswhite(*(*arg - 1)))
|
||||
|| (**arg == '-' && (*arg)[1] == '>'))) {
|
||||
if (**arg == '(') {
|
||||
partial_T *pt = NULL;
|
||||
// need to copy the funcref so that we can clear rettv
|
||||
if (evaluate) {
|
||||
functv = *rettv;
|
||||
rettv->v_type = VAR_UNKNOWN;
|
||||
ret = call_func_rettv((char_u **)arg, rettv, evaluate, selfdict, NULL,
|
||||
lua_funcname);
|
||||
|
||||
// Invoke the function. Recursive!
|
||||
if (functv.v_type == VAR_PARTIAL) {
|
||||
pt = functv.vval.v_partial;
|
||||
if (!lua) {
|
||||
s = partial_name(pt);
|
||||
}
|
||||
} else {
|
||||
s = functv.vval.v_string;
|
||||
}
|
||||
} else {
|
||||
s = (char_u *)"";
|
||||
}
|
||||
ret = get_func_tv(s, lua ? slen : -1, rettv, (char_u **)arg,
|
||||
curwin->w_cursor.lnum, curwin->w_cursor.lnum,
|
||||
&len, evaluate, pt, selfdict);
|
||||
|
||||
// Clear the funcref afterwards, so that deleting it while
|
||||
// evaluating the arguments is possible (see test55).
|
||||
if (evaluate) {
|
||||
tv_clear(&functv);
|
||||
}
|
||||
|
||||
/* Stop the expression evaluation when immediately aborting on
|
||||
* error, or when an interrupt occurred or an exception was thrown
|
||||
* but not caught. */
|
||||
// Stop the expression evaluation when immediately aborting on
|
||||
// error, or when an interrupt occurred or an exception was thrown
|
||||
// but not caught.
|
||||
if (aborting()) {
|
||||
if (ret == OK) {
|
||||
tv_clear(rettv);
|
||||
@ -8490,6 +8690,21 @@ handle_subscript(
|
||||
}
|
||||
tv_dict_unref(selfdict);
|
||||
selfdict = NULL;
|
||||
} else if (**arg == '-') {
|
||||
// Expression "-1.0->method()" applies the leader "-" before
|
||||
// applying ->.
|
||||
if (evaluate && *end_leaderp > start_leader) {
|
||||
ret = eval7_leader(rettv, start_leader, end_leaderp);
|
||||
}
|
||||
if (ret == OK) {
|
||||
if ((*arg)[2] == '{') {
|
||||
// expr->{lambda}()
|
||||
ret = eval_lambda((char_u **)arg, rettv, evaluate, verbose);
|
||||
} else {
|
||||
// expr->name()
|
||||
ret = eval_method((char_u **)arg, rettv, evaluate, verbose);
|
||||
}
|
||||
}
|
||||
} else { // **arg == '[' || **arg == '.'
|
||||
tv_dict_unref(selfdict);
|
||||
if (rettv->v_type == VAR_DICT) {
|
||||
@ -9274,6 +9489,7 @@ void ex_echo(exarg_T *eap)
|
||||
bool atstart = true;
|
||||
bool need_clear = true;
|
||||
const int did_emsg_before = did_emsg;
|
||||
const int called_emsg_before = called_emsg;
|
||||
|
||||
if (eap->skip)
|
||||
++emsg_skip;
|
||||
@ -9288,7 +9504,8 @@ void ex_echo(exarg_T *eap)
|
||||
// Report the invalid expression unless the expression evaluation
|
||||
// has been cancelled due to an aborting error, an interrupt, or an
|
||||
// exception.
|
||||
if (!aborting() && did_emsg == did_emsg_before) {
|
||||
if (!aborting() && did_emsg == did_emsg_before
|
||||
&& called_emsg == called_emsg_before) {
|
||||
EMSG2(_(e_invexpr2), p);
|
||||
}
|
||||
need_clr_eos = false;
|
||||
@ -10409,19 +10626,11 @@ typval_T eval_call_provider(char *provider, char *method, list_T *arguments,
|
||||
typval_T rettv = { .v_type = VAR_UNKNOWN, .v_lock = VAR_UNLOCKED };
|
||||
tv_list_ref(arguments);
|
||||
|
||||
int dummy;
|
||||
(void)call_func((const char_u *)func,
|
||||
name_len,
|
||||
&rettv,
|
||||
2,
|
||||
argvars,
|
||||
NULL,
|
||||
curwin->w_cursor.lnum,
|
||||
curwin->w_cursor.lnum,
|
||||
&dummy,
|
||||
true,
|
||||
NULL,
|
||||
NULL);
|
||||
funcexe_T funcexe = FUNCEXE_INIT;
|
||||
funcexe.firstline = curwin->w_cursor.lnum;
|
||||
funcexe.lastline = curwin->w_cursor.lnum;
|
||||
funcexe.evaluate = true;
|
||||
(void)call_func((const char_u *)func, name_len, &rettv, 2, argvars, &funcexe);
|
||||
|
||||
tv_list_unref(arguments);
|
||||
// Restore caller scope information
|
||||
@ -10779,7 +10988,9 @@ bool var_exists(const char *var)
|
||||
n = get_var_tv(name, len, &tv, NULL, false, true) == OK;
|
||||
if (n) {
|
||||
// Handle d.key, l[idx], f(expr).
|
||||
n = handle_subscript(&var, &tv, true, false) == OK;
|
||||
n = handle_subscript(&var, &tv, true, false, (const char_u *)name,
|
||||
(const char_u **)&name)
|
||||
== OK;
|
||||
if (n) {
|
||||
tv_clear(&tv);
|
||||
}
|
||||
|
@ -5,6 +5,9 @@
|
||||
-- args Number of arguments, list with maximum and minimum number of arguments
|
||||
-- or list with a minimum number of arguments only. Defaults to zero
|
||||
-- arguments.
|
||||
-- base For methods: the argument to use as the base argument (1-indexed):
|
||||
-- base->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
|
||||
-- `f_{funcname}`.
|
||||
|
||||
@ -12,111 +15,115 @@ local varargs = function(nr)
|
||||
return {nr}
|
||||
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 {
|
||||
funcs={
|
||||
abs={args=1},
|
||||
acos={args=1, func="float_op_wrapper", data="&acos"}, -- WJMc
|
||||
add={args=2},
|
||||
['and']={args=2},
|
||||
abs={args=1, base=1},
|
||||
acos={args=1, base=1, func="float_op_wrapper", data="&acos"}, -- WJMc
|
||||
add={args=2, base=1},
|
||||
['and']={args=2, base=1},
|
||||
api_info={},
|
||||
append={args=2},
|
||||
appendbufline={args=3},
|
||||
append={args=2, base=LAST},
|
||||
appendbufline={args=3, base=LAST},
|
||||
argc={args={0, 1}},
|
||||
argidx={},
|
||||
arglistid={args={0, 2}},
|
||||
argv={args={0, 2}},
|
||||
asin={args=1, func="float_op_wrapper", data="&asin"}, -- WJMc
|
||||
assert_beeps={args={1}},
|
||||
assert_equal={args={2, 3}},
|
||||
assert_equalfile={args={2, 3}},
|
||||
asin={args=1, base=1, func="float_op_wrapper", data="&asin"}, -- WJMc
|
||||
assert_beeps={args={1}, base=1},
|
||||
assert_equal={args={2, 3}, base=2},
|
||||
assert_equalfile={args={2, 3}, base=1},
|
||||
assert_exception={args={1, 2}},
|
||||
assert_fails={args={1, 3}},
|
||||
assert_false={args={1, 2}},
|
||||
assert_inrange={args={3, 4}},
|
||||
assert_match={args={2, 3}},
|
||||
assert_fails={args={1, 3}, base=1},
|
||||
assert_false={args={1, 2}, base=1},
|
||||
assert_inrange={args={3, 4}, base=3},
|
||||
assert_match={args={2, 3}, base=2},
|
||||
assert_nobeep={args={1}},
|
||||
assert_notequal={args={2, 3}},
|
||||
assert_notmatch={args={2, 3}},
|
||||
assert_report={args=1},
|
||||
assert_true={args={1, 2}},
|
||||
atan={args=1, func="float_op_wrapper", data="&atan"},
|
||||
atan2={args=2},
|
||||
assert_notequal={args={2, 3}, base=2},
|
||||
assert_notmatch={args={2, 3}, base=2},
|
||||
assert_report={args=1, base=1},
|
||||
assert_true={args={1, 2}, base=1},
|
||||
atan={args=1, base=1, func="float_op_wrapper", data="&atan"},
|
||||
atan2={args=2, base=1},
|
||||
browse={args=4},
|
||||
browsedir={args=2},
|
||||
bufadd={args=1},
|
||||
bufexists={args=1},
|
||||
buffer_exists={args=1, func='f_bufexists'}, -- obsolete
|
||||
bufadd={args=1, base=1},
|
||||
bufexists={args=1, base=1},
|
||||
buffer_exists={args=1, base=1, func='f_bufexists'}, -- obsolete
|
||||
buffer_name={args={0, 1}, func='f_bufname'}, -- obsolete
|
||||
buffer_number={args={0, 1}, func='f_bufnr'}, -- obsolete
|
||||
buflisted={args=1},
|
||||
bufload={args=1},
|
||||
bufloaded={args=1},
|
||||
bufname={args={0, 1}},
|
||||
bufnr={args={0, 2}},
|
||||
bufwinid={args=1},
|
||||
bufwinnr={args=1},
|
||||
byte2line={args=1},
|
||||
byteidx={args=2},
|
||||
byteidxcomp={args=2},
|
||||
call={args={2, 3}},
|
||||
ceil={args=1, func="float_op_wrapper", data="&ceil"},
|
||||
buflisted={args=1, base=1},
|
||||
bufload={args=1, base=1},
|
||||
bufloaded={args=1, base=1},
|
||||
bufname={args={0, 1}, base=1},
|
||||
bufnr={args={0, 2}, base=1},
|
||||
bufwinid={args=1, base=1},
|
||||
bufwinnr={args=1, base=1},
|
||||
byte2line={args=1, base=1},
|
||||
byteidx={args=2, base=1},
|
||||
byteidxcomp={args=2, base=1},
|
||||
call={args={2, 3}, base=1},
|
||||
ceil={args=1, base=1, func="float_op_wrapper", data="&ceil"},
|
||||
changenr={},
|
||||
chanclose={args={1, 2}},
|
||||
chansend={args=2},
|
||||
char2nr={args={1, 2}},
|
||||
char2nr={args={1, 2}, base=1},
|
||||
charidx={args={2, 3}},
|
||||
cindent={args=1},
|
||||
clearmatches={args={0, 1}},
|
||||
col={args=1},
|
||||
complete={args=2},
|
||||
complete_add={args=1},
|
||||
cindent={args=1, base=1},
|
||||
clearmatches={args={0, 1}, base=1},
|
||||
col={args=1, base=1},
|
||||
complete={args=2, base=2},
|
||||
complete_add={args=1, base=1},
|
||||
complete_check={},
|
||||
complete_info={args={0, 1}},
|
||||
confirm={args={1, 4}},
|
||||
copy={args=1},
|
||||
cos={args=1, func="float_op_wrapper", data="&cos"},
|
||||
cosh={args=1, func="float_op_wrapper", data="&cosh"},
|
||||
count={args={2, 4}},
|
||||
complete_info={args={0, 1}, base=1},
|
||||
confirm={args={1, 4}, base=1},
|
||||
copy={args=1, base=1},
|
||||
cos={args=1, base=1, func="float_op_wrapper", data="&cos"},
|
||||
cosh={args=1, base=1, func="float_op_wrapper", data="&cosh"},
|
||||
count={args={2, 4}, base=1},
|
||||
cscope_connection={args={0, 3}},
|
||||
ctxget={args={0, 1}},
|
||||
ctxpop={},
|
||||
ctxpush={args={0, 1}},
|
||||
ctxset={args={1, 2}},
|
||||
ctxsize={},
|
||||
cursor={args={1, 3}},
|
||||
debugbreak={args={1, 1}},
|
||||
deepcopy={args={1, 2}},
|
||||
delete={args={1,2}},
|
||||
deletebufline={args={2,3}},
|
||||
cursor={args={1, 3}, base=1},
|
||||
debugbreak={args={1, 1}, base=1},
|
||||
deepcopy={args={1, 2}, base=1},
|
||||
delete={args={1,2}, base=1},
|
||||
deletebufline={args={2,3}, base=1},
|
||||
dictwatcheradd={args=3},
|
||||
dictwatcherdel={args=3},
|
||||
did_filetype={},
|
||||
diff_filler={args=1},
|
||||
diff_hlID={args=2},
|
||||
empty={args=1},
|
||||
diff_filler={args=1, base=1},
|
||||
diff_hlID={args=2, base=1},
|
||||
empty={args=1, base=1},
|
||||
environ={},
|
||||
escape={args=2},
|
||||
eval={args=1},
|
||||
eval={args=1, base=1},
|
||||
eventhandler={},
|
||||
executable={args=1},
|
||||
execute={args={1, 2}},
|
||||
exepath={args=1},
|
||||
exists={args=1},
|
||||
exp={args=1, func="float_op_wrapper", data="&exp"},
|
||||
exp={args=1, base=1, func="float_op_wrapper", data="&exp"},
|
||||
expand={args={1, 3}},
|
||||
expandcmd={args=1},
|
||||
extend={args={2, 3}},
|
||||
extend={args={2, 3}, base=1},
|
||||
feedkeys={args={1, 2}},
|
||||
file_readable={args=1, func='f_filereadable'}, -- obsolete
|
||||
filereadable={args=1},
|
||||
filewritable={args=1},
|
||||
filter={args=2},
|
||||
filter={args=2, base=1},
|
||||
finddir={args={1, 3}},
|
||||
findfile={args={1, 3}},
|
||||
flatten={args={1, 2}},
|
||||
float2nr={args=1},
|
||||
floor={args=1, func="float_op_wrapper", data="&floor"},
|
||||
fmod={args=2},
|
||||
float2nr={args=1, base=1},
|
||||
floor={args=1, base=1, func="float_op_wrapper", data="&floor"},
|
||||
fmod={args=2, base=1},
|
||||
fnameescape={args=1},
|
||||
fnamemodify={args=2},
|
||||
foldclosed={args=1},
|
||||
@ -128,7 +135,7 @@ return {
|
||||
funcref={args={1, 3}},
|
||||
['function']={args={1, 3}},
|
||||
garbagecollect={args={0, 1}},
|
||||
get={args={2, 3}},
|
||||
get={args={2, 3}, base=1},
|
||||
getbufinfo={args={0, 1}},
|
||||
getbufline={args={2, 3}},
|
||||
getbufvar={args={2, 3}},
|
||||
@ -173,7 +180,7 @@ return {
|
||||
glob2regpat={args=1},
|
||||
globpath={args={2, 5}},
|
||||
has={args=1},
|
||||
has_key={args=2},
|
||||
has_key={args=2, base=1},
|
||||
haslocaldir={args={0,2}},
|
||||
hasmapto={args={1, 3}},
|
||||
highlightID={args=1, func='f_hlID'}, -- obsolete
|
||||
@ -187,22 +194,22 @@ return {
|
||||
hostname={},
|
||||
iconv={args=3},
|
||||
indent={args=1},
|
||||
index={args={2, 4}},
|
||||
index={args={2, 4}, base=1},
|
||||
input={args={1, 3}},
|
||||
inputdialog={args={1, 3}},
|
||||
inputlist={args=1},
|
||||
inputrestore={},
|
||||
inputsave={},
|
||||
inputsecret={args={1, 2}},
|
||||
insert={args={2, 3}},
|
||||
insert={args={2, 3}, base=1},
|
||||
interrupt={args=0},
|
||||
invert={args=1},
|
||||
invert={args=1, base=1},
|
||||
isdirectory={args=1},
|
||||
isinf={args=1},
|
||||
isinf={args=1, base=1},
|
||||
islocked={args=1},
|
||||
isnan={args=1},
|
||||
isnan={args=1, base=1},
|
||||
id={args=1},
|
||||
items={args=1},
|
||||
items={args=1, base=1},
|
||||
jobclose={args={1, 2}, func="f_chanclose"},
|
||||
jobpid={args=1},
|
||||
jobresize={args=3},
|
||||
@ -210,12 +217,12 @@ return {
|
||||
jobstart={args={1, 2}},
|
||||
jobstop={args=1},
|
||||
jobwait={args={1, 2}},
|
||||
join={args={1, 2}},
|
||||
join={args={1, 2}, base=1},
|
||||
json_decode={args=1},
|
||||
json_encode={args=1},
|
||||
keys={args=1},
|
||||
keys={args=1, base=1},
|
||||
last_buffer_nr={}, -- obsolete
|
||||
len={args=1},
|
||||
len={args=1, base=1},
|
||||
libcall={args=3},
|
||||
libcallnr={args=3},
|
||||
line={args={1, 2}},
|
||||
@ -223,10 +230,10 @@ return {
|
||||
lispindent={args=1},
|
||||
list2str={args={1, 2}},
|
||||
localtime={},
|
||||
log={args=1, func="float_op_wrapper", data="&log"},
|
||||
log10={args=1, func="float_op_wrapper", data="&log10"},
|
||||
log={args=1, base=1, func="float_op_wrapper", data="&log"},
|
||||
log10={args=1, base=1, func="float_op_wrapper", data="&log10"},
|
||||
luaeval={args={1, 2}},
|
||||
map={args=2},
|
||||
map={args=2, base=1},
|
||||
maparg={args={1, 4}},
|
||||
mapcheck={args={1, 3}},
|
||||
match={args={2, 4}},
|
||||
@ -238,20 +245,20 @@ return {
|
||||
matchlist={args={2, 4}},
|
||||
matchstr={args={2, 4}},
|
||||
matchstrpos={args={2,4}},
|
||||
max={args=1},
|
||||
max={args=1, base=1},
|
||||
menu_get={args={1, 2}},
|
||||
min={args=1},
|
||||
min={args=1, base=1},
|
||||
mkdir={args={1, 3}},
|
||||
mode={args={0, 1}},
|
||||
msgpackdump={args=1},
|
||||
msgpackparse={args=1},
|
||||
nextnonblank={args=1},
|
||||
nr2char={args={1, 2}},
|
||||
['or']={args=2},
|
||||
['or']={args=2, base=1},
|
||||
pathshorten={args=1},
|
||||
pow={args=2},
|
||||
pow={args=2, base=1},
|
||||
prevnonblank={args=1},
|
||||
printf={args=varargs(1)},
|
||||
printf={args=varargs(1), base=2},
|
||||
prompt_getprompt={args=1},
|
||||
prompt_setcallback={args={2, 2}},
|
||||
prompt_setinterrupt={args={2, 2}},
|
||||
@ -270,12 +277,12 @@ return {
|
||||
reltime={args={0, 2}},
|
||||
reltimefloat={args=1},
|
||||
reltimestr={args=1},
|
||||
remove={args={2, 3}},
|
||||
remove={args={2, 3}, base=1},
|
||||
rename={args=2},
|
||||
['repeat']={args=2},
|
||||
['repeat']={args=2, base=1},
|
||||
resolve={args=1},
|
||||
reverse={args=1},
|
||||
round={args=1, func="float_op_wrapper", data="&round"},
|
||||
reverse={args=1, base=1},
|
||||
round={args=1, base=1, func="float_op_wrapper", data="&round"},
|
||||
rpcnotify={args=varargs(2)},
|
||||
rpcrequest={args=varargs(2)},
|
||||
rpcstart={args={1, 2}},
|
||||
@ -324,19 +331,19 @@ return {
|
||||
sign_unplace={args={1, 2}},
|
||||
sign_unplacelist={args={1}},
|
||||
simplify={args=1},
|
||||
sin={args=1, func="float_op_wrapper", data="&sin"},
|
||||
sinh={args=1, func="float_op_wrapper", data="&sinh"},
|
||||
sin={args=1, base=1, func="float_op_wrapper", data="&sin"},
|
||||
sinh={args=1, base=1, func="float_op_wrapper", data="&sinh"},
|
||||
sockconnect={args={2,3}},
|
||||
sort={args={1, 3}},
|
||||
sort={args={1, 3}, base=1},
|
||||
soundfold={args=1},
|
||||
stdioopen={args=1},
|
||||
spellbadword={args={0, 1}},
|
||||
spellsuggest={args={1, 3}},
|
||||
split={args={1, 3}},
|
||||
sqrt={args=1, func="float_op_wrapper", data="&sqrt"},
|
||||
split={args={1, 3}, base=1},
|
||||
sqrt={args=1, base=1, func="float_op_wrapper", data="&sqrt"},
|
||||
stdpath={args=1},
|
||||
str2float={args=1},
|
||||
str2list={args={1, 2}},
|
||||
str2float={args=1, base=1},
|
||||
str2list={args={1, 2}, base=1},
|
||||
str2nr={args={1, 2}},
|
||||
strcharpart={args={2, 3}},
|
||||
strchars={args={1,2}},
|
||||
@ -344,31 +351,31 @@ return {
|
||||
strftime={args={1, 2}},
|
||||
strgetchar={args={2, 2}},
|
||||
stridx={args={2, 3}},
|
||||
string={args=1},
|
||||
strlen={args=1},
|
||||
string={args=1, base=1},
|
||||
strlen={args=1, base=1},
|
||||
strpart={args={2, 4}},
|
||||
strptime={args=2},
|
||||
strridx={args={2, 3}},
|
||||
strtrans={args=1},
|
||||
strwidth={args=1},
|
||||
strtrans={args=1, base=1},
|
||||
strwidth={args=1, base=1},
|
||||
submatch={args={1, 2}},
|
||||
substitute={args=4},
|
||||
substitute={args=4, base=1},
|
||||
swapinfo={args={1}},
|
||||
swapname={args={1}},
|
||||
synID={args=3},
|
||||
synIDattr={args={2, 3}},
|
||||
synIDtrans={args=1},
|
||||
synIDattr={args={2, 3}, base=1},
|
||||
synIDtrans={args=1, base=1},
|
||||
synconcealed={args=2},
|
||||
synstack={args=2},
|
||||
system={args={1, 2}},
|
||||
systemlist={args={1, 3}},
|
||||
system={args={1, 2}, base=1},
|
||||
systemlist={args={1, 3}, base=1},
|
||||
tabpagebuflist={args={0, 1}},
|
||||
tabpagenr={args={0, 1}},
|
||||
tabpagewinnr={args={1, 2}},
|
||||
tagfiles={},
|
||||
taglist={args={1, 2}},
|
||||
tan={args=1, func="float_op_wrapper", data="&tan"},
|
||||
tanh={args=1, func="float_op_wrapper", data="&tanh"},
|
||||
tan={args=1, base=1, func="float_op_wrapper", data="&tan"},
|
||||
tanh={args=1, base=1, func="float_op_wrapper", data="&tanh"},
|
||||
tempname={},
|
||||
termopen={args={1, 2}},
|
||||
test_garbagecollect_now={},
|
||||
@ -382,12 +389,12 @@ return {
|
||||
toupper={args=1},
|
||||
tr={args=3},
|
||||
trim={args={1,3}},
|
||||
trunc={args=1, func="float_op_wrapper", data="&trunc"},
|
||||
type={args=1},
|
||||
trunc={args=1, base=1, func="float_op_wrapper", data="&trunc"},
|
||||
type={args=1, base=1},
|
||||
undofile={args=1},
|
||||
undotree={},
|
||||
uniq={args={1, 3}},
|
||||
values={args=1},
|
||||
uniq={args={1, 3}, base=1},
|
||||
values={args=1, base=1},
|
||||
virtcol={args=1},
|
||||
visualmode={args={0, 1}},
|
||||
wait={args={2,3}},
|
||||
@ -401,7 +408,7 @@ return {
|
||||
win_id2win={args=1},
|
||||
win_screenpos={args=1},
|
||||
win_splitmove={args={2, 3}},
|
||||
winbufnr={args=1},
|
||||
winbufnr={args=1, base=1},
|
||||
wincol={},
|
||||
windowsversion={},
|
||||
winheight={args=1},
|
||||
@ -414,6 +421,6 @@ return {
|
||||
winwidth={args=1},
|
||||
wordcount={},
|
||||
writefile={args={2, 3}},
|
||||
xor={args=2},
|
||||
xor={args=2, base=1},
|
||||
},
|
||||
}
|
||||
|
@ -175,6 +175,53 @@ const VimLFuncDef *find_internal_func(const char *const name)
|
||||
return find_internal_func_gperf(name, len);
|
||||
}
|
||||
|
||||
int call_internal_func(const char_u *const fname, const int argcount,
|
||||
typval_T *const argvars, typval_T *const rettv)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
const VimLFuncDef *const fdef = find_internal_func((const char *)fname);
|
||||
if (fdef == NULL) {
|
||||
return ERROR_UNKNOWN;
|
||||
} else if (argcount < fdef->min_argc) {
|
||||
return ERROR_TOOFEW;
|
||||
} else if (argcount > fdef->max_argc) {
|
||||
return ERROR_TOOMANY;
|
||||
}
|
||||
argvars[argcount].v_type = VAR_UNKNOWN;
|
||||
fdef->func(argvars, rettv, fdef->data);
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
/// Invoke a method for base->method().
|
||||
int call_internal_method(const char_u *const fname, const int argcount,
|
||||
typval_T *const argvars, typval_T *const rettv,
|
||||
typval_T *const basetv)
|
||||
FUNC_ATTR_NONNULL_ALL
|
||||
{
|
||||
const VimLFuncDef *const fdef = find_internal_func((const char *)fname);
|
||||
if (fdef == NULL) {
|
||||
return ERROR_UNKNOWN;
|
||||
} else if (fdef->base_arg == BASE_NONE) {
|
||||
return ERROR_NOTMETHOD;
|
||||
} else if (argcount + 1 < fdef->min_argc) {
|
||||
return ERROR_TOOFEW;
|
||||
} else if (argcount + 1 > fdef->max_argc) {
|
||||
return ERROR_TOOMANY;
|
||||
}
|
||||
|
||||
typval_T argv[MAX_FUNC_ARGS + 1];
|
||||
const ptrdiff_t base_index
|
||||
= fdef->base_arg == BASE_LAST ? argcount : fdef->base_arg - 1;
|
||||
memcpy(argv, argvars, base_index * sizeof(typval_T));
|
||||
argv[base_index] = *basetv;
|
||||
memcpy(argv + base_index + 1, argvars + base_index,
|
||||
(argcount - base_index) * sizeof(typval_T));
|
||||
argv[argcount + 1].v_type = VAR_UNKNOWN;
|
||||
|
||||
fdef->func(argv, rettv, fdef->data);
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return TRUE for a non-zero Number and a non-empty String.
|
||||
*/
|
||||
@ -9420,7 +9467,6 @@ static int item_compare2(const void *s1, const void *s2, bool keep_zero)
|
||||
int res;
|
||||
typval_T rettv;
|
||||
typval_T argv[3];
|
||||
int dummy;
|
||||
const char *func_name;
|
||||
partial_T *partial = sortinfo->item_compare_partial;
|
||||
|
||||
@ -9444,10 +9490,11 @@ static int item_compare2(const void *s1, const void *s2, bool keep_zero)
|
||||
tv_copy(TV_LIST_ITEM_TV(si2->item), &argv[1]);
|
||||
|
||||
rettv.v_type = VAR_UNKNOWN; // tv_clear() uses this
|
||||
res = call_func((const char_u *)func_name,
|
||||
-1,
|
||||
&rettv, 2, argv, NULL, 0L, 0L, &dummy, true,
|
||||
partial, sortinfo->item_compare_selfdict);
|
||||
funcexe_T funcexe = FUNCEXE_INIT;
|
||||
funcexe.evaluate = true;
|
||||
funcexe.partial = partial;
|
||||
funcexe.selfdict = sortinfo->item_compare_selfdict;
|
||||
res = call_func((const char_u *)func_name, -1, &rettv, 2, argv, &funcexe);
|
||||
tv_clear(&argv[0]);
|
||||
tv_clear(&argv[1]);
|
||||
|
||||
|
@ -9,11 +9,16 @@ typedef void (*FunPtr)(void);
|
||||
/// Prototype of C function that implements VimL function
|
||||
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
|
||||
typedef struct fst {
|
||||
char *name; ///< Name of the function.
|
||||
uint8_t min_argc; ///< Minimal number of arguments.
|
||||
uint8_t max_argc; ///< Maximal number of arguments.
|
||||
uint8_t base_arg; ///< Method base arg # (1-indexed), BASE_NONE or BASE_LAST.
|
||||
VimLFunc func; ///< Function implementation.
|
||||
FunPtr data; ///< Userdata for function implementation.
|
||||
} VimLFuncDef;
|
||||
|
@ -414,12 +414,7 @@ get_func_tv(
|
||||
int len, // length of "name" or -1 to use strlen()
|
||||
typval_T *rettv,
|
||||
char_u **arg, // argument, pointing to the '('
|
||||
linenr_T firstline, // first line of range
|
||||
linenr_T lastline, // last line of range
|
||||
int *doesrange, // return: function handled range
|
||||
int evaluate,
|
||||
partial_T *partial, // for extra arguments
|
||||
dict_T *selfdict // Dictionary for "self"
|
||||
funcexe_T *funcexe // various values
|
||||
)
|
||||
{
|
||||
char_u *argp;
|
||||
@ -431,12 +426,13 @@ get_func_tv(
|
||||
* Get the arguments.
|
||||
*/
|
||||
argp = *arg;
|
||||
while (argcount < MAX_FUNC_ARGS - (partial == NULL ? 0 : partial->pt_argc)) {
|
||||
while (argcount < MAX_FUNC_ARGS
|
||||
- (funcexe->partial == NULL ? 0 : funcexe->partial->pt_argc)) {
|
||||
argp = skipwhite(argp + 1); // skip the '(' or ','
|
||||
if (*argp == ')' || *argp == ',' || *argp == NUL) {
|
||||
break;
|
||||
}
|
||||
if (eval1(&argp, &argvars[argcount], evaluate) == FAIL) {
|
||||
if (eval1(&argp, &argvars[argcount], funcexe->evaluate) == FAIL) {
|
||||
ret = FAIL;
|
||||
break;
|
||||
}
|
||||
@ -463,9 +459,7 @@ get_func_tv(
|
||||
((typval_T **)funcargs.ga_data)[funcargs.ga_len++] = &argvars[i];
|
||||
}
|
||||
}
|
||||
ret = call_func(name, len, rettv, argcount, argvars, NULL,
|
||||
firstline, lastline, doesrange, evaluate,
|
||||
partial, selfdict);
|
||||
ret = call_func(name, len, rettv, argcount, argvars, funcexe);
|
||||
|
||||
funcargs.ga_len -= i;
|
||||
} else if (!aborting()) {
|
||||
@ -1367,7 +1361,6 @@ int func_call(char_u *name, typval_T *args, partial_T *partial,
|
||||
{
|
||||
typval_T argv[MAX_FUNC_ARGS + 1];
|
||||
int argc = 0;
|
||||
int dummy;
|
||||
int r = 0;
|
||||
|
||||
TV_LIST_ITER(args->vval.v_list, item, {
|
||||
@ -1380,9 +1373,13 @@ int func_call(char_u *name, typval_T *args, partial_T *partial,
|
||||
tv_copy(TV_LIST_ITEM_TV(item), &argv[argc++]);
|
||||
});
|
||||
|
||||
r = call_func(name, -1, rettv, argc, argv, NULL,
|
||||
curwin->w_cursor.lnum, curwin->w_cursor.lnum,
|
||||
&dummy, true, partial, selfdict);
|
||||
funcexe_T funcexe = FUNCEXE_INIT;
|
||||
funcexe.firstline = curwin->w_cursor.lnum;
|
||||
funcexe.lastline = curwin->w_cursor.lnum;
|
||||
funcexe.evaluate = true;
|
||||
funcexe.partial = partial;
|
||||
funcexe.selfdict = selfdict;
|
||||
r = call_func(name, -1, rettv, argc, argv, &funcexe);
|
||||
|
||||
func_call_skip_call:
|
||||
// Free the arguments.
|
||||
@ -1402,6 +1399,9 @@ static void user_func_error(int error, const char_u *name)
|
||||
case ERROR_UNKNOWN:
|
||||
emsg_funcname(N_("E117: Unknown function: %s"), name);
|
||||
break;
|
||||
case ERROR_NOTMETHOD:
|
||||
emsg_funcname(N_("E276: Cannot use function as a method: %s"), name);
|
||||
break;
|
||||
case ERROR_DELETED:
|
||||
emsg_funcname(N_("E933: Function was deleted: %s"), name);
|
||||
break;
|
||||
@ -1423,12 +1423,25 @@ static void user_func_error(int error, const char_u *name)
|
||||
}
|
||||
}
|
||||
|
||||
/// Used by call_func to add a method base (if any) to a function argument list
|
||||
/// as the first argument. @see call_func
|
||||
static void argv_add_base(typval_T *const basetv, typval_T **const argvars,
|
||||
int *const argcount, typval_T *const new_argvars,
|
||||
int *const argv_base)
|
||||
FUNC_ATTR_NONNULL_ARG(2, 3, 4, 5)
|
||||
{
|
||||
if (basetv != NULL) {
|
||||
// Method call: base->Method()
|
||||
memmove(&new_argvars[1], *argvars, sizeof(typval_T) * (*argcount));
|
||||
new_argvars[0] = *basetv;
|
||||
(*argcount)++;
|
||||
*argvars = new_argvars;
|
||||
*argv_base = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/// Call a function with its resolved parameters
|
||||
///
|
||||
/// "argv_func", when not NULL, can be used to fill in arguments only when the
|
||||
/// invoked function uses them. It is called like this:
|
||||
/// new_argcount = argv_func(current_argcount, argv, called_func_argcount)
|
||||
///
|
||||
/// @return FAIL if function cannot be called, else OK (even if an error
|
||||
/// occurred while executing the function! Set `msg_list` to capture
|
||||
/// the error, see do_cmdline()).
|
||||
@ -1440,15 +1453,9 @@ call_func(
|
||||
int argcount_in, // number of "argvars"
|
||||
typval_T *argvars_in, // vars for arguments, must have "argcount"
|
||||
// PLUS ONE elements!
|
||||
ArgvFunc argv_func, // function to fill in argvars
|
||||
linenr_T firstline, // first line of range
|
||||
linenr_T lastline, // last line of range
|
||||
int *doesrange, // [out] function handled range
|
||||
bool evaluate,
|
||||
partial_T *partial, // optional, can be NULL
|
||||
dict_T *selfdict_in // Dictionary for "self"
|
||||
funcexe_T *funcexe // more arguments
|
||||
)
|
||||
FUNC_ATTR_NONNULL_ARG(1, 3, 5, 9)
|
||||
FUNC_ATTR_NONNULL_ARG(1, 3, 5, 6)
|
||||
{
|
||||
int ret = FAIL;
|
||||
int error = ERROR_NONE;
|
||||
@ -1459,9 +1466,12 @@ call_func(
|
||||
char_u *name = NULL;
|
||||
int argcount = argcount_in;
|
||||
typval_T *argvars = argvars_in;
|
||||
dict_T *selfdict = selfdict_in;
|
||||
typval_T argv[MAX_FUNC_ARGS + 1]; // used when "partial" is not NULL
|
||||
dict_T *selfdict = funcexe->selfdict;
|
||||
typval_T argv[MAX_FUNC_ARGS + 1]; // used when "partial" or
|
||||
// "funcexe->basetv" is not NULL
|
||||
int argv_clear = 0;
|
||||
int argv_base = 0;
|
||||
partial_T *partial = funcexe->partial;
|
||||
|
||||
// Initialize rettv so that it is safe for caller to invoke clear_tv(rettv)
|
||||
// even when call_func() returns FAIL.
|
||||
@ -1480,14 +1490,15 @@ call_func(
|
||||
fname = fname_trans_sid(name, fname_buf, &tofree, &error);
|
||||
}
|
||||
|
||||
*doesrange = false;
|
||||
if (funcexe->doesrange != NULL) {
|
||||
*funcexe->doesrange = false;
|
||||
}
|
||||
|
||||
if (partial != NULL) {
|
||||
// When the function has a partial with a dict and there is a dict
|
||||
// argument, use the dict argument. That is backwards compatible.
|
||||
// When the dict was bound explicitly use the one from the partial.
|
||||
if (partial->pt_dict != NULL
|
||||
&& (selfdict_in == NULL || !partial->pt_auto)) {
|
||||
if (partial->pt_dict != NULL && (selfdict == NULL || !partial->pt_auto)) {
|
||||
selfdict = partial->pt_dict;
|
||||
}
|
||||
if (error == ERROR_NONE && partial->pt_argc > 0) {
|
||||
@ -1506,7 +1517,7 @@ call_func(
|
||||
}
|
||||
}
|
||||
|
||||
if (error == ERROR_NONE && evaluate) {
|
||||
if (error == ERROR_NONE && funcexe->evaluate) {
|
||||
char_u *rfname = fname;
|
||||
|
||||
// Ignore "g:" before a function name.
|
||||
@ -1521,7 +1532,12 @@ call_func(
|
||||
if (is_luafunc(partial)) {
|
||||
if (len > 0) {
|
||||
error = ERROR_NONE;
|
||||
argv_add_base(funcexe->basetv, &argvars, &argcount, argv, &argv_base);
|
||||
nlua_typval_call((const char *)funcname, len, argvars, argcount, rettv);
|
||||
} else {
|
||||
// v:lua was called directly; show its name in the emsg
|
||||
XFREE_CLEAR(name);
|
||||
funcname = (const char_u *)"v:lua";
|
||||
}
|
||||
} else if (fp != NULL || !builtin_function((const char *)rfname, -1)) {
|
||||
// User defined function.
|
||||
@ -1549,13 +1565,16 @@ call_func(
|
||||
cfunc_T cb = fp->uf_cb;
|
||||
error = (*cb)(argcount, argvars, rettv, fp->uf_cb_state);
|
||||
} else if (fp != NULL) {
|
||||
if (argv_func != NULL) {
|
||||
if (funcexe->argv_func != NULL) {
|
||||
// postponed filling in the arguments, do it now
|
||||
argcount = argv_func(argcount, argvars, argv_clear,
|
||||
fp->uf_args.ga_len);
|
||||
argcount = funcexe->argv_func(argcount, argvars, argv_clear,
|
||||
fp->uf_args.ga_len);
|
||||
}
|
||||
if (fp->uf_flags & FC_RANGE) {
|
||||
*doesrange = true;
|
||||
|
||||
argv_add_base(funcexe->basetv, &argvars, &argcount, argv, &argv_base);
|
||||
|
||||
if (fp->uf_flags & FC_RANGE && funcexe->doesrange != NULL) {
|
||||
*funcexe->doesrange = true;
|
||||
}
|
||||
if (argcount < fp->uf_args.ga_len - fp->uf_def_args.ga_len) {
|
||||
error = ERROR_TOOFEW;
|
||||
@ -1565,25 +1584,20 @@ call_func(
|
||||
error = ERROR_DICT;
|
||||
} else {
|
||||
// Call the user function.
|
||||
call_user_func(fp, argcount, argvars, rettv, firstline, lastline,
|
||||
call_user_func(fp, argcount, argvars, rettv, funcexe->firstline,
|
||||
funcexe->lastline,
|
||||
(fp->uf_flags & FC_DICT) ? selfdict : NULL);
|
||||
error = ERROR_NONE;
|
||||
}
|
||||
}
|
||||
} else if (funcexe->basetv != NULL) {
|
||||
// expr->method(): Find the method name in the table, call its
|
||||
// implementation with the base as one of the arguments.
|
||||
error = call_internal_method(fname, argcount, argvars, rettv,
|
||||
funcexe->basetv);
|
||||
} else {
|
||||
// Find the function name in the table, call its implementation.
|
||||
const VimLFuncDef *const fdef = find_internal_func((const char *)fname);
|
||||
if (fdef != NULL) {
|
||||
if (argcount < fdef->min_argc) {
|
||||
error = ERROR_TOOFEW;
|
||||
} else if (argcount > fdef->max_argc) {
|
||||
error = ERROR_TOOMANY;
|
||||
} else {
|
||||
argvars[argcount].v_type = VAR_UNKNOWN;
|
||||
fdef->func(argvars, rettv, fdef->data);
|
||||
error = ERROR_NONE;
|
||||
}
|
||||
}
|
||||
error = call_internal_func(fname, argcount, argvars, rettv);
|
||||
}
|
||||
/*
|
||||
* The function call (or "FuncUndefined" autocommand sequence) might
|
||||
@ -1607,9 +1621,11 @@ theend:
|
||||
user_func_error(error, (name != NULL) ? name : funcname);
|
||||
}
|
||||
|
||||
// clear the copies made from the partial
|
||||
while (argv_clear > 0) {
|
||||
tv_clear(&argv[--argv_clear]);
|
||||
tv_clear(&argv[--argv_clear + argv_base]);
|
||||
}
|
||||
|
||||
xfree(tofree);
|
||||
xfree(name);
|
||||
|
||||
@ -2901,7 +2917,7 @@ void ex_call(exarg_T *eap)
|
||||
int len;
|
||||
typval_T rettv;
|
||||
linenr_T lnum;
|
||||
int doesrange;
|
||||
bool doesrange;
|
||||
bool failed = false;
|
||||
funcdict_T fudi;
|
||||
partial_T *partial = NULL;
|
||||
@ -2947,7 +2963,7 @@ void ex_call(exarg_T *eap)
|
||||
rettv.v_type = VAR_UNKNOWN; // tv_clear() uses this.
|
||||
|
||||
if (*startarg != '(') {
|
||||
EMSG2(_("E107: Missing parentheses: %s"), eap->arg);
|
||||
EMSG2(_(e_missingparen), eap->arg);
|
||||
goto end;
|
||||
}
|
||||
|
||||
@ -2965,15 +2981,22 @@ void ex_call(exarg_T *eap)
|
||||
curwin->w_cursor.coladd = 0;
|
||||
}
|
||||
arg = startarg;
|
||||
if (get_func_tv(name, -1, &rettv, &arg,
|
||||
eap->line1, eap->line2, &doesrange,
|
||||
true, partial, fudi.fd_dict) == FAIL) {
|
||||
|
||||
funcexe_T funcexe = FUNCEXE_INIT;
|
||||
funcexe.firstline = eap->line1;
|
||||
funcexe.lastline = eap->line2;
|
||||
funcexe.doesrange = &doesrange;
|
||||
funcexe.evaluate = true;
|
||||
funcexe.partial = partial;
|
||||
funcexe.selfdict = fudi.fd_dict;
|
||||
if (get_func_tv(name, -1, &rettv, &arg, &funcexe) == FAIL) {
|
||||
failed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Handle a function returning a Funcref, Dictionary or List.
|
||||
if (handle_subscript((const char **)&arg, &rettv, true, true)
|
||||
if (handle_subscript((const char **)&arg, &rettv, true, true,
|
||||
(const char_u *)name, (const char_u **)&name)
|
||||
== FAIL) {
|
||||
failed = true;
|
||||
break;
|
||||
|
@ -28,11 +28,37 @@ typedef enum {
|
||||
ERROR_OTHER,
|
||||
ERROR_BOTH,
|
||||
ERROR_DELETED,
|
||||
ERROR_NOTMETHOD,
|
||||
} FnameTransError;
|
||||
|
||||
/// Used in funcexe_T. Returns the new argcount.
|
||||
typedef int (*ArgvFunc)(int current_argcount, typval_T *argv, int argskip,
|
||||
int called_func_argcount);
|
||||
|
||||
/// Structure passed between functions dealing with function call execution.
|
||||
typedef struct {
|
||||
ArgvFunc argv_func; ///< when not NULL, can be used to fill in arguments only
|
||||
///< when the invoked function uses them
|
||||
linenr_T firstline; ///< first line of range
|
||||
linenr_T lastline; ///< last line of range
|
||||
bool *doesrange; ///< [out] if not NULL: function handled range
|
||||
bool evaluate; ///< actually evaluate expressions
|
||||
partial_T *partial; ///< for extra arguments
|
||||
dict_T *selfdict; ///< Dictionary for "self"
|
||||
typval_T *basetv; ///< base for base->method()
|
||||
} funcexe_T;
|
||||
|
||||
#define FUNCEXE_INIT (funcexe_T) { \
|
||||
.argv_func = NULL, \
|
||||
.firstline = 0, \
|
||||
.lastline = 0, \
|
||||
.doesrange = NULL, \
|
||||
.evaluate = false, \
|
||||
.partial = NULL, \
|
||||
.selfdict = NULL, \
|
||||
.basetv = NULL, \
|
||||
}
|
||||
|
||||
#define FUNCARG(fp, j) ((char_u **)(fp->uf_args.ga_data))[j]
|
||||
#define FUNCLINE(fp, j) ((char_u **)(fp->uf_lines.ga_data))[j]
|
||||
|
||||
|
@ -42,7 +42,7 @@ gperfpipe:write([[
|
||||
%language=ANSI-C
|
||||
%global-table
|
||||
%readonly-tables
|
||||
%define initializer-suffix ,0,0,NULL,NULL
|
||||
%define initializer-suffix ,0,0,BASE_NONE,NULL,NULL
|
||||
%define word-array-name functions
|
||||
%define hash-function-name hash_internal_func_gperf
|
||||
%define lookup-function-name find_internal_func_gperf
|
||||
@ -59,9 +59,10 @@ for name, def in pairs(funcs) do
|
||||
elseif #args == 1 then
|
||||
args[2] = 'MAX_FUNC_ARGS'
|
||||
end
|
||||
local base = def.base or "BASE_NONE"
|
||||
local func = def.func or ('f_' .. name)
|
||||
local data = def.data or "NULL"
|
||||
gperfpipe:write(('%s, %s, %s, &%s, (FunPtr)%s\n')
|
||||
:format(name, args[1], args[2], func, data))
|
||||
gperfpipe:write(('%s, %s, %s, %s, &%s, (FunPtr)%s\n')
|
||||
:format(name, args[1], args[2], base, func, data))
|
||||
end
|
||||
gperfpipe:close()
|
||||
|
@ -972,6 +972,7 @@ EXTERN char_u e_write[] INIT(= N_("E80: Error while writing"));
|
||||
EXTERN char_u e_zerocount[] INIT(= N_("E939: Positive count required"));
|
||||
EXTERN char_u e_usingsid[] INIT(= N_(
|
||||
"E81: Using <SID> not in a script context"));
|
||||
EXTERN char_u e_missingparen[] INIT(= N_("E107: Missing parentheses: %s"));
|
||||
EXTERN char_u e_maxmempat[] INIT(= N_(
|
||||
"E363: pattern uses more memory than 'maxmempattern'"));
|
||||
EXTERN char_u e_emptybuf[] INIT(= N_("E749: empty buffer"));
|
||||
|
@ -785,13 +785,13 @@ int nlua_call(lua_State *lstate)
|
||||
|
||||
try_start();
|
||||
typval_T rettv;
|
||||
int dummy;
|
||||
funcexe_T funcexe = FUNCEXE_INIT;
|
||||
funcexe.firstline = curwin->w_cursor.lnum;
|
||||
funcexe.lastline = curwin->w_cursor.lnum;
|
||||
funcexe.evaluate = true;
|
||||
// call_func() retval is deceptive, ignore it. Instead we set `msg_list`
|
||||
// (TRY_WRAP) to capture abort-causing non-exception errors.
|
||||
(void)call_func(name, (int)name_len, &rettv, nargs,
|
||||
vim_args, NULL,
|
||||
curwin->w_cursor.lnum, curwin->w_cursor.lnum,
|
||||
&dummy, true, NULL, NULL);
|
||||
(void)call_func(name, (int)name_len, &rettv, nargs, vim_args, &funcexe);
|
||||
if (!try_end(&err)) {
|
||||
nlua_push_typval(lstate, &rettv, false);
|
||||
}
|
||||
|
@ -2531,12 +2531,12 @@ do_mouse (
|
||||
}
|
||||
};
|
||||
typval_T rettv;
|
||||
int doesrange;
|
||||
(void)call_func((char_u *)tab_page_click_defs[mouse_col].func,
|
||||
-1,
|
||||
&rettv, ARRAY_SIZE(argv), argv, NULL,
|
||||
curwin->w_cursor.lnum, curwin->w_cursor.lnum,
|
||||
&doesrange, true, NULL, NULL);
|
||||
funcexe_T funcexe = FUNCEXE_INIT;
|
||||
funcexe.firstline = curwin->w_cursor.lnum;
|
||||
funcexe.lastline = curwin->w_cursor.lnum;
|
||||
funcexe.evaluate = true;
|
||||
(void)call_func((char_u *)tab_page_click_defs[mouse_col].func, -1,
|
||||
&rettv, ARRAY_SIZE(argv), argv, &funcexe);
|
||||
tv_clear(&rettv);
|
||||
break;
|
||||
}
|
||||
|
@ -6726,26 +6726,24 @@ static int vim_regsub_both(char_u *source, typval_T *expr, char_u *dest,
|
||||
|
||||
if (expr != NULL) {
|
||||
typval_T argv[2];
|
||||
int dummy;
|
||||
typval_T rettv;
|
||||
staticList10_T matchList = TV_LIST_STATIC10_INIT;
|
||||
|
||||
rettv.v_type = VAR_STRING;
|
||||
rettv.vval.v_string = NULL;
|
||||
argv[0].v_type = VAR_LIST;
|
||||
argv[0].vval.v_list = &matchList.sl_list;
|
||||
funcexe_T funcexe = FUNCEXE_INIT;
|
||||
funcexe.argv_func = fill_submatch_list;
|
||||
funcexe.evaluate = true;
|
||||
if (expr->v_type == VAR_FUNC) {
|
||||
s = expr->vval.v_string;
|
||||
call_func(s, -1, &rettv, 1, argv,
|
||||
fill_submatch_list, 0L, 0L, &dummy,
|
||||
true, NULL, NULL);
|
||||
call_func(s, -1, &rettv, 1, argv, &funcexe);
|
||||
} else if (expr->v_type == VAR_PARTIAL) {
|
||||
partial_T *partial = expr->vval.v_partial;
|
||||
|
||||
s = partial_name(partial);
|
||||
call_func(s, -1, &rettv, 1, argv,
|
||||
fill_submatch_list, 0L, 0L, &dummy,
|
||||
true, partial, NULL);
|
||||
funcexe.partial = partial;
|
||||
call_func(s, -1, &rettv, 1, argv, &funcexe);
|
||||
}
|
||||
if (tv_list_len(&matchList.sl_list) > 0) {
|
||||
// fill_submatch_list() was called.
|
||||
|
@ -5,3 +5,7 @@ let foo#bar = {}
|
||||
func foo#bar.echo()
|
||||
let g:called_foo_bar_echo += 1
|
||||
endfunc
|
||||
|
||||
func foo#addFoo(head)
|
||||
return a:head .. 'foo'
|
||||
endfunc
|
||||
|
@ -90,8 +90,8 @@ func Test_argadd_empty_curbuf()
|
||||
call assert_equal('', bufname('%'))
|
||||
call assert_equal(1, line('$'))
|
||||
rew
|
||||
call assert_notequal(curbuf, bufnr('%'))
|
||||
call assert_equal('Xargadd', bufname('%'))
|
||||
call assert_notequal(curbuf, '%'->bufnr())
|
||||
call assert_equal('Xargadd', '%'->bufname())
|
||||
call assert_equal(2, line('$'))
|
||||
|
||||
%argd
|
||||
|
@ -7,7 +7,7 @@ func Test_assert_equalfile()
|
||||
|
||||
let goodtext = ["one", "two", "three"]
|
||||
call writefile(goodtext, 'Xone')
|
||||
call assert_equal(1, assert_equalfile('Xone', 'xyzxyz'))
|
||||
call assert_equal(1, 'Xone'->assert_equalfile('xyzxyz'))
|
||||
call assert_match("E485: Can't read file xyzxyz", v:errors[0])
|
||||
call remove(v:errors, 0)
|
||||
|
||||
|
@ -8,6 +8,8 @@ func Test_autoload_dict_func()
|
||||
call g:foo#bar.echo()
|
||||
call assert_equal(1, g:loaded_foo_vim)
|
||||
call assert_equal(1, g:called_foo_bar_echo)
|
||||
|
||||
eval 'bar'->g:foo#addFoo()->assert_equal('barfoo')
|
||||
endfunc
|
||||
|
||||
func Test_source_autoload()
|
||||
|
@ -102,7 +102,7 @@ func Test_deletebufline()
|
||||
call assert_equal(0, deletebufline(b, 2, 8))
|
||||
call assert_equal(['aaa'], getbufline(b, 1, 2))
|
||||
exe "bd!" b
|
||||
call assert_equal(1, deletebufline(b, 1))
|
||||
call assert_equal(1, b->deletebufline(1))
|
||||
|
||||
split Xtest
|
||||
call setline(1, ['a', 'b', 'c'])
|
||||
@ -131,11 +131,11 @@ func Test_appendbufline_redraw()
|
||||
endif
|
||||
let lines =<< trim END
|
||||
new foo
|
||||
let winnr=bufwinnr('foo')
|
||||
let buf=bufnr('foo')
|
||||
let winnr = 'foo'->bufwinnr()
|
||||
let buf = bufnr('foo')
|
||||
wincmd p
|
||||
call appendbufline(buf, '$', range(1,200))
|
||||
exe winnr. 'wincmd w'
|
||||
exe winnr .. 'wincmd w'
|
||||
norm! G
|
||||
wincmd p
|
||||
call deletebufline(buf, 1, '$')
|
||||
|
@ -18,7 +18,7 @@ function Test_getbufwintabinfo()
|
||||
let l = getbufinfo('%')
|
||||
call assert_equal(bufnr('%'), l[0].bufnr)
|
||||
call assert_equal('vim', l[0].variables.editor)
|
||||
call assert_notequal(-1, index(l[0].windows, bufwinid('%')))
|
||||
call assert_notequal(-1, index(l[0].windows, '%'->bufwinid()))
|
||||
|
||||
" Test for getbufinfo() with 'bufmodified'
|
||||
call assert_equal(0, len(getbufinfo({'bufmodified' : 1})))
|
||||
|
@ -118,6 +118,16 @@ b = something();
|
||||
bw!
|
||||
endfunc
|
||||
|
||||
func Test_cindent_func()
|
||||
new
|
||||
setlocal cindent
|
||||
call setline(1, ['int main(void)', '{', 'return 0;', '}'])
|
||||
call assert_equal(-1, cindent(0))
|
||||
call assert_equal(&sw, 3->cindent())
|
||||
call assert_equal(-1, cindent(line('$')+1))
|
||||
bwipe!
|
||||
endfunc
|
||||
|
||||
" this was going beyond the end of the line.
|
||||
func Test_cindent_case()
|
||||
new
|
||||
|
@ -725,7 +725,7 @@ func Test_diff_filler()
|
||||
diffthis
|
||||
redraw
|
||||
|
||||
call assert_equal([0, 0, 0, 0, 0, 0, 0, 1, 0], map(range(-1, 7), 'diff_filler(v:val)'))
|
||||
call assert_equal([0, 0, 0, 0, 0, 0, 0, 1, 0], map(range(-1, 7), 'v:val->diff_filler()'))
|
||||
wincmd w
|
||||
call assert_equal([0, 0, 0, 0, 2, 0, 0, 0], map(range(-1, 6), 'diff_filler(v:val)'))
|
||||
|
||||
@ -741,16 +741,16 @@ func Test_diff_hlID()
|
||||
diffthis
|
||||
redraw
|
||||
|
||||
call assert_equal(synIDattr(diff_hlID(-1, 1), "name"), "")
|
||||
call diff_hlID(-1, 1)->synIDattr("name")->assert_equal("")
|
||||
|
||||
call assert_equal(diff_hlID(1, 1), hlID("DiffChange"))
|
||||
call assert_equal(synIDattr(diff_hlID(1, 1), "name"), "DiffChange")
|
||||
call diff_hlID(1, 1)->synIDattr("name")->assert_equal("DiffChange")
|
||||
call assert_equal(diff_hlID(1, 2), hlID("DiffText"))
|
||||
call assert_equal(synIDattr(diff_hlID(1, 2), "name"), "DiffText")
|
||||
call assert_equal(synIDattr(diff_hlID(2, 1), "name"), "")
|
||||
call diff_hlID(1, 2)->synIDattr("name")->assert_equal("DiffText")
|
||||
call diff_hlID(2, 1)->synIDattr("name")->assert_equal("")
|
||||
call assert_equal(diff_hlID(3, 1), hlID("DiffAdd"))
|
||||
call assert_equal(synIDattr(diff_hlID(3, 1), "name"), "DiffAdd")
|
||||
call assert_equal(synIDattr(diff_hlID(4, 1), "name"), "")
|
||||
call diff_hlID(3, 1)->synIDattr("name")->assert_equal("DiffAdd")
|
||||
call diff_hlID(4, 1)->synIDattr("name")->assert_equal("")
|
||||
|
||||
wincmd w
|
||||
call assert_equal(diff_hlID(1, 1), hlID("DiffChange"))
|
||||
|
@ -7,6 +7,8 @@ end
|
||||
func Test_abs()
|
||||
call assert_equal('1.23', string(abs(1.23)))
|
||||
call assert_equal('1.23', string(abs(-1.23)))
|
||||
eval -1.23->abs()->string()->assert_equal('1.23')
|
||||
|
||||
call assert_equal('0.0', string(abs(0.0)))
|
||||
call assert_equal('0.0', string(abs(1.0/(1.0/0.0))))
|
||||
call assert_equal('0.0', string(abs(-1.0/(1.0/0.0))))
|
||||
@ -22,6 +24,7 @@ endfunc
|
||||
func Test_sqrt()
|
||||
call assert_equal('0.0', string(sqrt(0.0)))
|
||||
call assert_equal('1.414214', string(sqrt(2.0)))
|
||||
eval 2.0->sqrt()->string()->assert_equal('1.414214')
|
||||
call assert_equal("str2float('inf')", string(sqrt(1.0/0.0)))
|
||||
call assert_equal("str2float('nan')", string(sqrt(-1.0)))
|
||||
call assert_equal("str2float('nan')", string(sqrt(0.0/0.0)))
|
||||
@ -31,6 +34,7 @@ endfunc
|
||||
func Test_log()
|
||||
call assert_equal('0.0', string(log(1.0)))
|
||||
call assert_equal('-0.693147', string(log(0.5)))
|
||||
eval 0.5->log()->string()->assert_equal('-0.693147')
|
||||
call assert_equal("-str2float('inf')", string(log(0.0)))
|
||||
call assert_equal("str2float('nan')", string(log(-1.0)))
|
||||
call assert_equal("str2float('inf')", string(log(1.0/0.0)))
|
||||
@ -42,6 +46,7 @@ func Test_log10()
|
||||
call assert_equal('0.0', string(log10(1.0)))
|
||||
call assert_equal('2.0', string(log10(100.0)))
|
||||
call assert_equal('2.079181', string(log10(120.0)))
|
||||
eval 120.0->log10()->string()->assert_equal('2.079181')
|
||||
call assert_equal("-str2float('inf')", string(log10(0.0)))
|
||||
call assert_equal("str2float('nan')", string(log10(-1.0)))
|
||||
call assert_equal("str2float('inf')", string(log10(1.0/0.0)))
|
||||
@ -53,6 +58,7 @@ func Test_exp()
|
||||
call assert_equal('1.0', string(exp(0.0)))
|
||||
call assert_equal('7.389056', string(exp(2.0)))
|
||||
call assert_equal('0.367879', string(exp(-1.0)))
|
||||
eval -1.0->exp()->string()->assert_equal('0.367879')
|
||||
call assert_equal("str2float('inf')", string(exp(1.0/0.0)))
|
||||
call assert_equal('0.0', string(exp(-1.0/0.0)))
|
||||
call assert_equal("str2float('nan')", string(exp(0.0/0.0)))
|
||||
@ -63,6 +69,7 @@ func Test_sin()
|
||||
call assert_equal('0.0', string(sin(0.0)))
|
||||
call assert_equal('0.841471', string(sin(1.0)))
|
||||
call assert_equal('-0.479426', string(sin(-0.5)))
|
||||
eval -0.5->sin()->string()->assert_equal('-0.479426')
|
||||
call assert_equal("str2float('nan')", string(sin(0.0/0.0)))
|
||||
call assert_equal("str2float('nan')", string(sin(1.0/0.0)))
|
||||
call assert_equal('0.0', string(sin(1.0/(1.0/0.0))))
|
||||
@ -73,6 +80,8 @@ endfunc
|
||||
func Test_asin()
|
||||
call assert_equal('0.0', string(asin(0.0)))
|
||||
call assert_equal('1.570796', string(asin(1.0)))
|
||||
eval 1.0->asin()->string()->assert_equal('1.570796')
|
||||
|
||||
call assert_equal('-0.523599', string(asin(-0.5)))
|
||||
call assert_equal("str2float('nan')", string(asin(1.1)))
|
||||
call assert_equal("str2float('nan')", string(asin(1.0/0.0)))
|
||||
@ -84,6 +93,7 @@ func Test_sinh()
|
||||
call assert_equal('0.0', string(sinh(0.0)))
|
||||
call assert_equal('0.521095', string(sinh(0.5)))
|
||||
call assert_equal('-1.026517', string(sinh(-0.9)))
|
||||
eval -0.9->sinh()->string()->assert_equal('-1.026517')
|
||||
call assert_equal("str2float('inf')", string(sinh(1.0/0.0)))
|
||||
call assert_equal("-str2float('inf')", string(sinh(-1.0/0.0)))
|
||||
call assert_equal("str2float('nan')", string(sinh(0.0/0.0)))
|
||||
@ -94,6 +104,7 @@ func Test_cos()
|
||||
call assert_equal('1.0', string(cos(0.0)))
|
||||
call assert_equal('0.540302', string(cos(1.0)))
|
||||
call assert_equal('0.877583', string(cos(-0.5)))
|
||||
eval -0.5->cos()->string()->assert_equal('0.877583')
|
||||
call assert_equal("str2float('nan')", string(cos(0.0/0.0)))
|
||||
call assert_equal("str2float('nan')", string(cos(1.0/0.0)))
|
||||
call assert_fails('call cos("")', 'E808:')
|
||||
@ -103,6 +114,7 @@ func Test_acos()
|
||||
call assert_equal('1.570796', string(acos(0.0)))
|
||||
call assert_equal('0.0', string(acos(1.0)))
|
||||
call assert_equal('3.141593', string(acos(-1.0)))
|
||||
eval -1.0->acos()->string()->assert_equal('3.141593')
|
||||
call assert_equal('2.094395', string(acos(-0.5)))
|
||||
call assert_equal("str2float('nan')", string(acos(1.1)))
|
||||
call assert_equal("str2float('nan')", string(acos(1.0/0.0)))
|
||||
@ -113,6 +125,7 @@ endfunc
|
||||
func Test_cosh()
|
||||
call assert_equal('1.0', string(cosh(0.0)))
|
||||
call assert_equal('1.127626', string(cosh(0.5)))
|
||||
eval 0.5->cosh()->string()->assert_equal('1.127626')
|
||||
call assert_equal("str2float('inf')", string(cosh(1.0/0.0)))
|
||||
call assert_equal("str2float('inf')", string(cosh(-1.0/0.0)))
|
||||
call assert_equal("str2float('nan')", string(cosh(0.0/0.0)))
|
||||
@ -123,6 +136,7 @@ func Test_tan()
|
||||
call assert_equal('0.0', string(tan(0.0)))
|
||||
call assert_equal('0.546302', string(tan(0.5)))
|
||||
call assert_equal('-0.546302', string(tan(-0.5)))
|
||||
eval -0.5->tan()->string()->assert_equal('-0.546302')
|
||||
call assert_equal("str2float('nan')", string(tan(1.0/0.0)))
|
||||
call assert_equal("str2float('nan')", string(cos(0.0/0.0)))
|
||||
call assert_equal('0.0', string(tan(1.0/(1.0/0.0))))
|
||||
@ -134,6 +148,7 @@ func Test_atan()
|
||||
call assert_equal('0.0', string(atan(0.0)))
|
||||
call assert_equal('0.463648', string(atan(0.5)))
|
||||
call assert_equal('-0.785398', string(atan(-1.0)))
|
||||
eval -1.0->atan()->string()->assert_equal('-0.785398')
|
||||
call assert_equal('1.570796', string(atan(1.0/0.0)))
|
||||
call assert_equal('-1.570796', string(atan(-1.0/0.0)))
|
||||
call assert_equal("str2float('nan')", string(atan(0.0/0.0)))
|
||||
@ -144,6 +159,7 @@ func Test_atan2()
|
||||
call assert_equal('-2.356194', string(atan2(-1, -1)))
|
||||
call assert_equal('2.356194', string(atan2(1, -1)))
|
||||
call assert_equal('0.0', string(atan2(1.0, 1.0/0.0)))
|
||||
eval 1.0->atan2(1.0/0.0)->string()->assert_equal('0.0')
|
||||
call assert_equal('1.570796', string(atan2(1.0/0.0, 1.0)))
|
||||
call assert_equal("str2float('nan')", string(atan2(0.0/0.0, 1.0)))
|
||||
call assert_fails('call atan2("", -1)', 'E808:')
|
||||
@ -154,6 +170,7 @@ func Test_tanh()
|
||||
call assert_equal('0.0', string(tanh(0.0)))
|
||||
call assert_equal('0.462117', string(tanh(0.5)))
|
||||
call assert_equal('-0.761594', string(tanh(-1.0)))
|
||||
eval -1.0->tanh()->string()->assert_equal('-0.761594')
|
||||
call assert_equal('1.0', string(tanh(1.0/0.0)))
|
||||
call assert_equal('-1.0', string(tanh(-1.0/0.0)))
|
||||
call assert_equal("str2float('nan')", string(tanh(0.0/0.0)))
|
||||
@ -164,6 +181,7 @@ func Test_fmod()
|
||||
call assert_equal('0.13', string(fmod(12.33, 1.22)))
|
||||
call assert_equal('-0.13', string(fmod(-12.33, 1.22)))
|
||||
call assert_equal("str2float('nan')", string(fmod(1.0/0.0, 1.0)))
|
||||
eval (1.0/0.0)->fmod(1.0)->string()->assert_equal("str2float('nan')")
|
||||
" On Windows we get "nan" instead of 1.0, accept both.
|
||||
let res = string(fmod(1.0, 1.0/0.0))
|
||||
if res != "str2float('nan')"
|
||||
@ -177,6 +195,7 @@ endfunc
|
||||
func Test_pow()
|
||||
call assert_equal('1.0', string(pow(0.0, 0.0)))
|
||||
call assert_equal('8.0', string(pow(2.0, 3.0)))
|
||||
eval 2.0->pow(3.0)->string()->assert_equal('8.0')
|
||||
call assert_equal("str2float('nan')", string(pow(2.0, 0.0/0.0)))
|
||||
call assert_equal("str2float('nan')", string(pow(0.0/0.0, 3.0)))
|
||||
call assert_equal("str2float('nan')", string(pow(0.0/0.0, 3.0)))
|
||||
@ -192,6 +211,7 @@ func Test_str2float()
|
||||
call assert_equal('1.0', string(str2float(' 1.0 ')))
|
||||
call assert_equal('1.23', string(str2float('1.23')))
|
||||
call assert_equal('1.23', string(str2float('1.23abc')))
|
||||
eval '1.23abc'->str2float()->string()->assert_equal('1.23')
|
||||
call assert_equal('1.0e40', string(str2float('1e40')))
|
||||
call assert_equal('-1.23', string(str2float('-1.23')))
|
||||
call assert_equal('1.23', string(str2float(' + 1.23 ')))
|
||||
@ -228,6 +248,7 @@ func Test_float2nr()
|
||||
call assert_equal(1, float2nr(1.234))
|
||||
call assert_equal(123, float2nr(1.234e2))
|
||||
call assert_equal(12, float2nr(123.4e-1))
|
||||
eval 123.4e-1->float2nr()->assert_equal(12)
|
||||
let max_number = 1/0
|
||||
let min_number = -max_number
|
||||
call assert_equal(max_number/2+1, float2nr(pow(2, 62)))
|
||||
@ -242,6 +263,7 @@ func Test_floor()
|
||||
call assert_equal('2.0', string(floor(2.0)))
|
||||
call assert_equal('2.0', string(floor(2.11)))
|
||||
call assert_equal('2.0', string(floor(2.99)))
|
||||
eval 2.99->floor()->string()->assert_equal('2.0')
|
||||
call assert_equal('-3.0', string(floor(-2.11)))
|
||||
call assert_equal('-3.0', string(floor(-2.99)))
|
||||
call assert_equal("str2float('nan')", string(floor(0.0/0.0)))
|
||||
@ -255,6 +277,7 @@ func Test_ceil()
|
||||
call assert_equal('3.0', string(ceil(2.11)))
|
||||
call assert_equal('3.0', string(ceil(2.99)))
|
||||
call assert_equal('-2.0', string(ceil(-2.11)))
|
||||
eval -2.11->ceil()->string()->assert_equal('-2.0')
|
||||
call assert_equal('-2.0', string(ceil(-2.99)))
|
||||
call assert_equal("str2float('nan')", string(ceil(0.0/0.0)))
|
||||
call assert_equal("str2float('inf')", string(ceil(1.0/0.0)))
|
||||
@ -266,6 +289,7 @@ func Test_round()
|
||||
call assert_equal('2.0', string(round(2.1)))
|
||||
call assert_equal('3.0', string(round(2.5)))
|
||||
call assert_equal('3.0', string(round(2.9)))
|
||||
eval 2.9->round()->string()->assert_equal('3.0')
|
||||
call assert_equal('-2.0', string(round(-2.1)))
|
||||
call assert_equal('-3.0', string(round(-2.5)))
|
||||
call assert_equal('-3.0', string(round(-2.9)))
|
||||
@ -279,6 +303,7 @@ func Test_trunc()
|
||||
call assert_equal('2.0', string(trunc(2.1)))
|
||||
call assert_equal('2.0', string(trunc(2.5)))
|
||||
call assert_equal('2.0', string(trunc(2.9)))
|
||||
eval 2.9->trunc()->string()->assert_equal('2.0')
|
||||
call assert_equal('-2.0', string(trunc(-2.1)))
|
||||
call assert_equal('-2.0', string(trunc(-2.5)))
|
||||
call assert_equal('-2.0', string(trunc(-2.9)))
|
||||
@ -291,6 +316,7 @@ endfunc
|
||||
func Test_isinf()
|
||||
call assert_equal(1, isinf(1.0/0.0))
|
||||
call assert_equal(-1, isinf(-1.0/0.0))
|
||||
eval (-1.0/0.0)->isinf()->assert_equal(-1)
|
||||
call assert_false(isinf(1.0))
|
||||
call assert_false(isinf(0.0/0.0))
|
||||
call assert_false(isinf('a'))
|
||||
@ -302,6 +328,7 @@ func Test_isnan()
|
||||
call assert_true(isnan(0.0/0.0))
|
||||
call assert_false(isnan(1.0))
|
||||
call assert_false(isnan(1.0/0.0))
|
||||
eval (1.0/0.0)->isnan()->assert_false()
|
||||
call assert_false(isnan(-1.0/0.0))
|
||||
call assert_false(isnan('a'))
|
||||
call assert_false(isnan([]))
|
||||
|
@ -852,7 +852,7 @@ func Test_byte2line_line2byte()
|
||||
|
||||
set fileformat=mac
|
||||
call assert_equal([-1, -1, 1, 1, 2, 2, 2, 3, 3, -1],
|
||||
\ map(range(-1, 8), 'byte2line(v:val)'))
|
||||
\ map(range(-1, 8), 'v:val->byte2line()'))
|
||||
call assert_equal([-1, -1, 1, 3, 6, 8, -1],
|
||||
\ map(range(-1, 5), 'line2byte(v:val)'))
|
||||
|
||||
@ -875,6 +875,34 @@ func Test_byte2line_line2byte()
|
||||
bw!
|
||||
endfunc
|
||||
|
||||
func Test_byteidx()
|
||||
let a = '.é.' " one char of two bytes
|
||||
call assert_equal(0, byteidx(a, 0))
|
||||
call assert_equal(0, byteidxcomp(a, 0))
|
||||
call assert_equal(1, byteidx(a, 1))
|
||||
call assert_equal(1, byteidxcomp(a, 1))
|
||||
call assert_equal(3, byteidx(a, 2))
|
||||
call assert_equal(3, byteidxcomp(a, 2))
|
||||
call assert_equal(4, byteidx(a, 3))
|
||||
call assert_equal(4, byteidxcomp(a, 3))
|
||||
call assert_equal(-1, byteidx(a, 4))
|
||||
call assert_equal(-1, byteidxcomp(a, 4))
|
||||
|
||||
let b = '.é.' " normal e with composing char
|
||||
call assert_equal(0, b->byteidx(0))
|
||||
call assert_equal(1, b->byteidx(1))
|
||||
call assert_equal(4, b->byteidx(2))
|
||||
call assert_equal(5, b->byteidx(3))
|
||||
call assert_equal(-1, b->byteidx(4))
|
||||
|
||||
call assert_equal(0, b->byteidxcomp(0))
|
||||
call assert_equal(1, b->byteidxcomp(1))
|
||||
call assert_equal(2, b->byteidxcomp(2))
|
||||
call assert_equal(4, b->byteidxcomp(3))
|
||||
call assert_equal(5, b->byteidxcomp(4))
|
||||
call assert_equal(-1, b->byteidxcomp(5))
|
||||
endfunc
|
||||
|
||||
" Test for charidx()
|
||||
func Test_charidx()
|
||||
let a = 'xáb́y'
|
||||
@ -1065,7 +1093,7 @@ func Test_col()
|
||||
call assert_equal(7, col('$'))
|
||||
call assert_equal(4, col("'x"))
|
||||
call assert_equal(6, col("'Y"))
|
||||
call assert_equal(2, col([1, 2]))
|
||||
call assert_equal(2, [1, 2]->col())
|
||||
call assert_equal(7, col([1, '$']))
|
||||
|
||||
call assert_equal(0, col(''))
|
||||
@ -1413,13 +1441,13 @@ func Test_bufadd_bufload()
|
||||
call assert_equal([''], getbufline(buf, 1, '$'))
|
||||
|
||||
let curbuf = bufnr('')
|
||||
call writefile(['some', 'text'], 'otherName')
|
||||
let buf = bufadd('otherName')
|
||||
call writefile(['some', 'text'], 'XotherName')
|
||||
let buf = 'XotherName'->bufadd()
|
||||
call assert_notequal(0, buf)
|
||||
call assert_equal(1, bufexists('otherName'))
|
||||
eval 'XotherName'->bufexists()->assert_equal(1)
|
||||
call assert_equal(0, getbufvar(buf, '&buflisted'))
|
||||
call assert_equal(0, bufloaded(buf))
|
||||
call bufload(buf)
|
||||
eval buf->bufload()
|
||||
call assert_equal(1, bufloaded(buf))
|
||||
call assert_equal(['some', 'text'], getbufline(buf, 1, '$'))
|
||||
call assert_equal(curbuf, bufnr(''))
|
||||
@ -1439,8 +1467,9 @@ func Test_bufadd_bufload()
|
||||
call assert_equal(0, bufexists(buf2))
|
||||
|
||||
bwipe someName
|
||||
bwipe otherName
|
||||
bwipe XotherName
|
||||
call assert_equal(0, bufexists('someName'))
|
||||
call delete('XotherName')
|
||||
endfunc
|
||||
|
||||
func Test_readdir()
|
||||
@ -1473,6 +1502,20 @@ func Test_readdir()
|
||||
call delete('Xdir', 'rf')
|
||||
endfunc
|
||||
|
||||
func Test_call()
|
||||
call assert_equal(3, call('len', [123]))
|
||||
call assert_equal(3, 'len'->call([123]))
|
||||
call assert_fails("call call('len', 123)", 'E714:')
|
||||
call assert_equal(0, call('', []))
|
||||
|
||||
function Mylen() dict
|
||||
return len(self.data)
|
||||
endfunction
|
||||
let mydict = {'data': [0, 1, 2, 3], 'len': function("Mylen")}
|
||||
eval mydict.len->call([], mydict)->assert_equal(4)
|
||||
call assert_fails("call call('Mylen', [], 0)", 'E715:')
|
||||
endfunc
|
||||
|
||||
" Test for the eval() function
|
||||
func Test_eval()
|
||||
call assert_fails("call eval('5 a')", 'E488:')
|
||||
|
@ -37,7 +37,7 @@ function Test_hide()
|
||||
" :hide as a command
|
||||
hide
|
||||
call assert_equal([orig_bname, orig_winnr], [bufname(''), winnr('$')])
|
||||
call assert_equal([1, 1], [buflisted('Xf1'), bufloaded('Xf1')])
|
||||
call assert_equal([1, 1], ['Xf1'->buflisted(), 'Xf1'->bufloaded()])
|
||||
bwipeout! Xf1
|
||||
|
||||
new Xf1
|
||||
|
@ -61,7 +61,7 @@ endfunction
|
||||
|
||||
function Test_lambda_fails()
|
||||
call assert_equal(3, {a, b -> a + b}(1, 2))
|
||||
call assert_fails('echo {a, a -> a + a}(1, 2)', 'E15:')
|
||||
call assert_fails('echo {a, a -> a + a}(1, 2)', 'E853:')
|
||||
call assert_fails('echo {a, b -> a + b)}(1, 2)', 'E15:')
|
||||
endfunc
|
||||
|
||||
|
@ -242,7 +242,7 @@ func Test_matchaddpos_otherwin()
|
||||
\]
|
||||
call assert_equal(expect, savematches)
|
||||
|
||||
call clearmatches(winid)
|
||||
eval winid->clearmatches()
|
||||
call assert_equal([], getmatches(winid))
|
||||
|
||||
call setmatches(savematches, winid)
|
||||
|
159
src/nvim/testdir/test_method.vim
Normal file
159
src/nvim/testdir/test_method.vim
Normal file
@ -0,0 +1,159 @@
|
||||
" Tests for ->method()
|
||||
|
||||
func Test_list_method()
|
||||
let l = [1, 2, 3]
|
||||
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->deepcopy())
|
||||
call assert_equal(1, l->count(2))
|
||||
call assert_false(l->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, 3], [1, 2, 3]->filter('v:val != 2'))
|
||||
call assert_equal(2, l->get(1))
|
||||
call assert_equal(1, l->index(2))
|
||||
call assert_equal([0, 1, 2, 3], [1, 2, 3]->insert(0))
|
||||
call assert_fails('eval l->items()', 'E715:')
|
||||
call assert_equal('1 2 3', l->join())
|
||||
call assert_fails('eval l->keys()', 'E715:')
|
||||
call assert_equal(3, l->len())
|
||||
call assert_equal([2, 3, 4], [1, 2, 3]->map('v:val + 1'))
|
||||
call assert_equal(3, l->max())
|
||||
call assert_equal(1, l->min())
|
||||
call assert_equal(2, [1, 2, 3]->remove(1))
|
||||
call assert_equal([1, 2, 3, 1, 2, 3], l->repeat(2))
|
||||
call assert_equal([3, 2, 1], [1, 2, 3]->reverse())
|
||||
call assert_equal([1, 2, 3, 4], [4, 2, 3, 1]->sort())
|
||||
call assert_equal('[1, 2, 3]', l->string())
|
||||
call assert_equal(v:t_list, l->type())
|
||||
call assert_equal([1, 2, 3], [1, 1, 2, 3, 3]->uniq())
|
||||
call assert_fails('eval l->values()', 'E715:')
|
||||
endfunc
|
||||
|
||||
func Test_dict_method()
|
||||
let d = #{one: 1, two: 2, three: 3}
|
||||
|
||||
call assert_equal(d, d->copy())
|
||||
call assert_equal(d, d->deepcopy())
|
||||
call assert_equal(1, d->count(2))
|
||||
call assert_false(d->empty())
|
||||
call assert_true({}->empty())
|
||||
call assert_equal(#{one: 1, two: 2, three: 3, four: 4}, d->extend(#{four: 4}))
|
||||
call assert_equal(#{one: 1, two: 2, three: 3}, d->filter('v:val != 4'))
|
||||
call assert_equal(2, d->get('two'))
|
||||
" Nvim doesn't support Blobs yet; expect a different emsg
|
||||
" call assert_fails("let x = d->index(2)", 'E897:')
|
||||
" call assert_fails("let x = d->insert(0)", 'E899:')
|
||||
call assert_fails("let x = d->index(2)", 'E714:')
|
||||
call assert_fails("let x = d->insert(0)", 'E686:')
|
||||
call assert_true(d->has_key('two'))
|
||||
call assert_equal([['one', 1], ['two', 2], ['three', 3]], d->items())
|
||||
call assert_fails("let x = d->join()", 'E714:')
|
||||
call assert_equal(['one', 'two', 'three'], d->keys())
|
||||
call assert_equal(3, d->len())
|
||||
call assert_equal(#{one: 2, two: 3, three: 4}, d->map('v:val + 1'))
|
||||
call assert_equal(#{one: 1, two: 2, three: 3}, d->map('v:val - 1'))
|
||||
call assert_equal(3, d->max())
|
||||
call assert_equal(1, d->min())
|
||||
call assert_equal(2, d->remove("two"))
|
||||
let d.two = 2
|
||||
call assert_fails('let x = d->repeat(2)', 'E731:')
|
||||
" Nvim doesn't support Blobs yet; expect a different emsg
|
||||
" call assert_fails('let x = d->reverse()', 'E899:')
|
||||
call assert_fails('let x = d->reverse()', 'E686:')
|
||||
call assert_fails('let x = d->sort()', 'E686:')
|
||||
call assert_equal("{'one': 1, 'two': 2, 'three': 3}", d->string())
|
||||
call assert_equal(v:t_dict, d->type())
|
||||
call assert_fails('let x = d->uniq()', 'E686:')
|
||||
call assert_equal([1, 2, 3], d->values())
|
||||
endfunc
|
||||
|
||||
func Test_string_method()
|
||||
eval '1 2 3'->split()->assert_equal(['1', '2', '3'])
|
||||
eval '1 2 3'->split()->map({i, v -> str2nr(v)})->assert_equal([1, 2, 3])
|
||||
eval 'ABC'->str2list()->assert_equal([65, 66, 67])
|
||||
eval 'ABC'->strlen()->assert_equal(3)
|
||||
eval "a\rb\ec"->strtrans()->assert_equal('a^Mb^[c')
|
||||
eval "aあb"->strwidth()->assert_equal(4)
|
||||
eval 'abc'->substitute('b', 'x', '')->assert_equal('axc')
|
||||
|
||||
eval 'abc'->printf('the %s arg')->assert_equal('the abc arg')
|
||||
endfunc
|
||||
|
||||
func Test_method_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
|
||||
|
||||
func Test_method_funcref()
|
||||
func Concat(one, two, three)
|
||||
return a:one .. a:two .. a:three
|
||||
endfunc
|
||||
let FuncRef = function('Concat')
|
||||
eval 'foo'->FuncRef('bar', 'tail')->assert_equal('foobartail')
|
||||
|
||||
" not enough arguments
|
||||
call assert_fails("eval 'foo'->FuncRef('bar')", 'E119:')
|
||||
" too many arguments
|
||||
call assert_fails("eval 'foo'->FuncRef('bar', 'tail', 'four')", 'E118:')
|
||||
|
||||
let Partial = function('Concat', ['two'])
|
||||
eval 'one'->Partial('three')->assert_equal('onetwothree')
|
||||
|
||||
" not enough arguments
|
||||
call assert_fails("eval 'one'->Partial()", 'E119:')
|
||||
" too many arguments
|
||||
call assert_fails("eval 'one'->Partial('three', 'four')", 'E118:')
|
||||
|
||||
delfunc Concat
|
||||
endfunc
|
||||
|
||||
func Test_method_float()
|
||||
eval 1.234->string()->assert_equal('1.234')
|
||||
eval -1.234->string()->assert_equal('-1.234')
|
||||
endfunc
|
||||
|
||||
func Test_method_syntax()
|
||||
eval [1, 2, 3] ->sort( )
|
||||
eval [1, 2, 3]
|
||||
\ ->sort(
|
||||
\ )
|
||||
call assert_fails('eval [1, 2, 3]-> sort()', 'E260:')
|
||||
call assert_fails('eval [1, 2, 3]->sort ()', 'E274:')
|
||||
call assert_fails('eval [1, 2, 3]-> sort ()', 'E260:')
|
||||
endfunc
|
||||
|
||||
func Test_method_lambda()
|
||||
eval "text"->{x -> x .. " extended"}()->assert_equal('text extended')
|
||||
eval "text"->{x, y -> x .. " extended " .. y}('more')->assert_equal('text extended more')
|
||||
|
||||
call assert_fails('eval "text"->{x -> x .. " extended"} ()', 'E274:')
|
||||
|
||||
" todo: lambda accepts more arguments than it consumes
|
||||
" call assert_fails('eval "text"->{x -> x .. " extended"}("more")', 'E99:')
|
||||
|
||||
" Nvim doesn't include test_refcount().
|
||||
" let l = [1, 2, 3]
|
||||
" eval l->{x -> x}()
|
||||
" call assert_equal(1, test_refcount(l))
|
||||
endfunc
|
||||
|
||||
func Test_method_not_supported()
|
||||
call assert_fails('eval 123->changenr()', 'E276:')
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
@ -250,7 +250,7 @@ endfunc
|
||||
|
||||
func Test_noinsert_complete()
|
||||
func! s:complTest1() abort
|
||||
call complete(1, ['source', 'soundfold'])
|
||||
eval ['source', 'soundfold']->complete(1)
|
||||
return ''
|
||||
endfunc
|
||||
|
||||
@ -403,7 +403,7 @@ func DummyCompleteFour(findstart, base)
|
||||
return 0
|
||||
else
|
||||
call complete_add('four1')
|
||||
call complete_add('four2')
|
||||
eval 'four2'->complete_add()
|
||||
call complete_check()
|
||||
call complete_add('four3')
|
||||
call complete_add('four4')
|
||||
@ -989,7 +989,7 @@ func GetCompleteInfo()
|
||||
if empty(g:compl_what)
|
||||
let g:compl_info = complete_info()
|
||||
else
|
||||
let g:compl_info = complete_info(g:compl_what)
|
||||
let g:compl_info = g:compl_what->complete_info()
|
||||
endif
|
||||
return ''
|
||||
endfunc
|
||||
|
@ -546,8 +546,8 @@ func Test_synstack_synIDtrans()
|
||||
call assert_equal([], synstack(1, 1))
|
||||
|
||||
norm f/
|
||||
call assert_equal(['cComment', 'cCommentStart'], map(synstack(line("."), col(".")), 'synIDattr(v:val, "name")'))
|
||||
call assert_equal(['Comment', 'Comment'], map(synstack(line("."), col(".")), 'synIDattr(synIDtrans(v:val), "name")'))
|
||||
eval synstack(line("."), col("."))->map('synIDattr(v:val, "name")')->assert_equal(['cComment', 'cCommentStart'])
|
||||
eval synstack(line("."), col("."))->map('synIDattr(synIDtrans(v:val), "name")')->assert_equal(['Comment', 'Comment'])
|
||||
|
||||
norm fA
|
||||
call assert_equal(['cComment'], map(synstack(line("."), col(".")), 'synIDattr(v:val, "name")'))
|
||||
|
@ -7,10 +7,10 @@ func Test_System()
|
||||
if !executable('echo') || !executable('cat') || !executable('wc')
|
||||
return
|
||||
endif
|
||||
let out = system('echo 123')
|
||||
let out = 'echo 123'->system()
|
||||
call assert_equal("123\n", out)
|
||||
|
||||
let out = systemlist('echo 123')
|
||||
let out = 'echo 123'->systemlist()
|
||||
if &shell =~# 'cmd.exe$'
|
||||
call assert_equal(["123\r"], out)
|
||||
else
|
||||
|
@ -47,7 +47,7 @@ func FuncWithRef(a)
|
||||
endfunc
|
||||
|
||||
func Test_user_func()
|
||||
let g:FuncRef=function("FuncWithRef")
|
||||
let g:FuncRef = function("FuncWithRef")
|
||||
let g:counter = 0
|
||||
inoremap <expr> ( ListItem()
|
||||
inoremap <expr> [ ListReset()
|
||||
@ -62,6 +62,14 @@ func Test_user_func()
|
||||
call assert_equal(9, g:retval)
|
||||
call assert_equal(333, g:FuncRef(333))
|
||||
|
||||
let g:retval = "nop"
|
||||
call assert_equal('xxx4asdf', "xxx"->Table(4, "asdf"))
|
||||
call assert_equal('fail', 45->Compute(0, "retval"))
|
||||
call assert_equal('nop', g:retval)
|
||||
call assert_equal('ok', 45->Compute(5, "retval"))
|
||||
call assert_equal(9, g:retval)
|
||||
" call assert_equal(333, 333->g:FuncRef())
|
||||
|
||||
enew
|
||||
|
||||
normal oXX+-XX
|
||||
@ -150,6 +158,14 @@ func Test_default_arg()
|
||||
\ execute('func Args2'))
|
||||
endfunc
|
||||
|
||||
func s:addFoo(lead)
|
||||
return a:lead .. 'foo'
|
||||
endfunc
|
||||
|
||||
func Test_user_method()
|
||||
eval 'bar'->s:addFoo()->assert_equal('barfoo')
|
||||
endfunc
|
||||
|
||||
func Test_failed_call_in_try()
|
||||
try | call UnknownFunc() | catch | endtry
|
||||
endfunc
|
||||
|
@ -1372,6 +1372,7 @@ func Test_bitwise_functions()
|
||||
" and
|
||||
call assert_equal(127, and(127, 127))
|
||||
call assert_equal(16, and(127, 16))
|
||||
eval 127->and(16)->assert_equal(16)
|
||||
call assert_equal(0, and(127, 128))
|
||||
call assert_fails("call and(1.0, 1)", 'E805:')
|
||||
call assert_fails("call and([], 1)", 'E745:')
|
||||
@ -1382,6 +1383,7 @@ func Test_bitwise_functions()
|
||||
" or
|
||||
call assert_equal(23, or(16, 7))
|
||||
call assert_equal(15, or(8, 7))
|
||||
eval 8->or(7)->assert_equal(15)
|
||||
call assert_equal(123, or(0, 123))
|
||||
call assert_fails("call or(1.0, 1)", 'E805:')
|
||||
call assert_fails("call or([], 1)", 'E745:')
|
||||
@ -1392,6 +1394,7 @@ func Test_bitwise_functions()
|
||||
" xor
|
||||
call assert_equal(0, xor(127, 127))
|
||||
call assert_equal(111, xor(127, 16))
|
||||
eval 127->xor(16)->assert_equal(111)
|
||||
call assert_equal(255, xor(127, 128))
|
||||
call assert_fails("call xor(1.0, 1)", 'E805:')
|
||||
call assert_fails("call xor([], 1)", 'E745:')
|
||||
@ -1401,6 +1404,7 @@ func Test_bitwise_functions()
|
||||
call assert_fails("call xor(1, {})", 'E728:')
|
||||
" invert
|
||||
call assert_equal(65408, and(invert(127), 65535))
|
||||
eval 127->invert()->and(65535)->assert_equal(65408)
|
||||
call assert_equal(65519, and(invert(16), 65535))
|
||||
call assert_equal(65407, and(invert(128), 65535))
|
||||
call assert_fails("call invert(1.0)", 'E805:')
|
||||
|
@ -247,9 +247,9 @@ describe('startup', function()
|
||||
[[" -u NONE -i NONE --cmd "set noruler" --cmd "let g:foo = g:bar"')]])
|
||||
screen:expect([[
|
||||
^ |
|
||||
|
|
||||
Error detected while processing pre-vimrc command line: |
|
||||
E121: Undefined variable: g:bar |
|
||||
E15: Invalid expression: g:bar |
|
||||
Press ENTER or type command to continue |
|
||||
|
|
||||
]])
|
||||
|
@ -53,7 +53,7 @@ describe('NULL', function()
|
||||
|
||||
-- Correct behaviour
|
||||
null_expr_test('can be indexed with error message for empty list', 'L[0]',
|
||||
'E684: list index out of range: 0\nE15: Invalid expression: L[0]', nil)
|
||||
'E684: list index out of range: 0', nil)
|
||||
null_expr_test('can be splice-indexed', 'L[:]', 0, {})
|
||||
null_expr_test('is not locked', 'islocked("v:_null_list")', 0, 0)
|
||||
null_test('is accepted by :for', 'for x in L|throw x|endfor', 0)
|
||||
@ -68,7 +68,7 @@ describe('NULL', function()
|
||||
null_expr_test('can be copied', 'copy(L)', 0, {})
|
||||
null_expr_test('can be deepcopied', 'deepcopy(L)', 0, {})
|
||||
null_expr_test('does not crash when indexed', 'L[1]',
|
||||
'E684: list index out of range: 1\nE15: Invalid expression: L[1]', nil)
|
||||
'E684: list index out of range: 1', nil)
|
||||
null_expr_test('does not crash call()', 'call("arglistid", L)', 0, 0)
|
||||
null_expr_test('does not crash col()', 'col(L)', 0, 0)
|
||||
null_expr_test('does not crash virtcol()', 'virtcol(L)', 0, 0)
|
||||
@ -135,7 +135,7 @@ describe('NULL', function()
|
||||
end)
|
||||
describe('dict', function()
|
||||
it('does not crash when indexing NULL dict', function()
|
||||
eq('\nE716: Key not present in Dictionary: "test"\nE15: Invalid expression: v:_null_dict.test',
|
||||
eq('\nE716: Key not present in Dictionary: "test"',
|
||||
redir_exec('echo v:_null_dict.test'))
|
||||
end)
|
||||
null_expr_test('makes extend error out', 'extend(D, {})', 'E742: Cannot change value of extend() argument', 0)
|
||||
|
@ -26,6 +26,14 @@ describe('assert function:', function()
|
||||
call('assert_beeps', 'normal 0')
|
||||
expected_errors({'command did not beep: normal 0'})
|
||||
end)
|
||||
|
||||
it('can be used as a method', function()
|
||||
local tmpname = source [[
|
||||
call assert_equal(0, 'normal h'->assert_beeps())
|
||||
call assert_equal(1, 'normal 0'->assert_beeps())
|
||||
]]
|
||||
expected_errors({tmpname .. ' line 2: command did not beep: normal 0'})
|
||||
end)
|
||||
end)
|
||||
|
||||
-- assert_equal({expected}, {actual}, [, {msg}])
|
||||
@ -133,6 +141,14 @@ describe('assert function:', function()
|
||||
call('assert_false', {})
|
||||
expected_errors({'Expected False but got []'})
|
||||
end)
|
||||
|
||||
it('can be used as a method', function()
|
||||
local tmpname = source [[
|
||||
call assert_equal(0, v:false->assert_false())
|
||||
call assert_equal(1, 123->assert_false())
|
||||
]]
|
||||
expected_errors({tmpname .. ' line 2: Expected False but got 123'})
|
||||
end)
|
||||
end)
|
||||
|
||||
-- assert_true({actual}, [, {msg}])
|
||||
@ -148,6 +164,14 @@ describe('assert function:', function()
|
||||
eq(1, call('assert_true', 1.5))
|
||||
expected_errors({'Expected True but got 1.5'})
|
||||
end)
|
||||
|
||||
it('can be used as a method', function()
|
||||
local tmpname = source [[
|
||||
call assert_equal(0, v:true->assert_true())
|
||||
call assert_equal(1, 0->assert_true())
|
||||
]]
|
||||
expected_errors({tmpname .. ' line 2: Expected True but got 0'})
|
||||
end)
|
||||
end)
|
||||
|
||||
describe('v:errors', function()
|
||||
@ -223,6 +247,15 @@ describe('assert function:', function()
|
||||
call('assert_match', 'bar.*foo', 'foobar', 'wrong')
|
||||
expected_errors({"wrong: Pattern 'bar.*foo' does not match 'foobar'"})
|
||||
end)
|
||||
|
||||
it('can be used as a method', function()
|
||||
local tmpname = source [[
|
||||
call assert_equal(1, 'foobar'->assert_match('bar.*foo', 'wrong'))
|
||||
]]
|
||||
expected_errors({
|
||||
tmpname .. " line 1: wrong: Pattern 'bar.*foo' does not match 'foobar'"
|
||||
})
|
||||
end)
|
||||
end)
|
||||
|
||||
-- assert_notmatch({pat}, {text}[, {msg}])
|
||||
@ -237,6 +270,13 @@ describe('assert function:', function()
|
||||
call('assert_notmatch', 'foo', 'foobar')
|
||||
expected_errors({"Pattern 'foo' does match 'foobar'"})
|
||||
end)
|
||||
|
||||
it('can be used as a method', function()
|
||||
local tmpname = source [[
|
||||
call assert_equal(1, 'foobar'->assert_notmatch('foo'))
|
||||
]]
|
||||
expected_errors({tmpname .. " line 1: Pattern 'foo' does match 'foobar'"})
|
||||
end)
|
||||
end)
|
||||
|
||||
-- assert_fails({cmd}, [, {error}])
|
||||
@ -267,6 +307,15 @@ describe('assert function:', function()
|
||||
eq(1, eval([[assert_fails('echo', '', 'echo command')]]))
|
||||
expected_errors({'command did not fail: echo command'})
|
||||
end)
|
||||
|
||||
it('can be used as a method', function()
|
||||
local tmpname = source [[
|
||||
call assert_equal(1, 'echo'->assert_fails('', 'echo command'))
|
||||
]]
|
||||
expected_errors({
|
||||
tmpname .. ' line 1: command did not fail: echo command'
|
||||
})
|
||||
end)
|
||||
end)
|
||||
|
||||
-- assert_inrange({lower}, {upper}, {actual}[, {msg}])
|
||||
@ -292,6 +341,15 @@ describe('assert function:', function()
|
||||
eq('Vim(call):E119: Not enough arguments for function: assert_inrange',
|
||||
exc_exec("call assert_inrange(1, 1)"))
|
||||
end)
|
||||
|
||||
it('can be used as a method', function()
|
||||
local tmpname = source [[
|
||||
call assert_equal(0, 5->assert_inrange(5, 7))
|
||||
call assert_equal(0, 7->assert_inrange(5, 7))
|
||||
call assert_equal(1, 8->assert_inrange(5, 7))
|
||||
]]
|
||||
expected_errors({tmpname .. ' line 3: Expected range 5 - 7, but got 8'})
|
||||
end)
|
||||
end)
|
||||
|
||||
-- assert_report({msg})
|
||||
@ -302,6 +360,13 @@ describe('assert function:', function()
|
||||
command('call remove(v:errors, 0)')
|
||||
expected_empty()
|
||||
end)
|
||||
|
||||
it('can be used as a method', function()
|
||||
local tmpname = source [[
|
||||
call assert_equal(1, 'also wrong'->assert_report())
|
||||
]]
|
||||
expected_errors({tmpname .. ' line 1: also wrong'})
|
||||
end)
|
||||
end)
|
||||
|
||||
-- assert_exception({cmd}, [, {error}])
|
||||
|
@ -481,6 +481,21 @@ describe('v:lua', function()
|
||||
pcall_err(eval, 'v:lua.mymod.crashy()'))
|
||||
end)
|
||||
|
||||
it('works when called as a method', function()
|
||||
eq(123, eval('110->v:lua.foo(13)'))
|
||||
eq(true, exec_lua([[return _G.val == nil]]))
|
||||
|
||||
eq(321, eval('300->v:lua.foo(21, "boop")'))
|
||||
eq("boop", exec_lua([[return _G.val]]))
|
||||
|
||||
eq(NIL, eval('"there"->v:lua.mymod.noisy()'))
|
||||
eq("hey there", meths.get_current_line())
|
||||
eq({5, 10, 15, 20}, eval('[[1], [2, 3], [4]]->v:lua.vim.tbl_flatten()->map({_, v -> v * 5})'))
|
||||
|
||||
eq("Vim:E5108: Error executing lua [string \"<nvim>\"]:0: attempt to call global 'nonexistent' (a nil value)",
|
||||
pcall_err(eval, '"huh?"->v:lua.mymod.crashy()'))
|
||||
end)
|
||||
|
||||
it('works in :call', function()
|
||||
command(":call v:lua.mymod.noisy('command')")
|
||||
eq("hey command", meths.get_current_line())
|
||||
@ -518,8 +533,15 @@ describe('v:lua', function()
|
||||
|
||||
eq("Vim:E15: Invalid expression: v:['lua'].foo()", pcall_err(eval, "v:['lua'].foo()"))
|
||||
eq("Vim(call):E461: Illegal variable name: v:['lua']", pcall_err(command, "call v:['lua'].baar()"))
|
||||
eq("Vim:E117: Unknown function: v:lua", pcall_err(eval, "v:lua()"))
|
||||
|
||||
eq("Vim(let):E46: Cannot change read-only variable \"v:['lua']\"", pcall_err(command, "let v:['lua'] = 'xx'"))
|
||||
eq("Vim(let):E46: Cannot change read-only variable \"v:lua\"", pcall_err(command, "let v:lua = 'xx'"))
|
||||
|
||||
eq("Vim:E107: Missing parentheses: v:lua.func", pcall_err(eval, "'bad'->v:lua.func"))
|
||||
eq("Vim:E274: No white space allowed before parenthesis", pcall_err(eval, "'bad'->v:lua.func ()"))
|
||||
eq("Vim:E107: Missing parentheses: v:lua", pcall_err(eval, "'bad'->v:lua"))
|
||||
eq("Vim:E117: Unknown function: v:lua", pcall_err(eval, "'bad'->v:lua()"))
|
||||
eq("Vim:E15: Invalid expression: v:lua.()", pcall_err(eval, "'bad'->v:lua.()"))
|
||||
end)
|
||||
end)
|
||||
|
@ -653,14 +653,12 @@ describe('clipboard (with fake clipboard.vim)', function()
|
||||
'',
|
||||
'',
|
||||
'E121: Undefined variable: doesnotexist',
|
||||
'E15: Invalid expression: doesnotexist',
|
||||
}, 'v'}, eval("g:test_clip['*']"))
|
||||
feed_command(':echo "Howdy!"')
|
||||
eq({{
|
||||
'',
|
||||
'',
|
||||
'E121: Undefined variable: doesnotexist',
|
||||
'E15: Invalid expression: doesnotexist',
|
||||
'',
|
||||
'Howdy!',
|
||||
}, 'v'}, eval("g:test_clip['*']"))
|
||||
|
Loading…
Reference in New Issue
Block a user