Compare commits

...

22 Commits

Author SHA1 Message Date
Bram Moolenaar
0588d4f9d2 patch 7.4.2139
Problem:    :delfunction causes illegal memory access.
Solution:   Correct logic when deciding to free a function.
2016-08-01 16:29:47 +02:00
Bram Moolenaar
2d3d60a7d4 patch 7.4.2138
Problem:    Test 86 and 87 fail.
Solution:   Call func_ref() also for regular functions.
2016-08-01 16:27:23 +02:00
Bram Moolenaar
437bafe4c8 patch 7.4.2137
Problem:    Using function() with a name will find another function when it is
            redefined.
Solution:   Add funcref().  Refer to lambda using a partial.  Fix several
            reference counting issues.
2016-08-01 15:40:54 +02:00
Bram Moolenaar
5801644819 patch 7.4.2136
Problem:    Closure function fails.
Solution:   Don't reset uf_scoped when it points to another funccal.
2016-07-31 18:30:22 +02:00
Bram Moolenaar
89eaa4185e patch 7.4.2135
Problem:    Various tiny issues.
Solution:   Update comments, white space, etc.
2016-07-31 14:17:27 +02:00
Bram Moolenaar
b54c3ff317 patch 7.4.2134
Problem:    No error for using function() badly.
Solution:   Check for passing wrong function name. (Ken Takata)
2016-07-31 14:11:58 +02:00
Bram Moolenaar
fc1f2015e8 patch 7.4.2133
Problem:    Can't build with tiny features.
Solution:   Add #ifdef.
2016-07-30 23:18:47 +02:00
Bram Moolenaar
31440a1f2b patch 7.4.2132
Problem:    test_partial has memory leaks reported.
Solution:   Add a note about why this happens.
2016-07-30 23:14:28 +02:00
Bram Moolenaar
57e69ff2cc patch 7.4.2131
Problem:    More memory leaks when using partial, e.g. for "exit-cb".
Solution:   Don't copy the callback when using a partial.
2016-07-30 23:05:09 +02:00
Bram Moolenaar
623e263ffb patch 7.4.2130
Problem:    Pending timers cause false memory leak reports.
Solution:   Free all timers on exit.
2016-07-30 22:47:56 +02:00
Bram Moolenaar
3ab14355ed patch 7.4.2129
Problem:    Memory leak when using timer_start(). (Dominique Pelle)
Solution:   Don't copy the callback when using a partial.
2016-07-30 22:32:11 +02:00
Bram Moolenaar
1e2258297b patch 7.4.2128
Problem:    Memory leak when saving for undo fails.
Solution:   Free allocated memory. (Hirohito Higashi)
2016-07-30 21:48:59 +02:00
Bram Moolenaar
3bcfca3ab4 patch 7.4.2127
Problem:    The short form of ":noswapfile" is ":noswap" instead of ":now".
            (Kent Sibilev)
Solution:   Only require three characters.  Add a test for the short forms.
2016-07-30 19:39:29 +02:00
Bram Moolenaar
90d121fa36 patch 7.4.2126
Problem:    No tests for :diffget and :diffput
Solution:   Add tests.
2016-07-30 19:11:25 +02:00
Bram Moolenaar
b20617b0b0 Add OSX build to Travis CI. (Christian Brabandt) 2016-07-30 17:41:49 +02:00
Bram Moolenaar
a5c0cc1133 patch 7.4.2125
Problem:    Compiler warning for loss of data.
Solution:   Add a type cast. (Christian Brabandt)
2016-07-30 16:40:39 +02:00
Bram Moolenaar
623cf88f9c patch 7.4.2124
Problem:    diffmode test leaves files behind, breaking another test.
Solution:   Delete the files.
2016-07-30 16:36:01 +02:00
Bram Moolenaar
42093c0ec5 patch 7.4.2123
Problem:    No new style test for diff mode.
Solution:   Add a test.  Check that folds are in sync.
2016-07-30 16:16:54 +02:00
Bram Moolenaar
b822cb0f93 patch 7.4.2122
Problem:    Mac: don't get +clipboard in huge build.
Solution:   Move #define down below including featureh.h
2016-07-30 14:12:23 +02:00
Bram Moolenaar
9532fe7fbe patch 7.4.2121
Problem:    No easy way to check if lambda and closure are supported.
Solution:   Add the +lambda feature.
2016-07-29 22:50:35 +02:00
Bram Moolenaar
10ce39a0d5 patch 7.4.2120
Problem:    User defined functions can't be a closure.
Solution:   Add the "closure" argument. Allow using :unlet on a bound
            variable. (Yasuhiro Matsumoto, Ken Takata)
2016-07-29 22:37:06 +02:00
Bram Moolenaar
1e96d9bf98 patch 7.4.2119
Problem:    Closures are not supported.
Solution:   Capture variables in lambdas from the outer scope. (Yasuhiro
            Matsumoto, Ken Takata)
2016-07-29 22:15:09 +02:00
38 changed files with 1460 additions and 461 deletions

View File

@@ -1,5 +1,9 @@
language: c
os:
- osx
- linux
compiler:
- clang
- gcc
@@ -7,14 +11,43 @@ compiler:
env:
- BUILD=yes TEST=scripttests COVERAGE=yes CFLAGS=--coverage LDFLAGS=--coverage FEATURES=huge SHADOWOPT= SRCDIR=./src CHECK_AUTOCONF=no
"CONFOPT='--enable-perlinterp --enable-pythoninterp --enable-python3interp --enable-rubyinterp --enable-luainterp'"
- BUILD=no TEST=unittests COVERAGE=yes CFLAGS=--coverage LDFLAGS=--coverage FEATURES=huge SHADOWOPT= SRCDIR=./src CHECK_AUTOCONF=no
CHECK_AUTOCONF=yes
- BUILD=no TEST=unittests COVERAGE=yes CFLAGS=--coverage LDFLAGS=--coverage FEATURES=huge SHADOWOPT= SRCDIR=./src CHECK_AUTOCONF=yes
- BUILD=yes TEST=test COVERAGE=no FEATURES=normal CONFOPT= SHADOWOPT="-C src/shadow" SRCDIR=./src/shadow CHECK_AUTOCONF=no
- BUILD=yes TEST=test COVERAGE=no FEATURES=small CONFOPT= SHADOWOPT= SRCDIR=./src CHECK_AUTOCONF=no
- BUILD=yes TEST=test COVERAGE=no FEATURES=tiny CONFOPT= SHADOWOPT= SRCDIR=./src CHECK_AUTOCONF=no
# Mac OSX build
- BUILD=yes TEST=test COVERAGE=no FEATURES=huge SHADOWOPT= SRCDIR=./src CHECK_AUTOCONF=no
"CONFOPT='--enable-perlinterp --enable-pythoninterp --enable-rubyinterp --enable-luainterp'"
sudo: false
git:
depth: 1
# instead of a 6*2*2 matrix (2*os + 2*compiler + 6*env),
# exclude some builds on mac os x and linux
# linux: 2*compiler + 5*env + mac: 2*compiler + 2*env
matrix:
exclude:
- os: osx
env: BUILD=yes TEST=test COVERAGE=no FEATURES=normal CONFOPT= SHADOWOPT="-C src/shadow" SRCDIR=./src/shadow CHECK_AUTOCONF=no
- os: osx
env: BUILD=no TEST=unittests COVERAGE=yes CFLAGS=--coverage LDFLAGS=--coverage FEATURES=huge SHADOWOPT= SRCDIR=./src CHECK_AUTOCONF=yes
- os: osx
env: BUILD=yes TEST=test COVERAGE=no FEATURES=small CONFOPT= SHADOWOPT= SRCDIR=./src CHECK_AUTOCONF=no
- os: osx
env: BUILD=yes TEST=scripttests COVERAGE=yes CFLAGS=--coverage LDFLAGS=--coverage FEATURES=huge SHADOWOPT= SRCDIR=./src CHECK_AUTOCONF=no
"CONFOPT='--enable-perlinterp --enable-pythoninterp --enable-python3interp --enable-rubyinterp --enable-luainterp'"
- os: linux
compiler: clang
env: BUILD=no TEST=unittests COVERAGE=yes CFLAGS=--coverage LDFLAGS=--coverage FEATURES=huge SHADOWOPT= SRCDIR=./src CHECK_AUTOCONF=yes
- os: linux
compiler: clang
env: BUILD=yes TEST=test COVERAGE=no FEATURES=small CONFOPT= SHADOWOPT= SRCDIR=./src CHECK_AUTOCONF=no
- os: linux
env: BUILD=yes TEST=test COVERAGE=no FEATURES=huge SHADOWOPT= SRCDIR=./src CHECK_AUTOCONF=no
"CONFOPT='--enable-perlinterp --enable-pythoninterp --enable-rubyinterp --enable-luainterp'"
branches:
except:
- /^v[0-9]/
@@ -32,6 +65,8 @@ addons:
before_install:
- pip install --user cpp-coveralls
# Lua is not installed on Travis OSX
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew install lua; export LUA_PREFIX=/usr/local; fi
script:
- NPROC=$(getconf _NPROCESSORS_ONLN)

View File

