0
0
mirror of https://github.com/vim/vim.git synced 2025-09-26 04:04:07 -04:00

patch 7.4.2008

Problem:    evalcmd() has a confusing name.
Solution:   Rename to execute().  Make silent optional.  Support a list of
            commands.
This commit is contained in:
Bram Moolenaar
2016-07-09 17:07:29 +02:00
parent fc4ad61607
commit 79815f1ec7
10 changed files with 238 additions and 133 deletions

View File

@@ -1,4 +1,4 @@
*eval.txt* For Vim version 7.4. Last change: 2016 Jul 06
*eval.txt* For Vim version 7.4. Last change: 2016 Jul 09
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -1961,9 +1961,9 @@ diff_hlID({lnum}, {col}) Number diff highlighting at {lnum}/{col}
empty({expr}) Number |TRUE| if {expr} is empty
escape({string}, {chars}) String escape {chars} in {string} with '\'
eval({string}) any evaluate {string} into its value
evalcmd({command}) String execute {command} and get the output
eventhandler() Number |TRUE| if inside an event handler
executable({expr}) Number 1 if executable {expr} exists
execute({command}) String execute {command} and get the output
exepath({expr}) String full path of the command {expr}
exists({expr}) Number |TRUE| if {expr} exists
extend({expr1}, {expr2} [, {expr3}])
@@ -3232,15 +3232,6 @@ eval({string}) Evaluate {string} and return the result. Especially useful to
them. Also works for |Funcref|s that refer to existing
functions.
evalcmd({command}) *evalcmd()*
Execute Ex {command} and return the output as a string. This
is equivalent to: >
redir => var
{command}
redir END
< To get a list of lines use: >
split(evalcmd(cmd), "\n")
eventhandler() *eventhandler()*
Returns 1 when inside an event handler. That is that Vim got
interrupted while waiting for the user to type a character,
@@ -3271,6 +3262,31 @@ executable({expr}) *executable()*
0 does not exist
-1 not implemented on this system
execute({command} [, {silent}]) *execute()*
Execute an Ex command or commands and return the output as a
string.
{command} can be a string or a List. In case of a List the
lines are executed one by one.
This is equivalent to: >
redir => var
{command}
redir END
<
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.
*E930*
It is not possible to use `:redir` anywhere in {command}.
To get a list of lines use |split()| on the result: >
split(evalcmd('args'), "\n")
< When used recursively the output of the recursive call is not
included in the output of the higher level call.
exepath({expr}) *exepath()*
If {expr} is an executable and is either an absolute path, a
relative path or found in $PATH, return the full path.
@@ -7046,9 +7062,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

@@ -2023,8 +2023,8 @@ test_arglist \
test_cmdline \
test_cursor_func \
test_delete \
test_evalcmd \
test_ex_undo \
test_execute_func \
test_expand \
test_expand_dllpath \
test_expr \

View File

