mirror of
https://github.com/macvim-dev/macvim.git
synced 2026-06-07 15:37:14 +02:00
Merge remote-tracking branch 'vim/master'
This commit is contained in:
+20
-2
@@ -6239,8 +6239,26 @@ min({expr}) Return the minimum value of all items in {expr}. Example: >
|
||||
mkdir({name} [, {path} [, {prot}]])
|
||||
Create directory {name}.
|
||||
|
||||
If {path} is "p" then intermediate directories are created as
|
||||
necessary. Otherwise it must be "".
|
||||
If {path} contains "p" then intermediate directories are
|
||||
created as necessary. Otherwise it must be "".
|
||||
|
||||
If {path} contains "D" then {name} is deleted at the end of
|
||||
the current function, as with: >
|
||||
defer delete({name}, 'd')
|
||||
<
|
||||
If {path} contains "R" then {name} is deleted recursively at
|
||||
the end of the current function, as with: >
|
||||
defer delete({name}, 'rf')
|
||||
< Note that when {name} has more than one part and "p" is used
|
||||
some directories may already exist. Only the first one that
|
||||
is created and what it contains is scheduled to be deleted.
|
||||
E.g. when using: >
|
||||
call mkdir('subdir/tmp/autoload', 'pR')
|
||||
< and "subdir" already exists then "subdir/tmp" will be
|
||||
scheduled for deletion, like with: >
|
||||
defer delete('subdir/tmp', 'rf')
|
||||
< Note that if scheduling the defer fails the directory is not
|
||||
deleted. This should only happen when out of memory.
|
||||
|
||||
If {prot} is given it is used to set the protection bits of
|
||||
the new directory. The default is 0o755 (rwxr-xr-x: r/w for
|
||||
|
||||
@@ -940,7 +940,7 @@ au BufNewFile,BufRead *.java,*.jav setf java
|
||||
au BufNewFile,BufRead *.jj,*.jjt setf javacc
|
||||
|
||||
" JavaScript, ECMAScript, ES module script, CommonJS script
|
||||
au BufNewFile,BufRead *.js,*.javascript,*.es,*.mjs,*.cjs setf javascript
|
||||
au BufNewFile,BufRead *.js,*.jsm,*.javascript,*.es,*.mjs,*.cjs setf javascript
|
||||
|
||||
" JavaScript with React
|
||||
au BufNewFile,BufRead *.jsx setf javascriptreact
|
||||
|
||||
+1
-2
@@ -943,14 +943,13 @@ vim_isprintc_strict(int c)
|
||||
init_chartabsize_arg(
|
||||
chartabsize_T *cts,
|
||||
win_T *wp,
|
||||
linenr_T lnum,
|
||||
linenr_T lnum UNUSED,
|
||||
colnr_T col,
|
||||
char_u *line,
|
||||
char_u *ptr)
|
||||
{
|
||||
CLEAR_POINTER(cts);
|
||||
cts->cts_win = wp;
|
||||
cts->cts_lnum = lnum;
|
||||
cts->cts_vcol = col;
|
||||
cts->cts_line = line;
|
||||
cts->cts_ptr = ptr;
|
||||
|
||||
+4
-2
@@ -911,13 +911,15 @@ eval_dict(char_u **arg, typval_T *rettv, evalarg_T *evalarg, int literal)
|
||||
int vim9script = in_vim9script();
|
||||
int had_comma;
|
||||
|
||||
// First check if it's not a curly-braces thing: {expr}.
|
||||
// First check if it's not a curly-braces expression: {expr}.
|
||||
// Must do this without evaluating, otherwise a function may be called
|
||||
// twice. Unfortunately this means we need to call eval1() twice for the
|
||||
// first item.
|
||||
// But {} is an empty Dictionary.
|
||||
// "{}" is an empty Dictionary.
|
||||
// "#{abc}" is never a curly-braces expression.
|
||||
if (!vim9script
|
||||
&& *curly_expr != '}'
|
||||
&& !literal
|
||||
&& eval1(&curly_expr, &tv, NULL) == OK
|
||||
&& *skipwhite(curly_expr) == '}')
|
||||
return NOTDONE;
|
||||
|
||||
+11
-3
@@ -263,9 +263,17 @@ eval_expr_typval(typval_T *expr, typval_T *argv, int argc, typval_T *rettv)
|
||||
if (partial->pt_func != NULL
|
||||
&& partial->pt_func->uf_def_status != UF_NOT_COMPILED)
|
||||
{
|
||||
// FIXME: should create a funccal and link it in current_funccal.
|
||||
if (call_def_function(partial->pt_func, argc, argv,
|
||||
partial, NULL, rettv) == FAIL)
|
||||
funccall_T *fc = create_funccal(partial->pt_func, rettv);
|
||||
int r;
|
||||
|
||||
if (fc == NULL)
|
||||
return FAIL;
|
||||
|
||||
// Shortcut to call a compiled function without overhead.
|
||||
r = call_def_function(partial->pt_func, argc, argv,
|
||||
DEF_USE_PT_ARGV, partial, fc, rettv);
|
||||
remove_funccal();
|
||||
if (r == FAIL)
|
||||
return FAIL;
|
||||
}
|
||||
else
|
||||
|
||||
+46
-9
@@ -1428,10 +1428,12 @@ f_isabsolutepath(typval_T *argvars, typval_T *rettv)
|
||||
/*
|
||||
* Create the directory in which "dir" is located, and higher levels when
|
||||
* needed.
|
||||
* Set "created" to the full name of the first created directory. It will be
|
||||
* NULL until that happens.
|
||||
* Return OK or FAIL.
|
||||
*/
|
||||
static int
|
||||
mkdir_recurse(char_u *dir, int prot)
|
||||
mkdir_recurse(char_u *dir, int prot, char_u **created)
|
||||
{
|
||||
char_u *p;
|
||||
char_u *updir;
|
||||
@@ -1449,8 +1451,12 @@ mkdir_recurse(char_u *dir, int prot)
|
||||
return FAIL;
|
||||
if (mch_isdir(updir))
|
||||
r = OK;
|
||||
else if (mkdir_recurse(updir, prot) == OK)
|
||||
else if (mkdir_recurse(updir, prot, created) == OK)
|
||||
{
|
||||
r = vim_mkdir_emsg(updir, prot);
|
||||
if (r == OK && created != NULL && *created == NULL)
|
||||
*created = FullName_save(updir, FALSE);
|
||||
}
|
||||
vim_free(updir);
|
||||
return r;
|
||||
}
|
||||
@@ -1464,6 +1470,9 @@ f_mkdir(typval_T *argvars, typval_T *rettv)
|
||||
char_u *dir;
|
||||
char_u buf[NUMBUFLEN];
|
||||
int prot = 0755;
|
||||
int defer = FALSE;
|
||||
int defer_recurse = FALSE;
|
||||
char_u *created = NULL;
|
||||
|
||||
rettv->vval.v_number = FAIL;
|
||||
if (check_restricted() || check_secure())
|
||||
@@ -1486,13 +1495,21 @@ f_mkdir(typval_T *argvars, typval_T *rettv)
|
||||
|
||||
if (argvars[1].v_type != VAR_UNKNOWN)
|
||||
{
|
||||
char_u *arg2;
|
||||
|
||||
if (argvars[2].v_type != VAR_UNKNOWN)
|
||||
{
|
||||
prot = (int)tv_get_number_chk(&argvars[2], NULL);
|
||||
if (prot == -1)
|
||||
return;
|
||||
}
|
||||
if (STRCMP(tv_get_string(&argvars[1]), "p") == 0)
|
||||
arg2 = tv_get_string(&argvars[1]);
|
||||
defer = vim_strchr(arg2, 'D') != NULL;
|
||||
defer_recurse = vim_strchr(arg2, 'R') != NULL;
|
||||
if ((defer || defer_recurse) && !can_add_defer())
|
||||
return;
|
||||
|
||||
if (vim_strchr(arg2, 'p') != NULL)
|
||||
{
|
||||
if (mch_isdir(dir))
|
||||
{
|
||||
@@ -1500,10 +1517,33 @@ f_mkdir(typval_T *argvars, typval_T *rettv)
|
||||
rettv->vval.v_number = OK;
|
||||
return;
|
||||
}
|
||||
mkdir_recurse(dir, prot);
|
||||
mkdir_recurse(dir, prot, defer || defer_recurse ? &created : NULL);
|
||||
}
|
||||
}
|
||||
rettv->vval.v_number = vim_mkdir_emsg(dir, prot);
|
||||
|
||||
// Handle "D" and "R": deferred deletion of the created directory.
|
||||
if (rettv->vval.v_number == OK
|
||||
&& created == NULL && (defer || defer_recurse))
|
||||
created = FullName_save(dir, FALSE);
|
||||
if (created != NULL)
|
||||
{
|
||||
typval_T tv[2];
|
||||
|
||||
tv[0].v_type = VAR_STRING;
|
||||
tv[0].v_lock = 0;
|
||||
tv[0].vval.v_string = created;
|
||||
tv[1].v_type = VAR_STRING;
|
||||
tv[1].v_lock = 0;
|
||||
tv[1].vval.v_string = vim_strsave(
|
||||
(char_u *)(defer_recurse ? "rf" : "d"));
|
||||
if (tv[0].vval.v_string == NULL || tv[1].vval.v_string == NULL
|
||||
|| add_defer((char_u *)"delete", 2, tv) == FAIL)
|
||||
{
|
||||
vim_free(tv[0].vval.v_string);
|
||||
vim_free(tv[1].vval.v_string);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2300,11 +2340,8 @@ f_writefile(typval_T *argvars, typval_T *rettv)
|
||||
if (fname == NULL)
|
||||
return;
|
||||
|
||||
if (defer && !in_def_function() && get_current_funccal() == NULL)
|
||||
{
|
||||
semsg(_(e_str_not_inside_function), "defer");
|
||||
if (defer && !can_add_defer())
|
||||
return;
|
||||
}
|
||||
|
||||
// Always open the file in binary mode, library functions have a mind of
|
||||
// their own about CR-LF conversion.
|
||||
@@ -2323,7 +2360,7 @@ f_writefile(typval_T *argvars, typval_T *rettv)
|
||||
|
||||
tv.v_type = VAR_STRING;
|
||||
tv.v_lock = 0;
|
||||
tv.vval.v_string = vim_strsave(fname);
|
||||
tv.vval.v_string = FullName_save(fname, FALSE);
|
||||
if (tv.vval.v_string == NULL
|
||||
|| add_defer((char_u *)"delete", 1, &tv) == FAIL)
|
||||
{
|
||||
|
||||
@@ -8649,6 +8649,7 @@ test_gui_w32_sendevent(dict_T *args)
|
||||
inputs[0].ki.wVk = vkCode;
|
||||
if (STRICMP(event, "keyup") == 0)
|
||||
inputs[0].ki.dwFlags = KEYEVENTF_KEYUP;
|
||||
(void)SetForegroundWindow(s_hwnd);
|
||||
SendInput(ARRAYSIZE(inputs), inputs, sizeof(INPUT));
|
||||
}
|
||||
else
|
||||
|
||||
@@ -21,6 +21,8 @@ int funcdepth_increment(void);
|
||||
void funcdepth_decrement(void);
|
||||
int funcdepth_get(void);
|
||||
void funcdepth_restore(int depth);
|
||||
funccall_T *create_funccal(ufunc_T *fp, typval_T *rettv);
|
||||
void remove_funccal(void);
|
||||
int check_user_func_argcount(ufunc_T *fp, int argcount);
|
||||
int call_user_func_check(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rettv, funcexe_T *funcexe, dict_T *selfdict);
|
||||
void save_funccal(funccal_entry_T *entry);
|
||||
@@ -58,6 +60,7 @@ 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);
|
||||
int can_add_defer(void);
|
||||
int add_defer(char_u *name, int argcount_arg, typval_T *argvars);
|
||||
void invoke_all_defer(void);
|
||||
void ex_call(exarg_T *eap);
|
||||
|
||||
@@ -15,7 +15,7 @@ typval_T *lookup_debug_var(char_u *name);
|
||||
int may_break_in_function(ufunc_T *ufunc);
|
||||
int exe_typval_instr(typval_T *tv, typval_T *rettv);
|
||||
char_u *exe_substitute_instr(void);
|
||||
int call_def_function(ufunc_T *ufunc, int argc_arg, typval_T *argv, partial_T *partial, funccall_T *funccal, typval_T *rettv);
|
||||
int call_def_function(ufunc_T *ufunc, int argc_arg, typval_T *argv, int flags, partial_T *partial, funccall_T *funccal, typval_T *rettv);
|
||||
void unwind_def_callstack(ectx_T *ectx);
|
||||
void may_invoke_defer_funcs(ectx_T *ectx);
|
||||
void set_context_in_disassemble_cmd(expand_T *xp, char_u *arg);
|
||||
|
||||
+1
-1
@@ -3444,7 +3444,7 @@ regmatch(
|
||||
linenr_T lnum = rex.reg_firstlnum + rex.lnum;
|
||||
long_u vcol = 0;
|
||||
|
||||
if (lnum > 0 && lnum <= wp->w_buffer->b_ml.ml_line_count)
|
||||
if (lnum >= 0 && lnum <= wp->w_buffer->b_ml.ml_line_count)
|
||||
vcol = (long_u)win_linetabsize(wp, lnum, rex.line,
|
||||
(colnr_T)(rex.input - rex.line));
|
||||
if (!re_num_cmp(vcol + 1, scan))
|
||||
|
||||
+1
-1
@@ -6778,7 +6778,7 @@ nfa_regmatch(
|
||||
linenr_T lnum = rex.reg_firstlnum + rex.lnum;
|
||||
long_u vcol = 0;
|
||||
|
||||
if (lnum > 0
|
||||
if (lnum >= 0
|
||||
&& lnum <= wp->w_buffer->b_ml.ml_line_count)
|
||||
vcol = (long_u)win_linetabsize(wp, lnum,
|
||||
rex.line, col);
|
||||
|
||||
@@ -4618,7 +4618,6 @@ typedef struct {
|
||||
// Argument for lbr_chartabsize().
|
||||
typedef struct {
|
||||
win_T *cts_win;
|
||||
linenr_T cts_lnum; // zero when not using text properties
|
||||
char_u *cts_line; // start of the line
|
||||
char_u *cts_ptr; // current position in line
|
||||
#ifdef FEAT_PROP_POPUP
|
||||
|
||||
@@ -275,6 +275,21 @@ func Test_assert_fail_fails()
|
||||
endtry
|
||||
call assert_match("E1222: String or List required for argument 2", exp)
|
||||
|
||||
try
|
||||
call assert_equal(0, assert_fails('xxx', [#{one: 1}]))
|
||||
catch
|
||||
let exp = v:exception
|
||||
endtry
|
||||
call assert_match("E731: Using a Dictionary as a String", exp)
|
||||
|
||||
let exp = ''
|
||||
try
|
||||
call assert_equal(0, assert_fails('xxx', ['E492', #{one: 1}]))
|
||||
catch
|
||||
let exp = v:exception
|
||||
endtry
|
||||
call assert_match("E731: Using a Dictionary as a String", exp)
|
||||
|
||||
try
|
||||
call assert_equal(1, assert_fails('xxx', 'E492', '', 'burp'))
|
||||
catch
|
||||
@@ -289,8 +304,8 @@ func Test_assert_fail_fails()
|
||||
endtry
|
||||
call assert_match("E1174: String required for argument 5", exp)
|
||||
|
||||
call assert_equal(1, assert_fails('c0', ['', '\1']))
|
||||
call assert_match("Expected '\\\\\\\\1' but got 'E939: Positive count required: c0': c0", v:errors[0])
|
||||
call assert_equal(1, assert_fails('c0', ['', '\(.\)\1']))
|
||||
call assert_match("Expected '\\\\\\\\(.\\\\\\\\)\\\\\\\\1' but got 'E939: Positive count required: c0': c0", v:errors[0])
|
||||
call remove(v:errors, 0)
|
||||
endfunc
|
||||
|
||||
|
||||
@@ -28,9 +28,9 @@ endfunc
|
||||
func Test_set_filename_other_window()
|
||||
let cwd = getcwd()
|
||||
call test_autochdir()
|
||||
call mkdir('Xa')
|
||||
call mkdir('Xb')
|
||||
call mkdir('Xc')
|
||||
call mkdir('Xa', 'R')
|
||||
call mkdir('Xb', 'R')
|
||||
call mkdir('Xc', 'R')
|
||||
try
|
||||
args Xa/aaa.txt Xb/bbb.txt
|
||||
set acd
|
||||
@@ -45,9 +45,6 @@ func Test_set_filename_other_window()
|
||||
bwipe! aaa.txt
|
||||
bwipe! bbb.txt
|
||||
bwipe! ccc.txt
|
||||
call delete('Xa', 'rf')
|
||||
call delete('Xb', 'rf')
|
||||
call delete('Xc', 'rf')
|
||||
endtry
|
||||
endfunc
|
||||
|
||||
@@ -56,7 +53,7 @@ func Test_acd_win_execute()
|
||||
set acd
|
||||
call test_autochdir()
|
||||
|
||||
call mkdir('XacdDir')
|
||||
call mkdir('XacdDir', 'R')
|
||||
let winid = win_getid()
|
||||
new XacdDir/file
|
||||
call assert_match('testdir.XacdDir$', getcwd())
|
||||
@@ -68,7 +65,6 @@ func Test_acd_win_execute()
|
||||
bwipe!
|
||||
set noacd
|
||||
call chdir(cwd)
|
||||
call delete('XacdDir', 'rf')
|
||||
endfunc
|
||||
|
||||
func Test_verbose_pwd()
|
||||
@@ -78,7 +74,7 @@ func Test_verbose_pwd()
|
||||
edit global.txt
|
||||
call assert_match('\[global\].*testdir$', execute('verbose pwd'))
|
||||
|
||||
call mkdir('Xautodir')
|
||||
call mkdir('Xautodir', 'R')
|
||||
split Xautodir/local.txt
|
||||
lcd Xautodir
|
||||
call assert_match('\[window\].*testdir[/\\]Xautodir', execute('verbose pwd'))
|
||||
@@ -112,7 +108,6 @@ func Test_verbose_pwd()
|
||||
|
||||
bwipe!
|
||||
call chdir(cwd)
|
||||
call delete('Xautodir', 'rf')
|
||||
endfunc
|
||||
|
||||
func Test_multibyte()
|
||||
|
||||
@@ -707,14 +707,13 @@ func Test_BufEnter()
|
||||
call assert_equal('++', g:val)
|
||||
|
||||
" Also get BufEnter when editing a directory
|
||||
call mkdir('Xbufenterdir')
|
||||
call mkdir('Xbufenterdir', 'D')
|
||||
split Xbufenterdir
|
||||
call assert_equal('+++', g:val)
|
||||
|
||||
" On MS-Windows we can't edit the directory, make sure we wipe the right
|
||||
" buffer.
|
||||
bwipe! Xbufenterdir
|
||||
call delete('Xbufenterdir', 'd')
|
||||
au! BufEnter
|
||||
|
||||
" Editing a "nofile" buffer doesn't read the file but does trigger BufEnter
|
||||
@@ -1902,11 +1901,10 @@ func Test_BufWriteCmd()
|
||||
new
|
||||
file Xbufwritecmd
|
||||
set buftype=acwrite
|
||||
call mkdir('Xbufwritecmd')
|
||||
call mkdir('Xbufwritecmd', 'D')
|
||||
write
|
||||
" BufWriteCmd should be triggered even if a directory has the same name
|
||||
call assert_equal(1, g:written)
|
||||
call delete('Xbufwritecmd', 'd')
|
||||
unlet g:written
|
||||
au! BufWriteCmd
|
||||
bwipe!
|
||||
@@ -2710,7 +2708,7 @@ func Test_throw_in_BufWritePre()
|
||||
endfunc
|
||||
|
||||
func Test_autocmd_in_try_block()
|
||||
call mkdir('Xintrydir')
|
||||
call mkdir('Xintrydir', 'R')
|
||||
au BufEnter * let g:fname = expand('%')
|
||||
try
|
||||
edit Xintrydir/
|
||||
@@ -2719,7 +2717,6 @@ func Test_autocmd_in_try_block()
|
||||
|
||||
unlet g:fname
|
||||
au! BufEnter
|
||||
call delete('Xintrydir', 'rf')
|
||||
endfunc
|
||||
|
||||
func Test_autocmd_SafeState()
|
||||
|
||||
@@ -44,6 +44,64 @@ func Test_mkdir_p()
|
||||
call assert_fails('call mkdir("abc", [], [])', 'E745:')
|
||||
endfunc
|
||||
|
||||
func DoMkdirDel(name)
|
||||
call mkdir(a:name, 'pD')
|
||||
call assert_true(isdirectory(a:name))
|
||||
endfunc
|
||||
|
||||
func DoMkdirDelAddFile(name)
|
||||
call mkdir(a:name, 'pD')
|
||||
call assert_true(isdirectory(a:name))
|
||||
call writefile(['text'], a:name .. '/file')
|
||||
endfunc
|
||||
|
||||
func DoMkdirDelRec(name)
|
||||
call mkdir(a:name, 'pR')
|
||||
call assert_true(isdirectory(a:name))
|
||||
endfunc
|
||||
|
||||
func DoMkdirDelRecAddFile(name)
|
||||
call mkdir(a:name, 'pR')
|
||||
call assert_true(isdirectory(a:name))
|
||||
call writefile(['text'], a:name .. '/file')
|
||||
endfunc
|
||||
|
||||
func Test_mkdir_defer_del()
|
||||
" Xtopdir/tmp is created thus deleted, not Xtopdir itself
|
||||
call mkdir('Xtopdir', 'R')
|
||||
call DoMkdirDel('Xtopdir/tmp')
|
||||
call assert_true(isdirectory('Xtopdir'))
|
||||
call assert_false(isdirectory('Xtopdir/tmp'))
|
||||
|
||||
" Deletion fails because "tmp" contains "sub"
|
||||
call DoMkdirDel('Xtopdir/tmp/sub')
|
||||
call assert_true(isdirectory('Xtopdir'))
|
||||
call assert_true(isdirectory('Xtopdir/tmp'))
|
||||
call delete('Xtopdir/tmp', 'rf')
|
||||
|
||||
" Deletion fails because "tmp" contains "file"
|
||||
call DoMkdirDelAddFile('Xtopdir/tmp')
|
||||
call assert_true(isdirectory('Xtopdir'))
|
||||
call assert_true(isdirectory('Xtopdir/tmp'))
|
||||
call assert_true(filereadable('Xtopdir/tmp/file'))
|
||||
call delete('Xtopdir/tmp', 'rf')
|
||||
|
||||
" Xtopdir/tmp is created thus deleted, not Xtopdir itself
|
||||
call DoMkdirDelRec('Xtopdir/tmp')
|
||||
call assert_true(isdirectory('Xtopdir'))
|
||||
call assert_false(isdirectory('Xtopdir/tmp'))
|
||||
|
||||
" Deletion works even though "tmp" contains "sub"
|
||||
call DoMkdirDelRec('Xtopdir/tmp/sub')
|
||||
call assert_true(isdirectory('Xtopdir'))
|
||||
call assert_false(isdirectory('Xtopdir/tmp'))
|
||||
|
||||
" Deletion works even though "tmp" contains "file"
|
||||
call DoMkdirDelRecAddFile('Xtopdir/tmp')
|
||||
call assert_true(isdirectory('Xtopdir'))
|
||||
call assert_false(isdirectory('Xtopdir/tmp'))
|
||||
endfunc
|
||||
|
||||
func Test_line_continuation()
|
||||
let array = [5,
|
||||
"\ ignore this
|
||||
|
||||
@@ -275,7 +275,7 @@ let s:filename_checks = {
|
||||
\ 'jam': ['file.jpl', 'file.jpr', 'JAM-file.file', 'JAM.file', 'Prl-file.file', 'Prl.file'],
|
||||
\ 'java': ['file.java', 'file.jav'],
|
||||
\ 'javacc': ['file.jj', 'file.jjt'],
|
||||
\ 'javascript': ['file.js', 'file.javascript', 'file.es', 'file.mjs', 'file.cjs'],
|
||||
\ 'javascript': ['file.js', 'file.jsm', 'file.javascript', 'file.es', 'file.mjs', 'file.cjs'],
|
||||
\ 'javascript.glimmer': ['file.gjs'],
|
||||
\ 'javascriptreact': ['file.jsx'],
|
||||
\ 'jess': ['file.clp'],
|
||||
|
||||
@@ -1614,12 +1614,15 @@ func Test_gui_CTRL_SHIFT_V()
|
||||
endfunc
|
||||
|
||||
func Test_gui_dialog_file()
|
||||
" make sure the file does not exist, otherwise a dialog makes Vim hang
|
||||
call delete('Xdialfile')
|
||||
|
||||
let lines =<< trim END
|
||||
file Xdialfile
|
||||
normal axxx
|
||||
confirm qa
|
||||
END
|
||||
call writefile(lines, 'Xlines')
|
||||
call writefile(lines, 'Xlines', 'D')
|
||||
let prefix = '!'
|
||||
if has('win32')
|
||||
let prefix = '!start '
|
||||
@@ -1636,7 +1639,6 @@ func Test_gui_dialog_file()
|
||||
|
||||
call delete('Xdialog')
|
||||
call delete('Xdialfile')
|
||||
call delete('Xlines')
|
||||
endfunc
|
||||
|
||||
" Test for sending low level key presses
|
||||
|
||||
@@ -321,6 +321,10 @@ func Test_dict()
|
||||
|
||||
" allow key starting with number at the start, not a curly expression
|
||||
call assert_equal({'1foo': 77}, #{1foo: 77})
|
||||
|
||||
" #{expr} is not a curly expression
|
||||
let x = 'x'
|
||||
call assert_equal(#{g: x}, #{g:x})
|
||||
endfunc
|
||||
|
||||
" This was allowed in legacy Vim script
|
||||
|
||||
@@ -30,11 +30,13 @@ endfunc
|
||||
func Test_equivalence_re1()
|
||||
set re=1
|
||||
call s:equivalence_test()
|
||||
set re=0
|
||||
endfunc
|
||||
|
||||
func Test_equivalence_re2()
|
||||
set re=2
|
||||
call s:equivalence_test()
|
||||
set re=0
|
||||
endfunc
|
||||
|
||||
func Test_recursive_substitute()
|
||||
@@ -67,6 +69,7 @@ func Test_eow_with_optional()
|
||||
let actual = matchlist('abc def', '\(abc\>\)\?\s*\(def\)')
|
||||
call assert_equal(expected, actual)
|
||||
endfor
|
||||
set re=0
|
||||
endfunc
|
||||
|
||||
func Test_backref()
|
||||
@@ -1141,4 +1144,14 @@ def Test_compare_columns()
|
||||
prop_type_delete('name')
|
||||
enddef
|
||||
|
||||
def Test_compare_column_matchstr()
|
||||
enew
|
||||
set re=1
|
||||
call assert_equal('aaa', matchstr('aaaaaaaaaaaaaaaaaaaa', '.*\%<5v'))
|
||||
set re=2
|
||||
call assert_equal('aaa', matchstr('aaaaaaaaaaaaaaaaaaaa', '.*\%<5v'))
|
||||
set re=0
|
||||
enddef
|
||||
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
||||
@@ -625,6 +625,29 @@ func Test_defer_quitall()
|
||||
call assert_false(filereadable('XQuitallTwo'))
|
||||
endfunc
|
||||
|
||||
func Test_defer_quitall_in_expr_func()
|
||||
let lines =<< trim END
|
||||
def DefIndex(idx: number, val: string): bool
|
||||
call writefile([idx .. ': ' .. val], 'Xentry' .. idx, 'D')
|
||||
if val == 'b'
|
||||
qa!
|
||||
endif
|
||||
return val == 'c'
|
||||
enddef
|
||||
|
||||
def Test_defer_in_funcref()
|
||||
assert_equal(2, indexof(['a', 'b', 'c'], funcref('g:DefIndex')))
|
||||
enddef
|
||||
call Test_defer_in_funcref()
|
||||
END
|
||||
call writefile(lines, 'XdeferQuitallExpr', 'D')
|
||||
let res = system(GetVimCommandClean() .. ' -X -S XdeferQuitallExpr')
|
||||
call assert_equal(0, v:shell_error)
|
||||
call assert_false(filereadable('Xentry0'))
|
||||
call assert_false(filereadable('Xentry1'))
|
||||
call assert_false(filereadable('Xentry2'))
|
||||
endfunc
|
||||
|
||||
func FuncIndex(idx, val)
|
||||
call writefile([a:idx .. ': ' .. a:val], 'Xentry' .. a:idx, 'D')
|
||||
return a:val == 'c'
|
||||
@@ -635,6 +658,11 @@ def DefIndex(idx: number, val: string): bool
|
||||
return val == 'c'
|
||||
enddef
|
||||
|
||||
def DefIndexXtra(xtra: string, idx: number, val: string): bool
|
||||
call writefile([idx .. ': ' .. val], 'Xentry' .. idx, 'D')
|
||||
return val == 'c'
|
||||
enddef
|
||||
|
||||
def Test_defer_in_funcref()
|
||||
assert_equal(2, indexof(['a', 'b', 'c'], function('g:FuncIndex')))
|
||||
assert_false(filereadable('Xentry0'))
|
||||
@@ -655,6 +683,16 @@ def Test_defer_in_funcref()
|
||||
assert_false(filereadable('Xentry0'))
|
||||
assert_false(filereadable('Xentry1'))
|
||||
assert_false(filereadable('Xentry2'))
|
||||
|
||||
assert_equal(2, indexof(['a', 'b', 'c'], function(g:DefIndexXtra, ['xtra'])))
|
||||
assert_false(filereadable('Xentry0'))
|
||||
assert_false(filereadable('Xentry1'))
|
||||
assert_false(filereadable('Xentry2'))
|
||||
|
||||
assert_equal(2, indexof(['a', 'b', 'c'], funcref(g:DefIndexXtra, ['xtra'])))
|
||||
assert_false(filereadable('Xentry0'))
|
||||
assert_false(filereadable('Xentry1'))
|
||||
assert_false(filereadable('Xentry2'))
|
||||
enddef
|
||||
|
||||
|
||||
|
||||
@@ -1617,4 +1617,19 @@ func Test_window_alloc_failure()
|
||||
tabonly
|
||||
endfunc
|
||||
|
||||
func Test_win_equal_last_status()
|
||||
let save_lines = &lines
|
||||
set lines=20
|
||||
set splitbelow
|
||||
set laststatus=0
|
||||
|
||||
split | split | quit
|
||||
call assert_equal(winheight(1), winheight(2))
|
||||
|
||||
let &lines = save_lines
|
||||
set splitbelow&
|
||||
set laststatus&
|
||||
endfunc
|
||||
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
||||
@@ -950,6 +950,19 @@ func Test_write_with_deferred_delete()
|
||||
call assert_equal('', glob('XdefdeferDelete'))
|
||||
endfunc
|
||||
|
||||
func DoWriteFile()
|
||||
call writefile(['text'], 'Xthefile', 'D')
|
||||
cd ..
|
||||
endfunc
|
||||
|
||||
func Test_write_defer_delete_chdir()
|
||||
let dir = getcwd()
|
||||
call DoWriteFile()
|
||||
call assert_notequal(dir, getcwd())
|
||||
call chdir(dir)
|
||||
call assert_equal('', glob('Xthefile'))
|
||||
endfunc
|
||||
|
||||
" Check that buffer is written before triggering QuitPre
|
||||
func Test_wq_quitpre_autocommand()
|
||||
edit Xsomefile
|
||||
|
||||
@@ -616,6 +616,11 @@ f_assert_fails(typval_T *argvars, typval_T *rettv)
|
||||
in_assert_fails = TRUE;
|
||||
|
||||
do_cmdline_cmd(cmd);
|
||||
|
||||
// reset here for any errors reported below
|
||||
trylevel = save_trylevel;
|
||||
suppress_errthrow = FALSE;
|
||||
|
||||
if (called_emsg == called_emsg_before)
|
||||
{
|
||||
prepare_assert_error(&ga);
|
||||
@@ -654,6 +659,8 @@ f_assert_fails(typval_T *argvars, typval_T *rettv)
|
||||
CHECK_LIST_MATERIALIZE(list);
|
||||
tv = &list->lv_first->li_tv;
|
||||
expected = tv_get_string_buf_chk(tv, buf);
|
||||
if (expected == NULL)
|
||||
goto theend;
|
||||
if (!pattern_match(expected, actual, FALSE))
|
||||
{
|
||||
error_found = TRUE;
|
||||
@@ -667,6 +674,8 @@ f_assert_fails(typval_T *argvars, typval_T *rettv)
|
||||
{
|
||||
tv = &list->lv_u.mat.lv_last->li_tv;
|
||||
expected = tv_get_string_buf_chk(tv, buf);
|
||||
if (expected == NULL)
|
||||
goto theend;
|
||||
if (!pattern_match(expected, actual, FALSE))
|
||||
{
|
||||
error_found = TRUE;
|
||||
|
||||
+52
-9
@@ -2580,6 +2580,40 @@ funcdepth_restore(int depth)
|
||||
funcdepth = depth;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a funccall_T, link it in current_funccal and fill in "fp" and
|
||||
* "rettv".
|
||||
* Must be followed by one call to remove_funccal() or cleanup_function_call().
|
||||
* Returns NULL when allocation fails.
|
||||
*/
|
||||
funccall_T *
|
||||
create_funccal(ufunc_T *fp, typval_T *rettv)
|
||||
{
|
||||
funccall_T *fc = ALLOC_CLEAR_ONE(funccall_T);
|
||||
|
||||
if (fc == NULL)
|
||||
return NULL;
|
||||
fc->fc_caller = current_funccal;
|
||||
current_funccal = fc;
|
||||
fc->fc_func = fp;
|
||||
func_ptr_ref(fp);
|
||||
fc->fc_rettv = rettv;
|
||||
return fc;
|
||||
}
|
||||
|
||||
/*
|
||||
* To be called when returning from a compiled function; restores
|
||||
* current_funccal.
|
||||
*/
|
||||
void
|
||||
remove_funccal()
|
||||
{
|
||||
funccall_T *fc = current_funccal;
|
||||
|
||||
current_funccal = fc->fc_caller;
|
||||
free_funccal(fc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Call a user function.
|
||||
*/
|
||||
@@ -2627,20 +2661,15 @@ call_user_func(
|
||||
|
||||
line_breakcheck(); // check for CTRL-C hit
|
||||
|
||||
fc = ALLOC_CLEAR_ONE(funccall_T);
|
||||
fc = create_funccal(fp, rettv);
|
||||
if (fc == NULL)
|
||||
return;
|
||||
fc->fc_caller = current_funccal;
|
||||
current_funccal = fc;
|
||||
fc->fc_func = fp;
|
||||
fc->fc_rettv = rettv;
|
||||
fc->fc_level = ex_nesting_level;
|
||||
// Check if this function has a breakpoint.
|
||||
fc->fc_breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name, (linenr_T)0);
|
||||
fc->fc_dbg_tick = debug_tick;
|
||||
// Set up fields for closure.
|
||||
ga_init2(&fc->fc_ufuncs, sizeof(ufunc_T *), 1);
|
||||
func_ptr_ref(fp);
|
||||
|
||||
if (fp->uf_def_status != UF_NOT_COMPILED)
|
||||
{
|
||||
@@ -2653,7 +2682,7 @@ call_user_func(
|
||||
profile_may_start_func(&profile_info, fp, caller);
|
||||
#endif
|
||||
sticky_cmdmod_flags = 0;
|
||||
call_def_function(fp, argcount, argvars, funcexe->fe_partial,
|
||||
call_def_function(fp, argcount, argvars, 0, funcexe->fe_partial,
|
||||
fc, rettv);
|
||||
funcdepth_decrement();
|
||||
#ifdef FEAT_PROFILE
|
||||
@@ -2661,8 +2690,7 @@ call_user_func(
|
||||
|| (caller != NULL && caller->uf_profiling)))
|
||||
profile_may_end_func(&profile_info, fp, caller);
|
||||
#endif
|
||||
current_funccal = fc->fc_caller;
|
||||
free_funccal(fc);
|
||||
remove_funccal();
|
||||
sticky_cmdmod_flags = save_sticky_cmdmod_flags;
|
||||
return;
|
||||
}
|
||||
@@ -5621,6 +5649,21 @@ ex_defer_inner(
|
||||
return add_defer(name, argcount, argvars);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return TRUE if currently inside a function call.
|
||||
* Give an error message and return FALSE when not.
|
||||
*/
|
||||
int
|
||||
can_add_defer(void)
|
||||
{
|
||||
if (!in_def_function() && get_current_funccal() == NULL)
|
||||
{
|
||||
semsg(_(e_str_not_inside_function), "defer");
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a deferred call for "name" with arguments "argvars[argcount]".
|
||||
* Consumes "argvars[]".
|
||||
|
||||
@@ -718,6 +718,32 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
412,
|
||||
/**/
|
||||
411,
|
||||
/**/
|
||||
410,
|
||||
/**/
|
||||
409,
|
||||
/**/
|
||||
408,
|
||||
/**/
|
||||
407,
|
||||
/**/
|
||||
406,
|
||||
/**/
|
||||
405,
|
||||
/**/
|
||||
404,
|
||||
/**/
|
||||
403,
|
||||
/**/
|
||||
402,
|
||||
/**/
|
||||
401,
|
||||
/**/
|
||||
400,
|
||||
/**/
|
||||
399,
|
||||
/**/
|
||||
|
||||
@@ -759,3 +759,5 @@ typedef enum {
|
||||
#define TVTT_DO_MEMBER 1
|
||||
#define TVTT_MORE_SPECIFIC 2 // get most specific type for member
|
||||
|
||||
// flags for call_def_function()
|
||||
#define DEF_USE_PT_ARGV 1 // use the partial arguments
|
||||
|
||||
+21
-12
@@ -5272,16 +5272,21 @@ call_def_function(
|
||||
ufunc_T *ufunc,
|
||||
int argc_arg, // nr of arguments
|
||||
typval_T *argv, // arguments
|
||||
int flags, // DEF_ flags
|
||||
partial_T *partial, // optional partial for context
|
||||
funccall_T *funccal,
|
||||
typval_T *rettv) // return value
|
||||
{
|
||||
ectx_T ectx; // execution context
|
||||
int argc = argc_arg;
|
||||
int partial_argc = partial == NULL
|
||||
|| (flags & DEF_USE_PT_ARGV) == 0
|
||||
? 0 : partial->pt_argc;
|
||||
int total_argc = argc + partial_argc;
|
||||
typval_T *tv;
|
||||
int idx;
|
||||
int ret = FAIL;
|
||||
int defcount = ufunc->uf_args.ga_len - argc;
|
||||
int defcount = ufunc->uf_args.ga_len - total_argc;
|
||||
sctx_T save_current_sctx = current_sctx;
|
||||
int did_emsg_before = did_emsg_cumul + did_emsg;
|
||||
int save_suppress_errthrow = suppress_errthrow;
|
||||
@@ -5345,14 +5350,14 @@ call_def_function(
|
||||
ectx.ec_did_emsg_before = did_emsg_before;
|
||||
++ex_nesting_level;
|
||||
|
||||
idx = argc - ufunc->uf_args.ga_len;
|
||||
idx = total_argc - ufunc->uf_args.ga_len;
|
||||
if (idx > 0 && ufunc->uf_va_name == NULL)
|
||||
{
|
||||
semsg(NGETTEXT(e_one_argument_too_many, e_nr_arguments_too_many,
|
||||
idx), idx);
|
||||
idx), idx);
|
||||
goto failed_early;
|
||||
}
|
||||
idx = argc - ufunc->uf_args.ga_len + ufunc->uf_def_args.ga_len;
|
||||
idx = total_argc - ufunc->uf_args.ga_len + ufunc->uf_def_args.ga_len;
|
||||
if (idx < 0)
|
||||
{
|
||||
semsg(NGETTEXT(e_one_argument_too_few, e_nr_arguments_too_few,
|
||||
@@ -5360,15 +5365,19 @@ call_def_function(
|
||||
goto failed_early;
|
||||
}
|
||||
|
||||
// Put arguments on the stack, but no more than what the function expects.
|
||||
// A lambda can be called with more arguments than it uses.
|
||||
for (idx = 0; idx < argc
|
||||
// Put values from the partial and arguments on the stack, but no more than
|
||||
// what the function expects. A lambda can be called with more arguments
|
||||
// than it uses.
|
||||
for (idx = 0; idx < total_argc
|
||||
&& (ufunc->uf_va_name != NULL || idx < ufunc->uf_args.ga_len);
|
||||
++idx)
|
||||
{
|
||||
int argv_idx = idx - partial_argc;
|
||||
|
||||
tv = idx < partial_argc ? partial->pt_argv + idx : argv + argv_idx;
|
||||
if (idx >= ufunc->uf_args.ga_len - ufunc->uf_def_args.ga_len
|
||||
&& argv[idx].v_type == VAR_SPECIAL
|
||||
&& argv[idx].vval.v_number == VVAL_NONE)
|
||||
&& tv->v_type == VAR_SPECIAL
|
||||
&& tv->vval.v_number == VVAL_NONE)
|
||||
{
|
||||
// Use the default value.
|
||||
STACK_TV_BOT(0)->v_type = VAR_UNKNOWN;
|
||||
@@ -5377,10 +5386,10 @@ call_def_function(
|
||||
{
|
||||
if (ufunc->uf_arg_types != NULL && idx < ufunc->uf_args.ga_len
|
||||
&& check_typval_arg_type(
|
||||
ufunc->uf_arg_types[idx], &argv[idx],
|
||||
NULL, idx + 1) == FAIL)
|
||||
ufunc->uf_arg_types[idx], tv,
|
||||
NULL, argv_idx + 1) == FAIL)
|
||||
goto failed_early;
|
||||
copy_tv(&argv[idx], STACK_TV_BOT(0));
|
||||
copy_tv(tv, STACK_TV_BOT(0));
|
||||
}
|
||||
++ectx.ec_stack.ga_len;
|
||||
}
|
||||
|
||||
+8
-6
@@ -2718,6 +2718,14 @@ win_close(win_T *win, int free_buf)
|
||||
// using the window.
|
||||
check_cursor();
|
||||
}
|
||||
|
||||
/*
|
||||
* If last window has a status line now and we don't want one, remove the
|
||||
* status line. Do this before win_equal(), because it may change the
|
||||
* height of a window
|
||||
*/
|
||||
last_status(FALSE);
|
||||
|
||||
if (p_ea && (*p_ead == 'b' || *p_ead == dir))
|
||||
// If the frame of the closed window contains the new current window,
|
||||
// only resize that frame. Otherwise resize all windows.
|
||||
@@ -2747,12 +2755,6 @@ win_close(win_T *win, int free_buf)
|
||||
--dont_parse_messages;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If last window has a status line now and we don't want one,
|
||||
* remove the status line.
|
||||
*/
|
||||
last_status(FALSE);
|
||||
|
||||
// After closing the help window, try restoring the window layout from
|
||||
// before it was opened.
|
||||
if (help_window)
|
||||
|
||||
Reference in New Issue
Block a user