@@ -1,4 +1,4 @@
*eval.txt* For Vim version 7.4. Last change: 2016 Jul 24
*eval.txt* For Vim version 7.4. Last change: 2016 Jul 31
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -40,7 +40,7 @@ done, the features in this document are not available. See |+eval| and
There are nine types of variables:
Number A 32 or 64 bit signed number. |expr-number| *Number*
64-bit Number is available only when compiled with the
64-bit Numbers are available only when compiled with the
|+num64| feature.
Examples: -123 0x10 0177
@@ -1219,7 +1219,7 @@ the following ways:
1. The body of the lambda expression is an |expr1| and not a sequence of |Ex|
commands.
2. The prefix "a:" is optional for arguments. E.g.: >
2. The prefix "a:" should not be used for arguments. E.g.: >
:let F = {arg1, arg2 -> arg1 - arg2}
:echo F(5, 2)
< 3
@@ -1228,6 +1228,21 @@ The arguments are optional. Example: >
:let F = {-> 'error function'}
:echo F()
< error function
*closure*
Lambda expressions can access outer scope variables and arguments. This is
often called a closure. Example where "i" a and "a:arg" are used in a lambda
while they exists in the function scope. They remain valid even after the
function returns: >
:function Foo(arg)
: let i = 3
: return {x -> x + i - a:arg}
:endfunction
:let Bar = Foo(4)
:echo Bar(6)
< 5
See also |:func-closure|. Lambda and closure support can be checked with: >
if has('lambda')
Examples for using a lambda expression with |sort()|, |map()| and |filter()|: >
:echo map([1, 2, 3], {idx, val -> val + 1})
@@ -1245,6 +1260,12 @@ The lambda expression is also useful for Channel, Job and timer: >
Note how execute() is used to execute an Ex command. That's ugly though.
Lambda expressions have internal names like '<lambda>42'. If you get an error
for a lambda expression, you can find what it is with the following command: >
:function {'<lambda>42'}
See also: |numbered-function|
==============================================================================
3. Internal variable *internal-variables* *E461*
@@ -2052,8 +2073,10 @@ foldlevel({lnum}) Number fold level at {lnum}
foldtext() String line displayed for closed fold
foldtextresult({lnum}) String text for closed fold at {lnum}
foreground() Number bring the Vim window to the foreground
function({name} [, {arglist}] [, {dict}])
funcref({name} [, {arglist}] [, {dict}])
Funcref reference to function {name}
function({name} [, {arglist}] [, {dict}])
Funcref named reference to function {name}
garbagecollect([{atexit}]) none free memory, breaking cyclic references
get({list}, {idx} [, {def}]) any get item {idx} from {list} or {def}
get({dict}, {key} [, {def}]) any get item {key} from {dict} or {def}
@@ -3831,6 +3854,15 @@ foreground() Move the Vim window to the foreground. Useful when sent from
{only in the Win32, Athena, Motif and GTK GUI versions and the
Win32 console version}
*funcref()*
funcref({name} [, {arglist}] [, {dict}])
Just like |function()|, but the returned Funcref will lookup
the function by reference, not by name. This matters when the
function {name} is redefined later.
Unlike |function()|, {name} must be an existing user function.
Also for autoloaded functions. {name} cannot be a builtin
function.
*function()* *E700* *E922* *E923*
function({name} [, {arglist}] [, {dict}])
@@ -3838,12 +3870,16 @@ function({name} [, {arglist}] [, {dict}])
{name} can be the name of a user defined function or an
internal function.
{name} can also be a Funcref, also a partial. When it is a
{name} can also be a Funcref or a partial. When it is a
partial the dict stored in it will be used and the {dict}
argument is not allowed. E.g.: >
let FuncWithArg = function(dict.Func, [arg])
let Broken = function(dict.Func, [arg], dict)
<
When using the Funcref the function will be found by {name},
also when it was redefined later. Use |funcref()| to keep the
same function.
When {arglist} or {dict} is present this creates a partial.
That means the argument list and/or the dictionary is stored in
the Funcref and will be used when the Funcref is called.
@@ -6172,6 +6208,7 @@ screenrow() *screenrow()*
The result is a Number, which is the current screen row of the
cursor. The top line has number one.
This function is mainly used for testing.
Alternatively you can use |winline()|.
Note: Same restrictions as with |screencol()|.
@@ -7494,7 +7531,8 @@ test_null_string() *test_null_string()*
test_settime({expr}) *test_settime()*
Set the time Vim uses internally. Currently only used for
timestamps in the history, as they are used in viminfo.
timestamps in the history, as they are used in viminfo, and
for undo.
{expr} must evaluate to a number. When the value is zero the
normal behavior is restored.
@@ -8019,6 +8057,7 @@ insert_expand Compiled with support for CTRL-X expansion commands in
Insert mode.
jumplist Compiled with |jumplist| support.
keymap Compiled with 'keymap' support.
lambda Compiled with |lambda| support.
langmap Compiled with 'langmap' support.
libcall Compiled with |libcall()| support.
linebreak Compiled with 'linebreak', 'breakat', 'showbreak' and
@@ -8198,7 +8237,7 @@ last defined. Example: >
See |:verbose-cmd| for more information.
*E124* *E125* *E853* *E884*
:fu[nction][!] {name}([arguments]) [range] [abort] [dict]
:fu[nction][!] {name}([arguments]) [range] [abort] [dict] [closure]
Define a new function by the name {name}. The name
must be made of alphanumeric characters and '_', and
must start with a capital or "s:" (see above). Note
@@ -8241,6 +8280,28 @@ See |:verbose-cmd| for more information.
be invoked through an entry in a |Dictionary|. The
local variable "self" will then be set to the
dictionary. See |Dictionary-function|.
*:func-closure* *E932*
When the [closure] argument is added, the function
can access variables and arguments from the outer
scope. This is usually called a closure. In this
example Bar() uses "x" from the scope of Foo(). It
remains referenced even after Foo() returns: >
:function! Foo()
: let x = 0
: function! Bar() closure
: let x += 1
: return x
: endfunction
: return function('Bar')
:endfunction
:let F = Foo()
:echo F()
< 1 >
:echo F()
< 2 >
:echo F()
< 3
*function-search-undo*
The last used search pattern and the redo command "."
@@ -8252,7 +8313,7 @@ See |:verbose-cmd| for more information.
:endf[unction] The end of a function definition. Must be on a line
by its own, without other commands.
*:delf* *:delfunction* *E130* *E131*
*:delf* *:delfunction* *E130* *E131* *E933*
:delf[unction] {name} Delete function {name}.
{name} can also be a |Dictionary| entry that is a
|Funcref|: >

View File

@@ -2,7 +2,7 @@
" You can also use this as a start for your own set of menus.
"
" Maintainer: Bram Moolenaar <Bram@vim.org>
" Last Change: 2014 May 22
" Last Change: 2016 Jul 27
" Note that ":an" (short for ":anoremenu") is often used to make a menu work
" in all modes and avoid side effects from mappings defined by the user.

View File

@@ -49,7 +49,7 @@ Building with Visual Studio (VS 98, VS .NET, VS .NET 2003, VS 2005, VS 2008,
VS2010, VS2012, VS2013 and VS2015) is straightforward. (These instructions
should also work for VS 4 and VS 5.)
Using VS C++ 2008 Express is recommended, the binaries build with that run on
Using VS C++ 2008 Express is recommended, the binaries built with that run on
nearly all platforms. Binaries from later versions may not run on Windows 95
or XP.

View File

@@ -2042,7 +2042,7 @@ test1 \
test11 test12 test13 test14 test15 test16 test17 test18 test19 \
test20 test21 test22 test23 test24 test25 test26 test27 test28 test29 \
test30 test31 test32 test33 test34 test36 test37 test38 test39 \
test40 test41 test42 test43 test44 test45 test46 test47 test48 test49 \
test40 test41 test42 test43 test44 test45 test46 test48 test49 \
test50 test51 test52 test53 test54 test55 test56 test57 test58 test59 \
test60 test62 test63 test64 test65 test66 test67 test68 test69 \
test70 test71 test72 test73 test74 test75 test76 test77 test78 test79 \
@@ -2064,6 +2064,7 @@ test_arglist \
test_cscope \
test_cursor_func \
test_delete \
test_diffmode \
test_digraph \
test_ex_undo \
test_execute_func \

View File

