mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
vim-patch:7.4.2008
Problem: evalcmd() has a confusing name.
Solution: Rename to execute(). Make silent optional. Support a list of
commands.
79815f1ec7
This commit is contained in:
parent
9fcf6d577f
commit
6520517e22
@ -3070,7 +3070,7 @@ executable({expr}) *executable()*
|
|||||||
0 does not exist
|
0 does not exist
|
||||||
-1 not implemented on this system
|
-1 not implemented on this system
|
||||||
|
|
||||||
execute({command}) *execute()*
|
execute({command} [, {silent}]) *execute()*
|
||||||
Execute {command} and capture its output.
|
Execute {command} and capture its output.
|
||||||
If {command} is a |String|, returns {command} output.
|
If {command} is a |String|, returns {command} output.
|
||||||
If {command} is a |List|, returns concatenated outputs.
|
If {command} is a |List|, returns concatenated outputs.
|
||||||
@ -3079,10 +3079,17 @@ execute({command}) *execute()*
|
|||||||
< foo >
|
< foo >
|
||||||
echo execute(['echon "foo"', 'echon "bar"'])
|
echo execute(['echon "foo"', 'echon "bar"'])
|
||||||
< foobar
|
< foobar
|
||||||
|
|
||||||
|
The optional {silent} argument can have these values:
|
||||||
|
"" no `:silent` used
|
||||||
|
"silent" `:silent` used
|
||||||
|
"silent!" `:silent!` used
|
||||||
|
The default is 'silent'. Note that with "silent!", unlike
|
||||||
|
`:redir`, error messages are dropped.
|
||||||
|
|
||||||
This function is not available in the |sandbox|.
|
This function is not available in the |sandbox|.
|
||||||
Note: {command} executes as if prepended with |:silent|
|
Note: If nested, an outer execute() will not observe output of
|
||||||
(output is collected but not displayed). If nested, an outer
|
the inner calls.
|
||||||
execute() will not observe output of the inner calls.
|
|
||||||
Note: Text attributes (highlights) are not captured.
|
Note: Text attributes (highlights) are not captured.
|
||||||
|
|
||||||
exepath({expr}) *exepath()*
|
exepath({expr}) *exepath()*
|
||||||
@ -7007,9 +7014,9 @@ synID({lnum}, {col}, {trans}) *synID()*
|
|||||||
that's where the cursor can be in Insert mode, synID() returns
|
that's where the cursor can be in Insert mode, synID() returns
|
||||||
zero.
|
zero.
|
||||||
|
|
||||||
When {trans} is non-zero, transparent items are reduced to the
|
When {trans} is |TRUE|, transparent items are reduced to the
|
||||||
item that they reveal. This is useful when wanting to know
|
item that they reveal. This is useful when wanting to know
|
||||||
the effective color. When {trans} is zero, the transparent
|
the effective color. When {trans} is |FALSE|, the transparent
|
||||||
item is returned. This is useful when wanting to know which
|
item is returned. This is useful when wanting to know which
|
||||||
syntax item is effective (e.g. inside parens).
|
syntax item is effective (e.g. inside parens).
|
||||||
Warning: This function can be very slow. Best speed is
|
Warning: This function can be very slow. Best speed is
|
||||||
|
@ -8828,10 +8828,27 @@ static void f_executable(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||||||
|| (gettail_dir(name) != name && os_can_exe(name, NULL, false));
|
|| (gettail_dir(name) != name && os_can_exe(name, NULL, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char_u * get_list_line(int c, void *cookie, int indent)
|
||||||
|
{
|
||||||
|
listitem_T **p = (listitem_T **)cookie;
|
||||||
|
listitem_T *item = *p;
|
||||||
|
char_u buf[NUMBUFLEN];
|
||||||
|
char_u *s;
|
||||||
|
|
||||||
|
if (item == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
s = get_tv_string_buf_chk(&item->li_tv, buf);
|
||||||
|
*p = item->li_next;
|
||||||
|
return s == NULL ? NULL : vim_strsave(s);
|
||||||
|
}
|
||||||
|
|
||||||
// "execute(command)" function
|
// "execute(command)" function
|
||||||
static void f_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
static void f_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
||||||
{
|
{
|
||||||
int save_msg_silent = msg_silent;
|
int save_msg_silent = msg_silent;
|
||||||
|
int save_emsg_silent = emsg_silent;
|
||||||
|
bool save_emsg_noredir = emsg_noredir;
|
||||||
garray_T *save_capture_ga = capture_ga;
|
garray_T *save_capture_ga = capture_ga;
|
||||||
|
|
||||||
if (check_secure()) {
|
if (check_secure()) {
|
||||||
@ -8839,23 +8856,45 @@ static void f_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
garray_T capture_local;
|
garray_T capture_local;
|
||||||
|
ga_init(&capture_local, (int)sizeof(char), 80);
|
||||||
capture_ga = &capture_local;
|
capture_ga = &capture_local;
|
||||||
ga_init(capture_ga, (int)sizeof(char), 80);
|
|
||||||
|
|
||||||
msg_silent++;
|
if (argvars[1].v_type != VAR_UNKNOWN) {
|
||||||
|
char_u buf[NUMBUFLEN];
|
||||||
|
char_u *s = get_tv_string_buf_chk(&argvars[1], buf);
|
||||||
|
|
||||||
|
if (s == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (STRNCMP(s, "silent", 6) == 0) {
|
||||||
|
msg_silent++;
|
||||||
|
}
|
||||||
|
if (STRCMP(s, "silent!") == 0) {
|
||||||
|
emsg_silent = true;
|
||||||
|
emsg_noredir = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
msg_silent++;
|
||||||
|
}
|
||||||
|
|
||||||
if (argvars[0].v_type != VAR_LIST) {
|
if (argvars[0].v_type != VAR_LIST) {
|
||||||
do_cmdline_cmd((char *)get_tv_string(&argvars[0]));
|
do_cmdline_cmd((char *)get_tv_string(&argvars[0]));
|
||||||
} else if (argvars[0].vval.v_list != NULL) {
|
} else if (argvars[0].vval.v_list != NULL) {
|
||||||
for (listitem_T *li = argvars[0].vval.v_list->lv_first;
|
list_T *list = argvars[0].vval.v_list;
|
||||||
li != NULL; li = li->li_next) {
|
list->lv_refcount++;
|
||||||
do_cmdline_cmd((char *)get_tv_string(&li->li_tv));
|
listitem_T *item = list->lv_first;
|
||||||
}
|
do_cmdline(NULL, get_list_line, (void *)&item,
|
||||||
|
DOCMD_NOWAIT|DOCMD_VERBOSE|DOCMD_REPEAT|DOCMD_KEYTYPED);
|
||||||
|
list->lv_refcount--;
|
||||||
}
|
}
|
||||||
msg_silent = save_msg_silent;
|
msg_silent = save_msg_silent;
|
||||||
|
emsg_silent = save_emsg_silent;
|
||||||
|
emsg_noredir = save_emsg_noredir;
|
||||||
|
|
||||||
ga_append(capture_ga, NUL);
|
ga_append(capture_ga, NUL);
|
||||||
rettv->v_type = VAR_STRING;
|
rettv->v_type = VAR_STRING;
|
||||||
rettv->vval.v_string = capture_ga->ga_data;
|
rettv->vval.v_string = vim_strsave(capture_ga->ga_data);
|
||||||
|
ga_clear(capture_ga);
|
||||||
|
|
||||||
capture_ga = save_capture_ga;
|
capture_ga = save_capture_ga;
|
||||||
}
|
}
|
||||||
|
@ -79,7 +79,7 @@ return {
|
|||||||
eval={args=1},
|
eval={args=1},
|
||||||
eventhandler={},
|
eventhandler={},
|
||||||
executable={args=1},
|
executable={args=1},
|
||||||
execute={args=1},
|
execute={args={1, 2}},
|
||||||
exepath={args=1},
|
exepath={args=1},
|
||||||
exists={args=1},
|
exists={args=1},
|
||||||
exp={args=1, func="float_op_wrapper", data="&exp"},
|
exp={args=1, func="float_op_wrapper", data="&exp"},
|
||||||
|
@ -871,6 +871,7 @@ EXTERN cmdmod_T cmdmod; /* Ex command modifiers */
|
|||||||
|
|
||||||
EXTERN int msg_silent INIT(= 0); /* don't print messages */
|
EXTERN int msg_silent INIT(= 0); /* don't print messages */
|
||||||
EXTERN int emsg_silent INIT(= 0); /* don't print error messages */
|
EXTERN int emsg_silent INIT(= 0); /* don't print error messages */
|
||||||
|
EXTERN bool emsg_noredir INIT(= false); // don't redirect error messages
|
||||||
EXTERN int cmd_silent INIT(= FALSE); /* don't echo the command line */
|
EXTERN int cmd_silent INIT(= FALSE); /* don't echo the command line */
|
||||||
|
|
||||||
/* Values for swap_exists_action: what to do when swap file already exists */
|
/* Values for swap_exists_action: what to do when swap file already exists */
|
||||||
|
@ -508,20 +508,22 @@ int emsg(char_u *s)
|
|||||||
* But do write it to the redirection file.
|
* But do write it to the redirection file.
|
||||||
*/
|
*/
|
||||||
if (emsg_silent != 0) {
|
if (emsg_silent != 0) {
|
||||||
msg_start();
|
if (!emsg_noredir) {
|
||||||
p = get_emsg_source();
|
msg_start();
|
||||||
if (p != NULL) {
|
p = get_emsg_source();
|
||||||
STRCAT(p, "\n");
|
if (p != NULL) {
|
||||||
redir_write(p, STRLEN(p));
|
STRCAT(p, "\n");
|
||||||
xfree(p);
|
redir_write(p, STRLEN(p));
|
||||||
|
xfree(p);
|
||||||
|
}
|
||||||
|
p = get_emsg_lnum();
|
||||||
|
if (p != NULL) {
|
||||||
|
STRCAT(p, "\n");
|
||||||
|
redir_write(p, STRLEN(p));
|
||||||
|
xfree(p);
|
||||||
|
}
|
||||||
|
redir_write(s, STRLEN(s));
|
||||||
}
|
}
|
||||||
p = get_emsg_lnum();
|
|
||||||
if (p != NULL) {
|
|
||||||
STRCAT(p, "\n");
|
|
||||||
redir_write(p, STRLEN(p));
|
|
||||||
xfree(p);
|
|
||||||
}
|
|
||||||
redir_write(s, STRLEN(s));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2508,7 +2510,7 @@ static void redir_write(char_u *str, int maxlen)
|
|||||||
int redirecting(void)
|
int redirecting(void)
|
||||||
{
|
{
|
||||||
return redir_fd != NULL || *p_vfile != NUL
|
return redir_fd != NULL || *p_vfile != NUL
|
||||||
|| redir_reg || redir_vname
|
|| redir_reg || redir_vname || capture_ga != NULL
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
source test_assign.vim
|
source test_assign.vim
|
||||||
source test_autocmd.vim
|
source test_autocmd.vim
|
||||||
source test_cursor_func.vim
|
source test_cursor_func.vim
|
||||||
|
source test_execute_func.vim
|
||||||
source test_ex_undo.vim
|
source test_ex_undo.vim
|
||||||
source test_expr.vim
|
source test_expr.vim
|
||||||
source test_expr_utf8.vim
|
source test_expr_utf8.vim
|
||||||
|
55
src/nvim/testdir/test_execute_func.vim
Normal file
55
src/nvim/testdir/test_execute_func.vim
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
" test execute()
|
||||||
|
|
||||||
|
func NestedEval()
|
||||||
|
let nested = execute('echo "nested\nlines"')
|
||||||
|
echo 'got: "' . nested . '"'
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func NestedRedir()
|
||||||
|
redir => var
|
||||||
|
echo 'broken'
|
||||||
|
redir END
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func Test_execute_string()
|
||||||
|
call assert_equal("\nnocompatible", execute('set compatible?'))
|
||||||
|
call assert_equal("\nsomething\nnice", execute('echo "something\nnice"'))
|
||||||
|
call assert_equal("noendofline", execute('echon "noendofline"'))
|
||||||
|
call assert_equal("", execute(123))
|
||||||
|
|
||||||
|
call assert_equal("\ngot: \"\nnested\nlines\"", execute('call NestedEval()'))
|
||||||
|
redir => redired
|
||||||
|
echo 'this'
|
||||||
|
let evaled = execute('echo "that"')
|
||||||
|
echo 'theend'
|
||||||
|
redir END
|
||||||
|
" Nvim supports execute('... :redir ...'), so this test is intentionally
|
||||||
|
" disabled.
|
||||||
|
" call assert_equal("\nthis\ntheend", redired)
|
||||||
|
call assert_equal("\nthat", evaled)
|
||||||
|
|
||||||
|
call assert_fails('call execute("doesnotexist")', 'E492:')
|
||||||
|
call assert_fails('call execute(3.4)', 'E806:')
|
||||||
|
" Nvim supports execute('... :redir ...'), so this test is intentionally
|
||||||
|
" disabled.
|
||||||
|
" call assert_fails('call execute("call NestedRedir()")', 'E930:')
|
||||||
|
|
||||||
|
call assert_equal("\nsomething", execute('echo "something"', ''))
|
||||||
|
call assert_equal("\nsomething", execute('echo "something"', 'silent'))
|
||||||
|
call assert_equal("\nsomething", execute('echo "something"', 'silent!'))
|
||||||
|
call assert_equal("", execute('burp', 'silent!'))
|
||||||
|
call assert_fails('call execute("echo \"x\"", 3.4)', 'E806:')
|
||||||
|
|
||||||
|
call assert_equal("", execute(""))
|
||||||
|
endfunc
|
||||||
|
|
||||||
|
func Test_execute_list()
|
||||||
|
call assert_equal("\nsomething\nnice", execute(['echo "something"', 'echo "nice"']))
|
||||||
|
let l = ['for n in range(0, 3)',
|
||||||
|
\ 'echo n',
|
||||||
|
\ 'endfor']
|
||||||
|
call assert_equal("\n0\n1\n2\n3", execute(l))
|
||||||
|
|
||||||
|
call assert_equal("", execute([]))
|
||||||
|
call assert_equal("", execute(v:_null_list))
|
||||||
|
endfunc
|
@ -7,7 +7,7 @@ local redir_exec = helpers.redir_exec
|
|||||||
local exc_exec = helpers.exc_exec
|
local exc_exec = helpers.exc_exec
|
||||||
local funcs = helpers.funcs
|
local funcs = helpers.funcs
|
||||||
local Screen = require('test.functional.ui.screen')
|
local Screen = require('test.functional.ui.screen')
|
||||||
local feed = helpers.feed
|
local command = helpers.command
|
||||||
|
|
||||||
describe('execute()', function()
|
describe('execute()', function()
|
||||||
before_each(clear)
|
before_each(clear)
|
||||||
@ -62,11 +62,11 @@ describe('execute()', function()
|
|||||||
ret = exc_exec('call execute(function("tr"))')
|
ret = exc_exec('call execute(function("tr"))')
|
||||||
eq('Vim(call):E729: using Funcref as a String', ret)
|
eq('Vim(call):E729: using Funcref as a String', ret)
|
||||||
ret = exc_exec('call execute(["echo 42", 0.0, "echo 44"])')
|
ret = exc_exec('call execute(["echo 42", 0.0, "echo 44"])')
|
||||||
eq('Vim(call):E806: using Float as a String', ret)
|
eq('Vim:E806: using Float as a String', ret)
|
||||||
ret = exc_exec('call execute(["echo 42", v:_null_dict, "echo 44"])')
|
ret = exc_exec('call execute(["echo 42", v:_null_dict, "echo 44"])')
|
||||||
eq('Vim(call):E731: using Dictionary as a String', ret)
|
eq('Vim:E731: using Dictionary as a String', ret)
|
||||||
ret = exc_exec('call execute(["echo 42", function("tr"), "echo 44"])')
|
ret = exc_exec('call execute(["echo 42", function("tr"), "echo 44"])')
|
||||||
eq('Vim(call):E729: using Funcref as a String', ret)
|
eq('Vim:E729: using Funcref as a String', ret)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
-- This matches Vim behavior.
|
-- This matches Vim behavior.
|
||||||
@ -74,18 +74,75 @@ describe('execute()', function()
|
|||||||
eq('\n:!echo "foo"\13\n', funcs.execute('!echo "foo"'))
|
eq('\n:!echo "foo"\13\n', funcs.execute('!echo "foo"'))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('silences command run inside', function()
|
describe('{silent} argument', function()
|
||||||
local screen = Screen.new(40, 5)
|
it('captures & displays output for ""', function()
|
||||||
screen:attach()
|
local screen = Screen.new(40, 5)
|
||||||
screen:set_default_attr_ids( {[0] = {bold=true, foreground=255}} )
|
screen:attach()
|
||||||
feed(':let g:mes = execute("echon 42")<CR>')
|
command('let g:mes = execute("echon 42", "")')
|
||||||
screen:expect([[
|
screen:expect([[
|
||||||
^ |
|
^ |
|
||||||
{0:~ }|
|
~ |
|
||||||
{0:~ }|
|
~ |
|
||||||
{0:~ }|
|
~ |
|
||||||
:let g:mes = execute("echon 42") |
|
42 |
|
||||||
]])
|
]])
|
||||||
eq('42', eval('g:mes'))
|
eq('42', eval('g:mes'))
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('captures but does not display output for "silent"', function()
|
||||||
|
local screen = Screen.new(40, 5)
|
||||||
|
screen:attach()
|
||||||
|
command('let g:mes = execute("echon 42")')
|
||||||
|
screen:expect([[
|
||||||
|
^ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
eq('42', eval('g:mes'))
|
||||||
|
|
||||||
|
command('let g:mes = execute("echon 13", "silent")')
|
||||||
|
screen:expect([[
|
||||||
|
^ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
|
|
||||||
|
]])
|
||||||
|
eq('13', eval('g:mes'))
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('suppresses errors for "silent!"', function()
|
||||||
|
eq(0, exc_exec('let g:mes = execute(0.0, "silent!")'))
|
||||||
|
eq('', eval('g:mes'))
|
||||||
|
|
||||||
|
eq(0, exc_exec('let g:mes = execute("echon add(1, 1)", "silent!")'))
|
||||||
|
eq('1', eval('g:mes'))
|
||||||
|
|
||||||
|
eq(0, exc_exec('let g:mes = execute(["echon 42", "echon add(1, 1)"], "silent!")'))
|
||||||
|
eq('421', eval('g:mes'))
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('propagates errors for "" and "silent"', function()
|
||||||
|
local ret
|
||||||
|
ret = exc_exec('call execute(0.0, "")')
|
||||||
|
eq('Vim(call):E806: using Float as a String', ret)
|
||||||
|
|
||||||
|
ret = exc_exec('call execute(v:_null_dict, "silent")')
|
||||||
|
eq('Vim(call):E731: using Dictionary as a String', ret)
|
||||||
|
|
||||||
|
ret = exc_exec('call execute("echo add(1, 1)", "")')
|
||||||
|
eq('Vim(echo):E714: List required', ret)
|
||||||
|
|
||||||
|
ret = exc_exec('call execute(["echon 42", "echo add(1, 1)"], "")')
|
||||||
|
eq('Vim(echo):E714: List required', ret)
|
||||||
|
|
||||||
|
ret = exc_exec('call execute("echo add(1, 1)", "silent")')
|
||||||
|
eq('Vim(echo):E714: List required', ret)
|
||||||
|
|
||||||
|
ret = exc_exec('call execute(["echon 42", "echo add(1, 1)"], "silent")')
|
||||||
|
eq('Vim(echo):E714: List required', ret)
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
Loading…
Reference in New Issue
Block a user