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:
James McCoy 2017-01-08 23:13:51 -05:00
parent 9fcf6d577f
commit 6520517e22
No known key found for this signature in database
GPG Key ID: DFE691AE331BA3DB
8 changed files with 207 additions and 45 deletions

View File

@ -3070,7 +3070,7 @@ executable({expr}) *executable()*
0 does not exist
-1 not implemented on this system
execute({command}) *execute()*
execute({command} [, {silent}]) *execute()*
Execute {command} and capture its output.
If {command} is a |String|, returns {command} output.
If {command} is a |List|, returns concatenated outputs.
@ -3079,10 +3079,17 @@ execute({command}) *execute()*
< foo >
echo execute(['echon "foo"', 'echon "bar"'])
< 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|.
Note: {command} executes as if prepended with |:silent|
(output is collected but not displayed). If nested, an outer
execute() will not observe output of the inner calls.
Note: If nested, an outer execute() will not observe output of
the inner calls.
Note: Text attributes (highlights) are not captured.
exepath({expr}) *exepath()*
@ -7007,9 +7014,9 @@ synID({lnum}, {col}, {trans}) *synID()*
that's where the cursor can be in Insert mode, synID() returns
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
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
syntax item is effective (e.g. inside parens).
Warning: This function can be very slow. Best speed is

View File

@ -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));
}
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
static void f_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
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;
if (check_secure()) {
@ -8839,23 +8856,45 @@ static void f_execute(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
garray_T capture_local;
ga_init(&capture_local, (int)sizeof(char), 80);
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) {
do_cmdline_cmd((char *)get_tv_string(&argvars[0]));
} else if (argvars[0].vval.v_list != NULL) {
for (listitem_T *li = argvars[0].vval.v_list->lv_first;
li != NULL; li = li->li_next) {
do_cmdline_cmd((char *)get_tv_string(&li->li_tv));
}
list_T *list = argvars[0].vval.v_list;
list->lv_refcount++;
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;
emsg_silent = save_emsg_silent;
emsg_noredir = save_emsg_noredir;
ga_append(capture_ga, NUL);
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;
}

View File

@ -79,7 +79,7 @@ return {
eval={args=1},
eventhandler={},
executable={args=1},
execute={args=1},
execute={args={1, 2}},
exepath={args=1},
exists={args=1},
exp={args=1, func="float_op_wrapper", data="&exp"},

View File

@ -871,6 +871,7 @@ EXTERN cmdmod_T cmdmod; /* Ex command modifiers */
EXTERN int msg_silent INIT(= 0); /* don't print 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 */
/* Values for swap_exists_action: what to do when swap file already exists */

View File

@ -508,20 +508,22 @@ int emsg(char_u *s)
* But do write it to the redirection file.
*/
if (emsg_silent != 0) {
msg_start();
p = get_emsg_source();
if (p != NULL) {
STRCAT(p, "\n");
redir_write(p, STRLEN(p));
xfree(p);
if (!emsg_noredir) {
msg_start();
p = get_emsg_source();
if (p != NULL) {
STRCAT(p, "\n");
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;
}
@ -2508,7 +2510,7 @@ static void redir_write(char_u *str, int maxlen)
int redirecting(void)
{
return redir_fd != NULL || *p_vfile != NUL
|| redir_reg || redir_vname
|| redir_reg || redir_vname || capture_ga != NULL
;
}

View File

@ -4,6 +4,7 @@
source test_assign.vim
source test_autocmd.vim
source test_cursor_func.vim
source test_execute_func.vim
source test_ex_undo.vim
source test_expr.vim
source test_expr_utf8.vim

View 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

View File

@ -7,7 +7,7 @@ local redir_exec = helpers.redir_exec
local exc_exec = helpers.exc_exec
local funcs = helpers.funcs
local Screen = require('test.functional.ui.screen')
local feed = helpers.feed
local command = helpers.command
describe('execute()', function()
before_each(clear)
@ -62,11 +62,11 @@ describe('execute()', function()
ret = exc_exec('call execute(function("tr"))')
eq('Vim(call):E729: using Funcref as a String', ret)
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"])')
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"])')
eq('Vim(call):E729: using Funcref as a String', ret)
eq('Vim:E729: using Funcref as a String', ret)
end)
-- This matches Vim behavior.
@ -74,18 +74,75 @@ describe('execute()', function()
eq('\n:!echo "foo"\13\n', funcs.execute('!echo "foo"'))
end)
it('silences command run inside', function()
local screen = Screen.new(40, 5)
screen:attach()
screen:set_default_attr_ids( {[0] = {bold=true, foreground=255}} )
feed(':let g:mes = execute("echon 42")<CR>')
screen:expect([[
^ |
{0:~ }|
{0:~ }|
{0:~ }|
:let g:mes = execute("echon 42") |
]])
eq('42', eval('g:mes'))
describe('{silent} argument', function()
it('captures & displays output for ""', function()
local screen = Screen.new(40, 5)
screen:attach()
command('let g:mes = execute("echon 42", "")')
screen:expect([[
^ |
~ |
~ |
~ |
42 |
]])
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)