@@ -1124,15 +1124,18 @@ set_callback(
if (callback != NULL && *callback != NUL)
{
if (partial != NULL)
*cbp = partial->pt_name;
*cbp = partial_name(partial);
else
{
*cbp = vim_strsave(callback);
func_ref(*cbp);
}
}
else
*cbp = NULL;
*pp = partial;
if (*pp != NULL)
++(*pp)->pt_refcount;
if (partial != NULL)
++partial->pt_refcount;
}
/*
@@ -1272,10 +1275,17 @@ channel_set_req_callback(
if (item != NULL)
{
item->cq_callback = vim_strsave(callback);
item->cq_partial = partial;
if (partial != NULL)
{
++partial->pt_refcount;
item->cq_callback = callback;
}
else
{
item->cq_callback = vim_strsave(callback);
func_ref(item->cq_callback);
}
item->cq_seq_nr = id;
item->cq_prev = head->cq_prev;
head->cq_prev = item;
@@ -3919,14 +3929,24 @@ free_job_options(jobopt_T *opt)
{
if (opt->jo_partial != NULL)
partial_unref(opt->jo_partial);
else if (opt->jo_callback != NULL)
func_unref(opt->jo_callback);
if (opt->jo_out_partial != NULL)
partial_unref(opt->jo_out_partial);
else if (opt->jo_out_cb != NULL)
func_unref(opt->jo_out_cb);
if (opt->jo_err_partial != NULL)
partial_unref(opt->jo_err_partial);
else if (opt->jo_err_cb != NULL)
func_unref(opt->jo_err_cb);
if (opt->jo_close_partial != NULL)
partial_unref(opt->jo_close_partial);
else if (opt->jo_close_cb != NULL)
func_unref(opt->jo_close_cb);
if (opt->jo_exit_partial != NULL)
partial_unref(opt->jo_exit_partial);
else if (opt->jo_exit_cb != NULL)
func_unref(opt->jo_exit_cb);
}
/*
@@ -4465,10 +4485,17 @@ job_set_options(job_T *job, jobopt_T *opt)
}
else
{
job->jv_exit_cb = vim_strsave(opt->jo_exit_cb);
job->jv_exit_partial = opt->jo_exit_partial;
if (job->jv_exit_partial != NULL)
{
job->jv_exit_cb = opt->jo_exit_cb;
++job->jv_exit_partial->pt_refcount;
}
else
{
job->jv_exit_cb = vim_strsave(opt->jo_exit_cb);
func_ref(job->jv_exit_cb);
}
}
}
}

View File

@@ -135,7 +135,7 @@ diff_buf_add(buf_T *buf)
return;
}
EMSGN(_("E96: Can not diff more than %ld buffers"), DB_COUNT);
EMSGN(_("E96: Cannot diff more than %ld buffers"), DB_COUNT);
}
/*

View File

@@ -2460,4 +2460,3 @@ keymap_unload(void)
}
#endif /* FEAT_KEYMAP */

View File