@@ -555,9 +555,9 @@ static void f_diff_hlID(typval_T *argvars, typval_T *rettv);
static void f_empty(typval_T *argvars, typval_T *rettv);
static void f_escape(typval_T *argvars, typval_T *rettv);
static void f_eval(typval_T *argvars, typval_T *rettv);
static void f_evalcmd(typval_T *argvars, typval_T *rettv);
static void f_eventhandler(typval_T *argvars, typval_T *rettv);
static void f_executable(typval_T *argvars, typval_T *rettv);
static void f_execute(typval_T *argvars, typval_T *rettv);
static void f_exepath(typval_T *argvars, typval_T *rettv);
static void f_exists(typval_T *argvars, typval_T *rettv);
#ifdef FEAT_FLOAT
@@ -8564,9 +8564,9 @@ static struct fst
{"empty", 1, 1, f_empty},
{"escape", 2, 2, f_escape},
{"eval", 1, 1, f_eval},
{"evalcmd", 1, 1, f_evalcmd},
{"eventhandler", 0, 0, f_eventhandler},
{"executable", 1, 1, f_executable},
{"execute", 1, 2, f_execute},
{"exepath", 1, 1, f_exepath},
{"exists", 1, 1, f_exists},
#ifdef FEAT_FLOAT
@@ -11345,65 +11345,6 @@ f_eval(typval_T *argvars, typval_T *rettv)
EMSG(_(e_trailing));
}
static garray_T redir_evalcmd_ga;
/*
* Append "value[value_len]" to the evalcmd() output.
*/
void
evalcmd_redir_str(char_u *value, int value_len)
{
int len;
if (value_len == -1)
len = (int)STRLEN(value); /* Append the entire string */
else
len = value_len; /* Append only "value_len" characters */
if (ga_grow(&redir_evalcmd_ga, len) == OK)
{
mch_memmove((char *)redir_evalcmd_ga.ga_data
+ redir_evalcmd_ga.ga_len, value, len);
redir_evalcmd_ga.ga_len += len;
}
}
/*
* "evalcmd()" function
*/
static void
f_evalcmd(typval_T *argvars, typval_T *rettv)
{
char_u *s;
int save_msg_silent = msg_silent;
int save_redir_evalcmd = redir_evalcmd;
garray_T save_ga;
rettv->vval.v_string = NULL;
rettv->v_type = VAR_STRING;
s = get_tv_string_chk(&argvars[0]);
if (s != NULL)
{
if (redir_evalcmd)
save_ga = redir_evalcmd_ga;
ga_init2(&redir_evalcmd_ga, (int)sizeof(char), 500);
redir_evalcmd = TRUE;
++msg_silent;
do_cmdline_cmd(s);
rettv->vval.v_string = redir_evalcmd_ga.ga_data;
msg_silent = save_msg_silent;
redir_evalcmd = save_redir_evalcmd;
if (redir_evalcmd)
redir_evalcmd_ga = save_ga;
/* "silent reg" or "silent echo x" leaves msg_col somewhere in the
* line. Put it back in the first column. */
msg_col = 0;
}
}
/*
* "eventhandler()" function
*/
@@ -11426,6 +11367,132 @@ f_executable(typval_T *argvars, typval_T *rettv)
|| (gettail(name) != name && mch_can_exe(name, NULL, FALSE));
}
static garray_T redir_execute_ga;
/*
* Append "value[value_len]" to the execute() output.
*/
void
execute_redir_str(char_u *value, int value_len)
{
int len;
if (value_len == -1)
len = (int)STRLEN(value); /* Append the entire string */
else
len = value_len; /* Append only "value_len" characters */
if (ga_grow(&redir_execute_ga, len) == OK)
{
mch_memmove((char *)redir_execute_ga.ga_data
+ redir_execute_ga.ga_len, value, len);
redir_execute_ga.ga_len += len;
}
}
/*
* Get next line from a list.
* Called by do_cmdline() to get the next line.
* Returns allocated string, or NULL for end of function.
*/
static char_u *
get_list_line(
int c UNUSED,
void *cookie,
int indent UNUSED)
{
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()" function
*/
static void
f_execute(typval_T *argvars, typval_T *rettv)
{
char_u *cmd = NULL;
list_T *list = NULL;
int save_msg_silent = msg_silent;
int save_emsg_silent = emsg_silent;
int save_emsg_noredir = emsg_noredir;
int save_redir_execute = redir_execute;
garray_T save_ga;
rettv->vval.v_string = NULL;
rettv->v_type = VAR_STRING;
if (argvars[0].v_type == VAR_LIST)
{
list = argvars[0].vval.v_list;
if (list == NULL || list->lv_first == NULL)
/* empty list, no commands, empty output */
return;
++list->lv_refcount;
}
else
{
cmd = get_tv_string_chk(&argvars[0]);
if (cmd == NULL)
return;
}
if (redir_execute)
save_ga = redir_execute_ga;
ga_init2(&redir_execute_ga, (int)sizeof(char), 500);
redir_execute = TRUE;
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 (cmd != NULL)
do_cmdline_cmd(cmd);
else
{
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;
}
rettv->vval.v_string = redir_execute_ga.ga_data;
msg_silent = save_msg_silent;
emsg_silent = save_emsg_silent;
emsg_noredir = save_emsg_noredir;
redir_execute = save_redir_execute;
if (redir_execute)
redir_execute_ga = save_ga;
/* "silent reg" or "silent echo x" leaves msg_col somewhere in the
* line. Put it back in the first column. */
msg_col = 0;
}
/*
* "exepath()" function
*/

View File

@@ -9456,9 +9456,9 @@ ex_redir(exarg_T *eap)
char_u *arg = eap->arg;
#ifdef FEAT_EVAL
if (redir_evalcmd)
if (redir_execute)
{
EMSG(_("E930: Cannot use :redir inside evalcmd()"));
EMSG(_("E930: Cannot use :redir inside execute()"));
return;
}
#endif

View File

@@ -971,6 +971,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 int emsg_noredir INIT(= 0); /* don't redirect error messages */
EXTERN int cmd_silent INIT(= FALSE); /* don't echo the command line */
#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG) \
@@ -1106,7 +1107,7 @@ EXTERN FILE *redir_fd INIT(= NULL); /* message redirection file */
#ifdef FEAT_EVAL
EXTERN int redir_reg INIT(= 0); /* message redirection register */
EXTERN int redir_vname INIT(= 0); /* message redirection variable */
EXTERN int redir_evalcmd INIT(= 0); /* evalcmd() redirection */
EXTERN int redir_execute INIT(= 0); /* execute() redirection */
#endif
#ifdef FEAT_LANGMAP

View File

@@ -566,22 +566,25 @@ emsg(char_u *s)
*/
if (emsg_silent != 0)
{
msg_start();
p = get_emsg_source();
if (p != NULL)
if (emsg_noredir == 0)
{
STRCAT(p, "\n");
redir_write(p, -1);
vim_free(p);
msg_start();
p = get_emsg_source();
if (p != NULL)
{
STRCAT(p, "\n");
redir_write(p, -1);
vim_free(p);
}
p = get_emsg_lnum();
if (p != NULL)
{
STRCAT(p, "\n");
redir_write(p, -1);
vim_free(p);
}
redir_write(s, -1);
}
p = get_emsg_lnum();
if (p != NULL)
{
STRCAT(p, "\n");
redir_write(p, -1);
vim_free(p);
}
redir_write(s, -1);
return TRUE;
}
@@ -3063,8 +3066,8 @@ redir_write(char_u *str, int maxlen)
while (cur_col < msg_col)
{
#ifdef FEAT_EVAL
if (redir_evalcmd)
evalcmd_redir_str((char_u *)" ", -1);
if (redir_execute)
execute_redir_str((char_u *)" ", -1);
else if (redir_reg)
write_reg_contents(redir_reg, (char_u *)" ", -1, TRUE);
else if (redir_vname)
@@ -3080,8 +3083,8 @@ redir_write(char_u *str, int maxlen)
}
#ifdef FEAT_EVAL
if (redir_evalcmd)
evalcmd_redir_str(s, maxlen);
if (redir_execute)
execute_redir_str(s, maxlen);
else if (redir_reg)
write_reg_contents(redir_reg, s, maxlen, TRUE);
else if (redir_vname)
@@ -3092,7 +3095,7 @@ redir_write(char_u *str, int maxlen)
while (*s != NUL && (maxlen < 0 || (int)(s - str) < maxlen))
{
#ifdef FEAT_EVAL
if (!redir_reg && !redir_vname && !redir_evalcmd)
if (!redir_reg && !redir_vname && !redir_execute)
#endif
if (redir_fd != NULL)
putc(*s, redir_fd);
@@ -3117,7 +3120,7 @@ redirecting(void)
{
return redir_fd != NULL || *p_vfile != NUL
#ifdef FEAT_EVAL
|| redir_reg || redir_vname || redir_evalcmd
|| redir_reg || redir_vname || redir_execute
#endif
;
}

View File

@@ -88,7 +88,7 @@ char_u *get_expr_name(expand_T *xp, int idx);
int call_func(char_u *funcname, int len, typval_T *rettv, int argcount_in, typval_T *argvars_in, linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate, partial_T *partial, dict_T *selfdict_in);
buf_T *buflist_find_by_name(char_u *name, int curtab_only);
int func_call(char_u *name, typval_T *args, partial_T *partial, dict_T *selfdict, typval_T *rettv);
void evalcmd_redir_str(char_u *value, int value_len);
void execute_redir_str(char_u *value, int value_len);
void dict_extend(dict_T *d1, dict_T *d2, char_u *action);
void mzscheme_call_vim(char_u *name, typval_T *args, typval_T *rettv);
float_T vim_round(float_T f);

View File

@@ -5,7 +5,7 @@ source test_assign.vim
source test_autocmd.vim
source test_cursor_func.vim
source test_delete.vim
source test_evalcmd.vim
source test_execute_func.vim
source test_ex_undo.vim
source test_expand.vim
source test_expr.vim

View File

@@ -1,33 +0,0 @@
" test evalcmd()
func NestedEval()
let nested = evalcmd('echo "nested\nlines"')
echo 'got: "' . nested . '"'
endfunc
func NestedRedir()
redir => var
echo 'broken'
redir END
endfunc
func Test_evalcmd()
call assert_equal("\nnocompatible", evalcmd('set compatible?'))
call assert_equal("\nsomething\nnice", evalcmd('echo "something\nnice"'))
call assert_equal("noendofline", evalcmd('echon "noendofline"'))
call assert_equal("", evalcmd(123))
call assert_equal("\ngot: \"\nnested\nlines\"", evalcmd('call NestedEval()'))
redir => redired
echo 'this'
let evaled = evalcmd('echo "that"')
echo 'theend'
redir END
call assert_equal("\nthis\ntheend", redired)
call assert_equal("\nthat", evaled)
call assert_fails('call evalcmd("doesnotexist")', 'E492:')
call assert_fails('call evalcmd(3.4)', 'E806:')
call assert_fails('call evalcmd("call NestedRedir()")', 'E930:')
endfunc

View File

@@ -0,0 +1,51 @@
" 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
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:')
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(test_null_string()))
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(test_null_list()))
endfunc