@@ -237,8 +237,8 @@ static int get_env_tv(char_u **arg, typval_T *rettv, int evaluate);
static int get_env_len(char_u **arg);
static char_u * make_expanded_name(char_u *in_start, char_u *expr_start, char_u *expr_end, char_u *in_end);
static void check_vars(char_u *name, int len);
static typval_T *alloc_string_tv(char_u *string);
static hashtab_T *find_var_ht(char_u *name, char_u **varname);
static void delete_var(hashtab_T *ht, hashitem_T *hi);
static void list_one_var(dictitem_T *v, char_u *prefix, int *first);
static void list_one_var_a(char_u *prefix, char_u *name, int type, char_u *string, int *first);
@@ -2837,7 +2837,9 @@ do_unlet(char_u *name, int forceit)
}
}
hi = hash_find(ht, varname);
if (!HASHITEM_EMPTY(hi))
if (HASHITEM_EMPTY(hi))
hi = find_hi_in_scoped_ht(name, &varname, &ht);
if (hi != NULL && !HASHITEM_EMPTY(hi))
{
di = HI2DI(hi);
if (var_check_fixed(di->di_flags, name, FALSE)
@@ -4332,6 +4334,9 @@ eval7(
{
partial_T *partial;
if (!evaluate)
check_vars(s, len);
/* If "s" is the name of a variable of type VAR_FUNC
* use its contents. */
s = deref_func_name(s, &len, &partial, !evaluate);
@@ -4363,7 +4368,10 @@ eval7(
else if (evaluate)
ret = get_var_tv(s, len, rettv, NULL, TRUE, FALSE);
else
{
check_vars(s, len);
ret = OK;
}
}
vim_free(alias);
}
@@ -5003,6 +5011,17 @@ get_lit_string_tv(char_u **arg, typval_T *rettv, int evaluate)
return OK;
}
/*
* Return the function name of the partial.
*/
char_u *
partial_name(partial_T *pt)
{
if (pt->pt_name != NULL)
return pt->pt_name;
return pt->pt_func->uf_name;
}
static void
partial_free(partial_T *pt)
{
@@ -5012,8 +5031,13 @@ partial_free(partial_T *pt)
clear_tv(&pt->pt_argv[i]);
vim_free(pt->pt_argv);
dict_unref(pt->pt_dict);
func_unref(pt->pt_name);
vim_free(pt->pt_name);
if (pt->pt_name != NULL)
{
func_unref(pt->pt_name);
vim_free(pt->pt_name);
}
else
func_ptr_unref(pt->pt_func);
vim_free(pt);
}
@@ -5043,11 +5067,11 @@ func_equal(
/* empty and NULL function name considered the same */
s1 = tv1->v_type == VAR_FUNC ? tv1->vval.v_string
: tv1->vval.v_partial->pt_name;
: partial_name(tv1->vval.v_partial);
if (s1 != NULL && *s1 == NUL)
s1 = NULL;
s2 = tv2->v_type == VAR_FUNC ? tv2->vval.v_string
: tv2->vval.v_partial->pt_name;
: partial_name(tv2->vval.v_partial);
if (s2 != NULL && *s2 == NUL)
s2 = NULL;
if (s1 == NULL || s2 == NULL)
@@ -5540,6 +5564,10 @@ set_ref_in_item(
}
}
}
else if (tv->v_type == VAR_FUNC)
{
abort = set_ref_in_func(tv->vval.v_string, NULL, copyID);
}
else if (tv->v_type == VAR_PARTIAL)
{
partial_T *pt = tv->vval.v_partial;
@@ -5549,6 +5577,8 @@ set_ref_in_item(
*/
if (pt != NULL)
{
abort = set_ref_in_func(pt->pt_name, pt->pt_func, copyID);
if (pt->pt_dict != NULL)
{
typval_T dtv;
@@ -5721,7 +5751,7 @@ echo_string_core(
{
partial_T *pt = tv->vval.v_partial;
char_u *fname = string_quote(pt == NULL ? NULL
: pt->pt_name, FALSE);
: partial_name(pt), FALSE);
garray_T ga;
int i;
char_u *tf;
@@ -6790,6 +6820,34 @@ get_var_tv(
return ret;
}
/*
* Check if variable "name[len]" is a local variable or an argument.
* If so, "*eval_lavars_used" is set to TRUE.
*/
static void
check_vars(char_u *name, int len)
{
int cc;
char_u *varname;
hashtab_T *ht;
if (eval_lavars_used == NULL)
return;
/* truncate the name, so that we can use strcmp() */
cc = name[len];
name[len] = NUL;
ht = find_var_ht(name, &varname);
if (ht == get_funccal_local_ht() || ht == get_funccal_args_ht())
{
if (find_var(name, NULL, TRUE) != NULL)
*eval_lavars_used = TRUE;
}
name[len] = cc;
}
/*
* Handle expr[expr], expr[expr:expr] subscript and .name lookup.
* Also handle function call with Funcref variable: func(expr)
@@ -6829,7 +6887,7 @@ handle_subscript(
if (functv.v_type == VAR_PARTIAL)
{
pt = functv.vval.v_partial;
s = pt->pt_name;
s = partial_name(pt);
}
else
s = functv.vval.v_string;
@@ -7274,13 +7332,20 @@ find_var(char_u *name, hashtab_T **htp, int no_autoload)
{
char_u *varname;
hashtab_T *ht;
dictitem_T *ret = NULL;
ht = find_var_ht(name, &varname);
if (htp != NULL)
*htp = ht;
if (ht == NULL)
return NULL;
return find_var_in_ht(ht, *name, varname, no_autoload || htp != NULL);
ret = find_var_in_ht(ht, *name, varname, no_autoload || htp != NULL);
if (ret != NULL)
return ret;
/* Search in parent scope for lambda */
return find_var_in_scoped_ht(name, varname ? &varname : NULL,
no_autoload || htp != NULL);
}
/*
@@ -7341,7 +7406,7 @@ find_var_in_ht(
* Return NULL if the name is not valid.
* Set "varname" to the start of name without ':'.
*/
static hashtab_T *
hashtab_T *
find_var_ht(char_u *name, char_u **varname)
{
hashitem_T *hi;
@@ -7617,6 +7682,10 @@ set_var(
}
v = find_var_in_ht(ht, 0, varname, TRUE);
/* Search in parent scope which is possible to reference from lambda */
if (v == NULL)
v = find_var_in_scoped_ht(name, varname ? &varname : NULL, TRUE);
if ((tv->v_type == VAR_FUNC || tv->v_type == VAR_PARTIAL)
&& var_check_func_name(name, v == NULL))
return;
@@ -7760,7 +7829,7 @@ var_check_func_name(
/* Don't allow hiding a function. When "v" is not NULL we might be
* assigning another function to the same var, the type is checked
* below. */
if (new_var && function_exists(name))
if (new_var && function_exists(name, FALSE))
{
EMSG2(_("E705: Variable name conflicts with existing function: %s"),
name);
@@ -9972,7 +10041,7 @@ filter_map_one(typval_T *tv, typval_T *expr, int map, int *remp)
{
partial_T *partial = expr->vval.v_partial;
s = partial->pt_name;
s = partial_name(partial);
if (call_func(s, (int)STRLEN(s), &rettv, 2, argv, NULL,
0L, 0L, &dummy, TRUE, partial, NULL) == FAIL)
goto theend;

View File

@@ -148,6 +148,7 @@ static void f_foldlevel(typval_T *argvars, typval_T *rettv);
static void f_foldtext(typval_T *argvars, typval_T *rettv);
static void f_foldtextresult(typval_T *argvars, typval_T *rettv);
static void f_foreground(typval_T *argvars, typval_T *rettv);
static void f_funcref(typval_T *argvars, typval_T *rettv);
static void f_function(typval_T *argvars, typval_T *rettv);
static void f_garbagecollect(typval_T *argvars, typval_T *rettv);
static void f_get(typval_T *argvars, typval_T *rettv);
@@ -563,6 +564,7 @@ static struct fst
{"foldtext", 0, 0, f_foldtext},
{"foldtextresult", 1, 1, f_foldtextresult},
{"foreground", 0, 0, f_foreground},
{"funcref", 1, 3, f_funcref},
{"function", 1, 3, f_function},
{"garbagecollect", 0, 1, f_garbagecollect},
{"get", 2, 3, f_get},
@@ -1723,7 +1725,7 @@ f_call(typval_T *argvars, typval_T *rettv)
else if (argvars[0].v_type == VAR_PARTIAL)
{
partial = argvars[0].vval.v_partial;
func = partial->pt_name;
func = partial_name(partial);
}
else
func = get_tv_string(&argvars[0]);
@@ -2845,7 +2847,7 @@ f_exists(typval_T *argvars, typval_T *rettv)
}
else if (*p == '*') /* internal or user defined function */
{
n = function_exists(p + 1);
n = function_exists(p + 1, FALSE);
}
else if (*p == ':')
{
@@ -3543,16 +3545,14 @@ f_foreground(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
#endif
}
/*
* "function()" function
*/
static void
f_function(typval_T *argvars, typval_T *rettv)
common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
{
char_u *s;
char_u *name;
int use_string = FALSE;
partial_T *arg_pt = NULL;
char_u *trans_name = NULL;
if (argvars[0].v_type == VAR_FUNC)
{
@@ -3564,7 +3564,7 @@ f_function(typval_T *argvars, typval_T *rettv)
{
/* function(dict.MyFunc, [arg]) */
arg_pt = argvars[0].vval.v_partial;
s = arg_pt->pt_name;
s = partial_name(arg_pt);
}
else
{
@@ -3573,11 +3573,22 @@ f_function(typval_T *argvars, typval_T *rettv)
use_string = TRUE;
}
if (((use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL)
|| is_funcref))
{
name = s;
trans_name = trans_function_name(&name, FALSE,
TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
if (*name != NUL)
s = NULL;
}
if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s)))
EMSG2(_(e_invarg2), s);
/* Don't check an autoload name for existence here. */
else if (use_string && vim_strchr(s, AUTOLOAD_CHAR) == NULL
&& !function_exists(s))
else if (trans_name != NULL && (is_funcref
? find_func(trans_name) == NULL
: !translated_function_exists(trans_name)))
EMSG2(_("E700: Unknown function: %s"), s);
else
{
@@ -3625,7 +3636,7 @@ f_function(typval_T *argvars, typval_T *rettv)
{
EMSG(_("E922: expected a dict"));
vim_free(name);
return;
goto theend;
}
if (argvars[dict_idx].vval.v_dict == NULL)
dict_idx = 0;
@@ -3636,14 +3647,14 @@ f_function(typval_T *argvars, typval_T *rettv)
{
EMSG(_("E923: Second argument of function() must be a list or a dict"));
vim_free(name);
return;
goto theend;
}
list = argvars[arg_idx].vval.v_list;
if (list == NULL || list->lv_len == 0)
arg_idx = 0;
}
}
if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL)
if (dict_idx > 0 || arg_idx > 0 || arg_pt != NULL || is_funcref)
{
partial_T *pt = (partial_T *)alloc_clear(sizeof(partial_T));
@@ -3670,17 +3681,14 @@ f_function(typval_T *argvars, typval_T *rettv)
{
vim_free(pt);
vim_free(name);
return;
}
else
{
for (i = 0; i < arg_len; i++)
copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
if (lv_len > 0)
for (li = list->lv_first; li != NULL;
li = li->li_next)
copy_tv(&li->li_tv, &pt->pt_argv[i++]);
goto theend;
}
for (i = 0; i < arg_len; i++)
copy_tv(&arg_pt->pt_argv[i], &pt->pt_argv[i]);
if (lv_len > 0)
for (li = list->lv_first; li != NULL;
li = li->li_next)
copy_tv(&li->li_tv, &pt->pt_argv[i++]);
}
/* For "function(dict.func, [], dict)" and "func" is a partial
@@ -3702,8 +3710,23 @@ f_function(typval_T *argvars, typval_T *rettv)
}
pt->pt_refcount = 1;
pt->pt_name = name;
func_ref(pt->pt_name);
if (arg_pt != NULL && arg_pt->pt_func != NULL)
{
pt->pt_func = arg_pt->pt_func;
func_ptr_ref(pt->pt_func);
vim_free(name);
}
else if (is_funcref)
{
pt->pt_func = find_func(trans_name);
func_ptr_ref(pt->pt_func);
vim_free(name);
}
else
{
pt->pt_name = name;
func_ref(name);
}
}
rettv->v_type = VAR_PARTIAL;
rettv->vval.v_partial = pt;
@@ -3716,6 +3739,26 @@ f_function(typval_T *argvars, typval_T *rettv)
func_ref(name);
}
}
theend:
vim_free(trans_name);
}
/*
* "funcref()" function
*/
static void
f_funcref(typval_T *argvars, typval_T *rettv)
{
common_function(argvars, rettv, TRUE);
}
/*
* "function()" function
*/
static void
f_function(typval_T *argvars, typval_T *rettv)
{
common_function(argvars, rettv, FALSE);
}
/*
@@ -3781,14 +3824,20 @@ f_get(typval_T *argvars, typval_T *rettv)
if (pt != NULL)
{
char_u *what = get_tv_string(&argvars[1]);
char_u *n;
if (STRCMP(what, "func") == 0 || STRCMP(what, "name") == 0)
{
rettv->v_type = (*what == 'f' ? VAR_FUNC : VAR_STRING);
if (pt->pt_name == NULL)
n = partial_name(pt);
if (n == NULL)
rettv->vval.v_string = NULL;
else
rettv->vval.v_string = vim_strsave(pt->pt_name);
{
rettv->vval.v_string = vim_strsave(n);
if (rettv->v_type == VAR_FUNC)
func_ref(rettv->vval.v_string);
}
}
else if (STRCMP(what, "dict") == 0)
{
@@ -5205,6 +5254,7 @@ f_has(typval_T *argvars, typval_T *rettv)
#ifdef FEAT_KEYMAP
"keymap",
#endif
"lambda", /* always with FEAT_EVAL, since 7.4.2120 with closure */
#ifdef FEAT_LANGMAP
"langmap",
#endif
@@ -10103,7 +10153,7 @@ item_compare2(const void *s1, const void *s2)
if (partial == NULL)
func_name = sortinfo->item_compare_func;
else
func_name = partial->pt_name;
func_name = partial_name(partial);
/* Copy the values. This is needed to be able to set v_lock to VAR_FIXED
* in the copy without changing the original list items. */
@@ -11862,16 +11912,14 @@ get_callback(typval_T *arg, partial_T **pp)
{
*pp = arg->vval.v_partial;
++(*pp)->pt_refcount;
return (*pp)->pt_name;
return partial_name(*pp);
}
*pp = NULL;
if (arg->v_type == VAR_FUNC)
if (arg->v_type == VAR_FUNC || arg->v_type == VAR_STRING)
{
func_ref(arg->vval.v_string);
return arg->vval.v_string;
}
if (arg->v_type == VAR_STRING)
return arg->vval.v_string;
if (arg->v_type == VAR_NUMBER && arg->vval.v_number == 0)
return (char_u *)"";
EMSG(_("E921: Invalid callback argument"));
@@ -11930,7 +11978,11 @@ f_timer_start(typval_T *argvars, typval_T *rettv)
}
else
{
timer->tr_callback = vim_strsave(callback);
if (timer->tr_partial == NULL)
timer->tr_callback = vim_strsave(callback);
else
/* pointer into the partial */
timer->tr_callback = callback;
rettv->vval.v_number = timer->tr_id;
}
}

View File

@@ -4091,7 +4091,12 @@ do_ecmd(
u_sync(FALSE);
if (u_savecommon(0, curbuf->b_ml.ml_line_count + 1, 0, TRUE)
== FAIL)
{
#ifdef FEAT_AUTOCMD
vim_free(new_name);
#endif
goto theend;
}
u_unchanged(curbuf);
buf_freeall(curbuf, BFA_KEEP_UNDO);

View File

@@ -1265,12 +1265,35 @@ set_ref_in_timer(int copyID)
for (timer = first_timer; timer != NULL; timer = timer->tr_next)
{
tv.v_type = VAR_PARTIAL;
tv.vval.v_partial = timer->tr_partial;
if (timer->tr_partial != NULL)
{
tv.v_type = VAR_PARTIAL;
tv.vval.v_partial = timer->tr_partial;
}
else
{
tv.v_type = VAR_FUNC;
tv.vval.v_string = timer->tr_callback;
}
abort = abort || set_ref_in_item(&tv, copyID, NULL, NULL);
}
return abort;
}
# if defined(EXITFREE) || defined(PROTO)
void
timer_free_all()
{
timer_T *timer;
while (first_timer != NULL)
{
timer = first_timer;
remove_timer(timer);
free_timer(timer);
}
}
# endif
# endif
#if defined(FEAT_SYN_HL) && defined(FEAT_RELTIME) && defined(FEAT_FLOAT)

View File

@@ -1954,7 +1954,7 @@ do_one_cmd(
#endif
continue;
}
if (!checkforcmd(&ea.cmd, "noswapfile", 6))
if (!checkforcmd(&ea.cmd, "noswapfile", 3))
break;
cmdmod.noswapfile = TRUE;
continue;

View File

@@ -1658,6 +1658,9 @@ EXTERN time_T time_for_testing INIT(= 0);
/* Abort conversion to string after a recursion error. */
EXTERN int did_echo_string_emsg INIT(= FALSE);
/* Used for checking if local variables or arguments used in a lambda. */
EXTERN int *eval_lavars_used INIT(= NULL);
#endif
/*

View File

@@ -3134,7 +3134,7 @@ vim_to_mzscheme_impl(typval_T *vim_value, int depth, Scheme_Hash_Table *visited)
/* FIXME: func_ref() and func_unref() are needed. */
/* TODO: Support pt_dict and pt_argv. */
funcname = scheme_make_byte_string(
(char *)vim_value->vval.v_partial->pt_name);
(char *)partial_name(vim_value->vval.v_partial));
MZ_GC_CHECK();
result = scheme_make_closed_prim_w_arity(vim_funcref, funcname,
(const char *)BYTE_STRING_VALUE(funcname), 0, -1);

View File

@@ -2863,7 +2863,6 @@ FunctionNew(PyTypeObject *subtype, char_u *name, int argc, typval_T *argv,
return NULL;
}
self->name = vim_strsave(name);
func_ref(self->name);
}
else
if ((self->name = get_expanded_name(name,
@@ -2875,6 +2874,7 @@ FunctionNew(PyTypeObject *subtype, char_u *name, int argc, typval_T *argv,
return NULL;
}
func_ref(self->name);
self->argc = argc;
self->argv = argv;
self->self = selfdict;
@@ -6310,7 +6310,7 @@ ConvertToPyObject(typval_T *tv)
if (tv->vval.v_partial->pt_dict != NULL)
tv->vval.v_partial->pt_dict->dv_refcount++;
return NEW_FUNCTION(tv->vval.v_partial == NULL
? (char_u *)"" : tv->vval.v_partial->pt_name,
? (char_u *)"" : partial_name(tv->vval.v_partial),
tv->vval.v_partial->pt_argc, argv,
tv->vval.v_partial->pt_dict,
tv->vval.v_partial->pt_auto);

View File

@@ -304,7 +304,7 @@ trunc_string(
if (len + n > room || half == 0)
break;
len += n;
i = half;
i = (int)half;
}
}
else

View File

@@ -1217,11 +1217,18 @@ free_all_mem(void)
if (delete_first_msg() == FAIL)
break;
# ifdef FEAT_JOB_CHANNEL
channel_free_all();
# endif
#ifdef FEAT_TIMERS
timer_free_all();
#endif
# ifdef FEAT_EVAL
/* must be after channel_free_all() with unrefs partials */
eval_clear();
# endif
# ifdef FEAT_JOB_CHANNEL
channel_free_all();
/* must be after eval_clear() with unrefs jobs */
job_free_all();
# endif

View File

@@ -40,6 +40,7 @@ char_u *get_user_var_name(expand_T *xp, int idx);
int eval0(char_u *arg, typval_T *rettv, char_u **nextcmd, int evaluate);
int eval1(char_u **arg, typval_T *rettv, int evaluate);
int get_option_tv(char_u **arg, typval_T *rettv, int evaluate);
char_u *partial_name(partial_T *pt);
void partial_unref(partial_T *pt);
int tv_equal(typval_T *tv1, typval_T *tv2, int ic, int recursive);
int get_copyID(void);
@@ -87,6 +88,7 @@ char_u *get_tv_string_chk(typval_T *varp);
char_u *get_tv_string_buf_chk(typval_T *varp, char_u *buf);
dictitem_T *find_var(char_u *name, hashtab_T **htp, int no_autoload);
dictitem_T *find_var_in_ht(hashtab_T *ht, int htname, char_u *varname, int no_autoload);
hashtab_T *find_var_ht(char_u *name, char_u **varname);
char_u *get_var_value(char_u *name);
void new_script_vars(scid_T id);
void init_var_dict(dict_T *dict, dictitem_T *dict_var, int scope);

View File

@@ -18,11 +18,12 @@ float_T profile_float(proftime_T *tm);
void profile_setlimit(long msec, proftime_T *tm);
int profile_passed_limit(proftime_T *tm);
void profile_zero(proftime_T *tm);
timer_T *create_timer(long msec, int repeats);
timer_T *create_timer(long msec, int repeat);
long check_due_timer(void);
timer_T *find_timer(int id);
void stop_timer(timer_T *timer);
int set_ref_in_timer(int copyID);
void timer_free_all(void);
void profile_divide(proftime_T *tm, int count, proftime_T *tm2);
void profile_add(proftime_T *tm, proftime_T *tm2);
void profile_self(proftime_T *self, proftime_T *total, proftime_T *children);

View File

@@ -3,13 +3,15 @@ void func_init(void);
int get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate);
char_u *deref_func_name(char_u *name, int *lenp, partial_T **partialp, int no_autoload);
int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate, partial_T *partial, dict_T *selfdict);
ufunc_T *find_func(char_u *name);
void free_all_functions(void);
int func_call(char_u *name, typval_T *args, partial_T *partial, dict_T *selfdict, typval_T *rettv);
int call_func(char_u *funcname, int len, typval_T *rettv, int argcount_in, typval_T *argvars_in, int (*argv_func)(int, typval_T *, int), linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate, partial_T *partial, dict_T *selfdict_in);
char_u *trans_function_name(char_u **pp, int skip, int flags, funcdict_T *fdp, partial_T **partial);
void ex_function(exarg_T *eap);
int eval_fname_script(char_u *p);
int translated_function_exists(char_u *name);
int function_exists(char_u *name);
int function_exists(char_u *name, int no_deref);
char_u *get_expanded_name(char_u *name, int check);
void func_dump_profile(FILE *fd);
void prof_child_enter(proftime_T *tm);
@@ -17,7 +19,9 @@ void prof_child_exit(proftime_T *tm);
char_u *get_user_func_name(expand_T *xp, int idx);
void ex_delfunction(exarg_T *eap);
void func_unref(char_u *name);
void func_ptr_unref(ufunc_T *fp);
void func_ref(char_u *name);
void func_ptr_ref(ufunc_T *fp);
void ex_return(exarg_T *eap);
void ex_call(exarg_T *eap);
int do_return(exarg_T *eap, int reanimate, int is_cmd, void *rettv);
@@ -46,7 +50,10 @@ void *clear_current_funccal(void);
void restore_current_funccal(void *f);
void list_func_vars(int *first);
dict_T *get_current_funccal_dict(hashtab_T *ht);
hashitem_T *find_hi_in_scoped_ht(char_u *name, char_u **varname, hashtab_T **pht);
dictitem_T *find_var_in_scoped_ht(char_u *name, char_u **varname, int no_autoload);
int set_ref_in_previous_funccal(int copyID);
int set_ref_in_call_stack(int copyID);
int set_ref_in_func_args(int copyID);
int set_ref_in_func(char_u *name, ufunc_T *fp_in, int copyID);
/* vim: set ft=c : */

View File

@@ -7499,7 +7499,7 @@ vim_regsub_both(
{
partial_T *partial = expr->vval.v_partial;
s = partial->pt_name;
s = partial_name(partial);
call_func(s, (int)STRLEN(s), &rettv,
1, argv, fill_submatch_list,
0L, 0L, &dummy, TRUE, partial, NULL);

View File

@@ -1295,10 +1295,100 @@ struct dictvar_S
dict_T *dv_used_prev; /* previous dict in used dicts list */
};
#if defined(FEAT_EVAL) || defined(PROTO)
typedef struct funccall_S funccall_T;
/*
* Structure to hold info for a user function.
*/
typedef struct
{
int uf_varargs; /* variable nr of arguments */
int uf_flags;
int uf_calls; /* nr of active calls */
garray_T uf_args; /* arguments */
garray_T uf_lines; /* function lines */
#ifdef FEAT_PROFILE
int uf_profiling; /* TRUE when func is being profiled */
/* profiling the function as a whole */
int uf_tm_count; /* nr of calls */
proftime_T uf_tm_total; /* time spent in function + children */
proftime_T uf_tm_self; /* time spent in function itself */
proftime_T uf_tm_children; /* time spent in children this call */
/* profiling the function per line */
int *uf_tml_count; /* nr of times line was executed */
proftime_T *uf_tml_total; /* time spent in a line + children */
proftime_T *uf_tml_self; /* time spent in a line itself */
proftime_T uf_tml_start; /* start time for current line */
proftime_T uf_tml_children; /* time spent in children for this line */
proftime_T uf_tml_wait; /* start wait time for current line */
int uf_tml_idx; /* index of line being timed; -1 if none */
int uf_tml_execed; /* line being timed was executed */
#endif
scid_T uf_script_ID; /* ID of script where function was defined,
used for s: variables */
int uf_refcount; /* for numbered function: reference count */
funccall_T *uf_scoped; /* l: local variables for closure */
char_u uf_name[1]; /* name of function (actually longer); can
start with <SNR>123_ (<SNR> is K_SPECIAL
KS_EXTRA KE_SNR) */
} ufunc_T;
#define MAX_FUNC_ARGS 20 /* maximum number of function arguments */
#define VAR_SHORT_LEN 20 /* short variable name length */
#define FIXVAR_CNT 12 /* number of fixed variables */
/* structure to hold info for a function that is currently being executed. */
struct funccall_S
{
ufunc_T *func; /* function being called */
int linenr; /* next line to be executed */
int returned; /* ":return" used */
struct /* fixed variables for arguments */
{
dictitem_T var; /* variable (without room for name) */
char_u room[VAR_SHORT_LEN]; /* room for the name */
} fixvar[FIXVAR_CNT];
dict_T l_vars; /* l: local function variables */
dictitem_T l_vars_var; /* variable for l: scope */
dict_T l_avars; /* a: argument variables */
dictitem_T l_avars_var; /* variable for a: scope */
list_T l_varlist; /* list for a:000 */
listitem_T l_listitems[MAX_FUNC_ARGS]; /* listitems for a:000 */
typval_T *rettv; /* return value */
linenr_T breakpoint; /* next line with breakpoint or zero */
int dbg_tick; /* debug_tick when breakpoint was set */
int level; /* top nesting level of executed function */
#ifdef FEAT_PROFILE
proftime_T prof_child; /* time spent in a child */
#endif
funccall_T *caller; /* calling function or NULL */
/* for closure */
int fc_refcount;
int fc_copyID; /* for garbage collection */
garray_T fc_funcs; /* list of ufunc_T* which refer this */
};
/*
* Struct used by trans_function_name()
*/
typedef struct
{
dict_T *fd_dict; /* Dictionary used */
char_u *fd_newkey; /* new key in "dict" in allocated memory */
dictitem_T *fd_di; /* Dictionary item used */
} funcdict_T;
#endif
struct partial_S
{
int pt_refcount; /* reference count */
char_u *pt_name; /* function name */
char_u *pt_name; /* function name; when NULL use
* pt_func->uf_name */
ufunc_T *pt_func; /* function pointer; when NULL lookup function
* with pt_name */
int pt_auto; /* when TRUE the partial was created for using
dict.member in handle_subscript() */
int pt_argc; /* number of arguments */

View File

@@ -43,7 +43,6 @@ SCRIPTS_ALL = \
test44.out \
test45.out \
test46.out \
test47.out \
test48.out \
test51.out \
test53.out \
@@ -168,6 +167,7 @@ NEW_TESTS = test_arglist.res \
test_channel.res \
test_cmdline.res \
test_cscope.res \
test_diffmode.res \
test_digraph.res \
test_farsi.res \
test_gn.res \

View File

@@ -80,14 +80,14 @@ test1.out: test1.in
@-/bin/sh -c "sleep .2 > /dev/null 2>&1 || sleep 1"
-$(RUN_VIM) $*.in
# For flaky tests retry one time.
@/bin/sh -c "if test -f test.out -a $* = test61; then \
if diff test.out $*.ok; \
then echo flaky test ok first time; \
else rm -rf $*.failed $(RM_ON_RUN); \
$(RUN_VIM) $*.in; \
fi \
fi"
# For flaky tests retry one time. No tests at the moment.
#@/bin/sh -c "if test -f test.out -a $* = test61; then \
# if diff test.out $*.ok; \
# then echo flaky test ok first time; \
# else rm -rf $*.failed $(RM_ON_RUN); \
# $(RUN_VIM) $*.in; \
# fi \
# fi"
# Check if the test.out file matches test.ok.
@/bin/sh -c "if test -f test.out; then \

View File

@@ -1,103 +0,0 @@
Tests for vertical splits and filler lines in diff mode
Also tests restoration of saved options by :diffoff.
STARTTEST
:so small.vim
:" Disable the title to avoid xterm keeping the wrong one.
:set notitle noicon
/^1
yG:new
pkdd:w! Xtest
ddGpkkrXoxxx:w! Xtest2
:file Nop
ggoyyyjjjozzzz
:set foldmethod=marker foldcolumn=4
:redir => nodiffsettings
:silent! :set diff? fdm? fdc? scb? crb? wrap?
:redir END
:vert diffsplit Xtest
:vert diffsplit Xtest2
:redir => diffsettings
:silent! :set diff? fdm? fdc? scb? crb? wrap?
:redir END
:let diff_fdm = &fdm
:let diff_fdc = &fdc
:" repeat entering diff mode here to see if this saves the wrong settings
:diffthis
:" jump to second window for a moment to have filler line appear at start of
:" first window
ggpgg:let one = winline()
j:let one = one . "-" . winline()
j:let one = one . "-" . winline()
j:let one = one . "-" . winline()
j:let one = one . "-" . winline()
j:let one = one . "-" . winline()
gg:let two = winline()
j:let two = two . "-" . winline()
j:let two = two . "-" . winline()
j:let two = two . "-" . winline()
j:let two = two . "-" . winline()
gg:let three = winline()
j:let three = three . "-" . winline()
j:let three = three . "-" . winline()
j:let three = three . "-" . winline()
j:let three = three . "-" . winline()
j:let three = three . "-" . winline()
j:let three = three . "-" . winline()
:call append("$", one)
:call append("$", two)
:call append("$", three)
:$-2,$w! test.out
:"
:" Test diffoff
:diffoff!
1
:let &diff = 1
:let &fdm = diff_fdm
:let &fdc = diff_fdc
4
:diffoff!
:$put =nodiffsettings
:$put =diffsettings
1
:redir => nd1
:silent! :set diff? fdm? fdc? scb? crb? wrap?
:redir END

:redir => nd2
:silent! :set diff? fdm? fdc? scb? crb? wrap?
:redir END

:redir => nd3
:silent! :set diff? fdm? fdc? scb? crb? wrap?
:redir END

:$put =nd1
:$put =nd2
:$put =nd3
:$-39,$w >> test.out
:"
:" Test that diffing shows correct filler lines
:windo :bw!
:enew
:put =range(4,10)
:1d _
:vnew
:put =range(1,10)
:1d _
:windo :diffthis
:wincmd h
:let w0=line('w0')
:enew
:put =w0
:.w >> test.out
:unlet! one two three nodiffsettings diffsettings diff_fdm diff_fdc nd1 nd2 nd3 w0
:qa!
ENDTEST
1 aa
2 bb
3 cc
4 dd
5 ee

View File

@@ -1,44 +0,0 @@
2-4-5-6-8-9
1-2-4-5-8
2-3-4-5-6-7-8
nodiff
foldmethod=marker
foldcolumn=4
noscrollbind
nocursorbind
wrap
diff
foldmethod=diff
foldcolumn=2
scrollbind
cursorbind
nowrap
nodiff
foldmethod=marker
foldcolumn=4
noscrollbind
nocursorbind
wrap
nodiff
foldmethod=marker
foldcolumn=4
noscrollbind
nocursorbind
wrap
nodiff
foldmethod=marker
foldcolumn=4
noscrollbind
nocursorbind
wrap
1

View File

@@ -1,5 +1,5 @@
Test for *sub-replace-special* and *sub-replace-expression* on substitue().
Test for submatch() on substitue().
Test for *sub-replace-special* and *sub-replace-expression* on substitute().
Test for submatch() on substitute().
Test for *:s%* on :substitute.
STARTTEST

View File

@@ -1320,7 +1320,7 @@ func Test_collapse_buffers()
1,$delete
call job_start('cat test_channel.vim', {'out_io': 'buffer', 'out_name': 'testout'})
call WaitFor('line("$") > g:linecount')
call assert_true(line('$') > g:linecount)
call assert_inrange(g:linecount + 1, g:linecount + 2, line('$'))
bwipe!
endfunc

View File

@@ -0,0 +1,204 @@
" Tests for diff mode
func Test_diff_fold_sync()
enew!
let l = range(50)
call setline(1, l)
diffthis
let winone = win_getid()
new
let l[25] = 'diff'
call setline(1, l)
diffthis
let wintwo = win_getid()
" line 15 is inside the closed fold
call assert_equal(19, foldclosedend(10))
call win_gotoid(winone)
call assert_equal(19, foldclosedend(10))
" open the fold
normal zv
call assert_equal(-1, foldclosedend(10))
" fold in other window must have opened too
call win_gotoid(wintwo)
call assert_equal(-1, foldclosedend(10))
" cursor position is in sync
normal 23G
call win_gotoid(winone)
call assert_equal(23, getcurpos()[1])
windo diffoff
close!
set nomodified
endfunc
func Test_vert_split()
" Disable the title to avoid xterm keeping the wrong one.
set notitle noicon
new
let l = ['1 aa', '2 bb', '3 cc', '4 dd', '5 ee']
call setline(1, l)
w! Xtest
normal dd
$
put
normal kkrXoxxx
w! Xtest2
file Nop
normal ggoyyyjjjozzzz
set foldmethod=marker foldcolumn=4
call assert_equal(0, &diff)
call assert_equal('marker', &foldmethod)
call assert_equal(4, &foldcolumn)
call assert_equal(0, &scrollbind)
call assert_equal(0, &cursorbind)
call assert_equal(1, &wrap)
vert diffsplit Xtest
vert diffsplit Xtest2
call assert_equal(1, &diff)
call assert_equal('diff', &foldmethod)
call assert_equal(2, &foldcolumn)
call assert_equal(1, &scrollbind)
call assert_equal(1, &cursorbind)
call assert_equal(0, &wrap)
let diff_fdm = &fdm
let diff_fdc = &fdc
" repeat entering diff mode here to see if this saves the wrong settings
diffthis
" jump to second window for a moment to have filler line appear at start of
" first window
wincmd w
normal gg
wincmd p
normal gg
call assert_equal(2, winline())
normal j
call assert_equal(4, winline())
normal j
call assert_equal(5, winline())
normal j
call assert_equal(6, winline())
normal j
call assert_equal(8, winline())
normal j
call assert_equal(9, winline())
wincmd w
normal gg
call assert_equal(1, winline())
normal j
call assert_equal(2, winline())
normal j
call assert_equal(4, winline())
normal j
call assert_equal(5, winline())
normal j
call assert_equal(8, winline())
wincmd w
normal gg
call assert_equal(2, winline())
normal j
call assert_equal(3, winline())
normal j
call assert_equal(4, winline())
normal j
call assert_equal(5, winline())
normal j
call assert_equal(6, winline())
normal j
call assert_equal(7, winline())
normal j
call assert_equal(8, winline())
" Test diffoff
diffoff!
1wincmd 2
let &diff = 1
let &fdm = diff_fdm
let &fdc = diff_fdc
4wincmd w
diffoff!
1wincmd w
call assert_equal(0, &diff)
call assert_equal('marker', &foldmethod)
call assert_equal(4, &foldcolumn)
call assert_equal(0, &scrollbind)
call assert_equal(0, &cursorbind)
call assert_equal(1, &wrap)
wincmd w
call assert_equal(0, &diff)
call assert_equal('marker', &foldmethod)
call assert_equal(4, &foldcolumn)
call assert_equal(0, &scrollbind)
call assert_equal(0, &cursorbind)
call assert_equal(1, &wrap)
wincmd w
call assert_equal(0, &diff)
call assert_equal('marker', &foldmethod)
call assert_equal(4, &foldcolumn)
call assert_equal(0, &scrollbind)
call assert_equal(0, &cursorbind)
call assert_equal(1, &wrap)
call delete('Xtest')
call delete('Xtest2')
windo bw!
endfunc
func Test_filler_lines()
" Test that diffing shows correct filler lines
enew!
put =range(4,10)
1d _
vnew
put =range(1,10)
1d _
windo diffthis
wincmd h
call assert_equal(1, line('w0'))
unlet! diff_fdm diff_fdc
windo diffoff
bwipe!
enew!
endfunc
func Test_diffget_diffput()
enew!
let l = range(50)
call setline(1, l)
call assert_fails('diffget', 'E99:')
diffthis
call assert_fails('diffget', 'E100:')
new
let l[10] = 'one'
let l[20] = 'two'
let l[30] = 'three'
let l[40] = 'four'
call setline(1, l)
diffthis
call assert_equal('one', getline(11))
11diffget
call assert_equal('10', getline(11))
21diffput
wincmd w
call assert_equal('two', getline(21))
normal 31Gdo
call assert_equal('three', getline(31))
call assert_equal('40', getline(41))
normal 41Gdp
wincmd w
call assert_equal('40', getline(41))
new
diffthis
call assert_fails('diffget', 'E101:')
windo diffoff
bwipe!
bwipe!
enew!
endfunc

View File

@@ -172,3 +172,25 @@ func Test_substitute_expr_arg()
call assert_fails("call substitute('xxx', '.', {m -> string(extend(m, ['x']))}, '')", 'E742:')
call assert_fails("call substitute('xxx', '.', {m -> string(remove(m, 1))}, '')", 'E742:')
endfunc
func Test_function_with_funcref()
let s:f = function('type')
let s:fref = function(s:f)
call assert_equal(v:t_string, s:fref('x'))
call assert_fails("call function('s:f')", 'E700:')
endfunc
func Test_funcref()
func! One()
return 1
endfunc
let OneByName = function('One')
let OneByRef = funcref('One')
func! One()
return 2
endfunc
call assert_equal(2, OneByName())
call assert_equal(1, OneByRef())
let OneByRef = funcref('One')
call assert_equal(2, OneByRef())
endfunc

View File

@@ -1,3 +1,9 @@
" Test for lambda and closure
function! Test_lambda_feature()
call assert_equal(1, has('lambda'))
endfunction
function! Test_lambda_with_filter()
let s:x = 2
call assert_equal([2, 3], filter([1, 2, 3], {i, v -> v >= s:x}))
@@ -21,7 +27,7 @@ function! Test_lambda_with_timer()
let s:timer_id = 0
function! s:Foo()
"let n = 0
let s:timer_id = timer_start(50, {-> execute("let s:n += 1 | echo s:n")}, {"repeat": -1})
let s:timer_id = timer_start(50, {-> execute("let s:n += 1 | echo s:n", "")}, {"repeat": -1})
endfunction
call s:Foo()
@@ -51,3 +57,216 @@ func Test_not_lamda()
let x = {'>' : 'foo'}
call assert_equal('foo', x['>'])
endfunc
function! Test_lambda_capture_by_reference()
let v = 1
let l:F = {x -> x + v}
let v = 2
call assert_equal(12, l:F(10))
endfunction
function! Test_lambda_side_effect()
function! s:update_and_return(arr)
let a:arr[1] = 5
return a:arr
endfunction
function! s:foo(arr)
return {-> s:update_and_return(a:arr)}
endfunction
let arr = [3,2,1]
call assert_equal([3, 5, 1], s:foo(arr)())
endfunction
function! Test_lambda_refer_local_variable_from_other_scope()
function! s:foo(X)
return a:X() " refer l:x in s:bar()
endfunction
function! s:bar()
let x = 123
return s:foo({-> x})
endfunction
call assert_equal(123, s:bar())
endfunction
function! Test_lambda_do_not_share_local_variable()
function! s:define_funcs()
let l:One = {-> split(execute("let a = 'abc' | echo a"))[0]}
let l:Two = {-> exists("a") ? a : "no"}
return [l:One, l:Two]
endfunction
let l:F = s:define_funcs()
call assert_equal('no', l:F[1]())
call assert_equal('abc', l:F[0]())
call assert_equal('no', l:F[1]())
endfunction
function! Test_lambda_closure_counter()
function! s:foo()
let x = 0
return {-> [execute("let x += 1"), x][-1]}
endfunction
let l:F = s:foo()
call test_garbagecollect_now()
call assert_equal(1, l:F())
call assert_equal(2, l:F())
call assert_equal(3, l:F())
call assert_equal(4, l:F())
endfunction
function! Test_lambda_with_a_var()
function! s:foo()
let x = 2
return {... -> a:000 + [x]}
endfunction
function! s:bar()
return s:foo()(1)
endfunction
call assert_equal([1, 2], s:bar())
endfunction
function! Test_lambda_call_lambda_from_lambda()
function! s:foo(x)
let l:F1 = {-> {-> a:x}}
return {-> l:F1()}
endfunction
let l:F = s:foo(1)
call assert_equal(1, l:F()())
endfunction
function! Test_lambda_delfunc()
function! s:gen()
let pl = l:
let l:Foo = {-> get(pl, "Foo", get(pl, "Bar", {-> 0}))}
let l:Bar = l:Foo
delfunction l:Foo
return l:Bar
endfunction
let l:F = s:gen()
call assert_fails(':call l:F()', 'E933:')
endfunction
function! Test_lambda_scope()
function! s:NewCounter()
let c = 0
return {-> [execute('let c += 1'), c][-1]}
endfunction
function! s:NewCounter2()
return {-> [execute('let c += 100'), c][-1]}
endfunction
let l:C = s:NewCounter()
let l:D = s:NewCounter2()
call assert_equal(1, l:C())
call assert_fails(':call l:D()', 'E15:') " E121: then E15:
call assert_equal(2, l:C())
endfunction
function! Test_lambda_share_scope()
function! s:New()
let c = 0
let l:Inc0 = {-> [execute('let c += 1'), c][-1]}
let l:Dec0 = {-> [execute('let c -= 1'), c][-1]}
return [l:Inc0, l:Dec0]
endfunction
let [l:Inc, l:Dec] = s:New()
call assert_equal(1, l:Inc())
call assert_equal(2, l:Inc())
call assert_equal(1, l:Dec())
endfunction
function! Test_lambda_circular_reference()
function! s:Foo()
let d = {}
let d.f = {-> d}
return d.f
endfunction
call s:Foo()
call test_garbagecollect_now()
let i = 0 | while i < 10000 | call s:Foo() | let i+= 1 | endwhile
call test_garbagecollect_now()
endfunction
function! Test_lambda_combination()
call assert_equal(2, {x -> {x -> x}}(1)(2))
call assert_equal(10, {y -> {x -> x(y)(10)}({y -> y})}({z -> z}))
call assert_equal(5.0, {x -> {y -> x / y}}(10)(2.0))
call assert_equal(6, {x -> {y -> {z -> x + y + z}}}(1)(2)(3))
call assert_equal(6, {x -> {f -> f(x)}}(3)({x -> x * 2}))
call assert_equal(6, {f -> {x -> f(x)}}({x -> x * 2})(3))
" Z combinator
let Z = {f -> {x -> f({y -> x(x)(y)})}({x -> f({y -> x(x)(y)})})}
let Fact = {f -> {x -> x == 0 ? 1 : x * f(x - 1)}}
call assert_equal(120, Z(Fact)(5))
endfunction
function! Test_closure_counter()
function! s:foo()
let x = 0
function! s:bar() closure
let x += 1
return x
endfunction
return function('s:bar')
endfunction
let l:F = s:foo()
call test_garbagecollect_now()
call assert_equal(1, l:F())
call assert_equal(2, l:F())
call assert_equal(3, l:F())
call assert_equal(4, l:F())
endfunction
function! Test_closure_unlet()
function! s:foo()
let x = 1
function! s:bar() closure
unlet x
endfunction
call s:bar()
return l:
endfunction
call assert_false(has_key(s:foo(), 'x'))
call test_garbagecollect_now()
endfunction
function! LambdaFoo()
let x = 0
function! LambdaBar() closure
let x += 1
return x
endfunction
return function('LambdaBar')
endfunction
func Test_closure_refcount()
let g:Count = LambdaFoo()
call test_garbagecollect_now()
call assert_equal(1, g:Count())
let g:Count2 = LambdaFoo()
call test_garbagecollect_now()
call assert_equal(1, g:Count2())
call assert_equal(2, g:Count())
call assert_equal(3, g:Count2())
delfunc LambdaFoo
delfunc LambdaBar
endfunc

View File

@@ -1,4 +1,26 @@
" Test binding arguments to a Funcref.
" NOTE: This function may cause memory leaks to be reported.
" That is because when fork/exec fails memory is not freed. Since the process
" exists right away it's not a real leak.
func Test_job_start_fails()
if has('job')
let job = job_start('axdfxsdf')
for i in range(100)
let status = job_status(job)
if status == 'dead' || status == 'fail'
break
endif
sleep 10m
endfor
if has('unix')
call assert_equal('dead', job_status(job))
else
call assert_equal('fail', job_status(job))
endif
unlet job
endif
endfunc
func MyFunc(arg1, arg2, arg3)
return a:arg1 . '/' . a:arg2 . '/' . a:arg3
@@ -271,25 +293,6 @@ func Test_cycle_partial_job()
endif
endfunc
func Test_job_start_fails()
if has('job')
let job = job_start('axdfxsdf')
for i in range(100)
let status = job_status(job)
if status == 'dead' || status == 'fail'
break
endif
sleep 10m
endfor
if has('unix')
call assert_equal('dead', job_status(job))
else
call assert_equal('fail', job_status(job))
endif
unlet job
endif
endfunc
func Test_ref_job_partial_dict()
if has('job')
let g:ref_job = job_start('echo')

View File

@@ -8,31 +8,57 @@ function Test_cmdmods()
MyCmd
aboveleft MyCmd
abo MyCmd
belowright MyCmd
bel MyCmd
botright MyCmd
bo MyCmd
browse MyCmd
bro MyCmd
confirm MyCmd
conf MyCmd
hide MyCmd
hid MyCmd
keepalt MyCmd
keepa MyCmd
keepjumps MyCmd
keepj MyCmd
keepmarks MyCmd
kee MyCmd
keeppatterns MyCmd
keepp MyCmd
leftabove MyCmd " results in :aboveleft
lefta MyCmd
lockmarks MyCmd
loc MyCmd
" noautocmd MyCmd
noswapfile MyCmd
nos MyCmd
rightbelow MyCmd " results in :belowright
rightb MyCmd
" sandbox MyCmd
silent MyCmd
sil MyCmd
tab MyCmd
topleft MyCmd
to MyCmd
" unsilent MyCmd
verbose MyCmd
verb MyCmd
vertical MyCmd
vert MyCmd
aboveleft belowright botright browse confirm hide keepalt keepjumps
\ keepmarks keeppatterns lockmarks noswapfile silent tab
\ topleft verbose vertical MyCmd
call assert_equal(' aboveleft belowright botright browse confirm ' .
\ 'hide keepalt keepjumps keepmarks keeppatterns lockmarks ' .
\ 'noswapfile silent tab topleft verbose vertical aboveleft ' .
\ 'belowright botright browse confirm hide keepalt keepjumps ' .
call assert_equal(' aboveleft aboveleft belowright belowright botright ' .
\ 'botright browse browse confirm confirm hide hide ' .
\ 'keepalt keepalt keepjumps keepjumps keepmarks keepmarks ' .
\ 'keeppatterns keeppatterns aboveleft aboveleft lockmarks lockmarks noswapfile ' .
\ 'noswapfile belowright belowright silent silent tab topleft topleft verbose verbose ' .
\ 'vertical vertical ' .
\ 'aboveleft belowright botright browse confirm hide keepalt keepjumps ' .
\ 'keepmarks keeppatterns lockmarks noswapfile silent tab topleft ' .
\ 'verbose vertical ', g:mods)

File diff suppressed because it is too large Load Diff

View File

@@ -304,6 +304,11 @@ static char *(features[]) =
#else
"-keymap",
#endif
#ifdef FEAT_EVAL
"+lambda",
#else
"-lambda",
#endif
#ifdef FEAT_LANGMAP
"+langmap",
#else
@@ -758,6 +763,48 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
2139,
/**/
2138,
/**/
2137,
/**/
2136,
/**/
2135,
/**/
2134,
/**/
2133,
/**/
2132,
/**/
2131,
/**/
2130,
/**/
2129,
/**/
2128,
/**/
2127,
/**/
2126,
/**/
2125,
/**/
2124,
/**/
2123,
/**/
2122,
/**/
2121,
/**/
2120,
/**/
2119,
/**/
2118,
/**/

View File

@@ -98,12 +98,6 @@
# ifndef HAVE_CONFIG_H
# define UNIX
# endif
# if defined(FEAT_SMALL) && !defined(FEAT_CLIPBOARD)
# define FEAT_CLIPBOARD
# endif
# if defined(FEAT_SMALL) && !defined(FEAT_MOUSE)
# define FEAT_MOUSE
# endif
#endif
#if defined(MACOS_X) || defined(MACOS_CLASSIC)
# define MACOS
@@ -180,7 +174,20 @@
#endif
#include "feature.h" /* #defines for optionals and features */
/*
* #defines for optionals and features
* Also defines FEAT_TINY, FEAT_SMALL, etc. when FEAT_HUGE is defined.
*/
#include "feature.h"
#if defined(MACOS_X_UNIX)
# if defined(FEAT_SMALL) && !defined(FEAT_CLIPBOARD)
# define FEAT_CLIPBOARD
# endif
# if defined(FEAT_SMALL) && !defined(FEAT_MOUSE)
# define FEAT_MOUSE
# endif
#endif
/* +x11 is only enabled when it's both available and wanted. */
#if defined(HAVE_X11) && defined(WANT_X11)
@@ -2451,6 +2458,7 @@ int vim_main2(int argc, char **argv);
#define TFN_INT 1 /* internal function name OK */
#define TFN_QUIET 2 /* no error messages */
#define TFN_NO_AUTOLOAD 4 /* do not use script autoloading */
#define TFN_NO_DEREF 8 /* do not dereference a Funcref */
/* Values for get_lval() flags argument: */
#define GLV_QUIET TFN_QUIET /* no error messages */
@@ -2467,6 +2475,7 @@ int vim_main2(int argc, char **argv);
#define ERROR_DICT 4
#define ERROR_NONE 5
#define ERROR_OTHER 6
#define ERROR_DELETED 7
/* flags for find_name_end() */
#define FNE_INCL_BR 1 /* include [] in name */

View File

@@ -4,6 +4,10 @@ This is XPM library compiled for Windows which is intended for use with Vim
Libraries in x86 directory were compiled with MSVC6 and MinGW. Proposed
commands to compile Vim are:
If you want to build XPM library by yourself, you may want to use the
following Win32 port:
https://github.com/koron/libXpm-win32
Any version of MSVC starting from version 6.0:
nmake -f Make_mvc.mak GUI=yes CSCOPE=yes NETBEANS=yes XPM=e:\hg\xpm\x86