mirror of
https://github.com/neovim/neovim.git
synced 2024-12-20 03:05:11 -07:00
Merge #4697 'capture() function'.
This commit is contained in:
commit
8a4e5b4bc2
@ -1813,6 +1813,7 @@ byteidx({expr}, {nr}) Number byte index of {nr}'th char in {expr}
|
||||
byteidxcomp({expr}, {nr}) Number byte index of {nr}'th char in {expr}
|
||||
call({func}, {arglist} [, {dict}])
|
||||
any call {func} with arguments {arglist}
|
||||
capture({command}) String capture output of {command}
|
||||
ceil({expr}) Float round {expr} up
|
||||
changenr() Number current change number
|
||||
char2nr({expr}[, {utf8}]) Number ASCII/UTF8 value of first char in {expr}
|
||||
@ -2496,6 +2497,23 @@ call({func}, {arglist} [, {dict}]) *call()* *E699*
|
||||
{dict} is for functions with the "dict" attribute. It will be
|
||||
used to set the local variable "self". |Dictionary-function|
|
||||
|
||||
capture({command}) *capture()*
|
||||
Capture output of {command}.
|
||||
If {command} is a |String|, returns {command} output.
|
||||
If {command} is a |List|, returns concatenated outputs.
|
||||
Examples: >
|
||||
echo capture('echon "foo"')
|
||||
< foo >
|
||||
echo capture(['echon "foo"', 'echon "bar"'])
|
||||
< foobar
|
||||
This function is not available in the |sandbox|.
|
||||
Note: {command}s run as if prepended with |:silent| (output is
|
||||
captured, but not displayed). If multiple capture() calls are
|
||||
nested, the outer capture() will not catch the command output
|
||||
of the inner capture(); the inner capture will not cancel the
|
||||
outer.
|
||||
Note: Text attributes (highlights) are not captured.
|
||||
|
||||
ceil({expr}) *ceil()*
|
||||
Return the smallest integral value greater than or equal to
|
||||
{expr} as a |Float| (round up).
|
||||
|
@ -415,8 +415,9 @@ m *+xpm_w32* Win32 GUI only: pixmap support |w32-xpm-support|
|
||||
To stop the messages and commands from being echoed to
|
||||
the screen, put the commands in a function and call it
|
||||
with ":silent call Function()".
|
||||
An alternative is to use the 'verbosefile' option,
|
||||
this can be used in combination with ":redir".
|
||||
Alternatives are the 'verbosefile' option or
|
||||
|capture()| function, these can be used in combination
|
||||
with ":redir".
|
||||
|
||||
:redi[r] >> {file} Redirect messages to file {file}. Append if {file}
|
||||
already exists.
|
||||
|
@ -6713,6 +6713,7 @@ static struct fst {
|
||||
{ "byteidx", 2, 2, f_byteidx },
|
||||
{ "byteidxcomp", 2, 2, f_byteidxcomp },
|
||||
{ "call", 2, 3, f_call },
|
||||
{ "capture", 1, 1, f_capture },
|
||||
{ "ceil", 1, 1, f_ceil },
|
||||
{ "changenr", 0, 0, f_changenr },
|
||||
{ "char2nr", 1, 2, f_char2nr },
|
||||
@ -8083,6 +8084,38 @@ static void f_call(typval_T *argvars, typval_T *rettv)
|
||||
(void)func_call(func, &argvars[1], selfdict, rettv);
|
||||
}
|
||||
|
||||
// "capture(command)" function
|
||||
static void f_capture(typval_T *argvars, typval_T *rettv)
|
||||
{
|
||||
int save_msg_silent = msg_silent;
|
||||
garray_T *save_capture_ga = capture_ga;
|
||||
|
||||
if (check_secure()) {
|
||||
return;
|
||||
}
|
||||
|
||||
garray_T capture_local;
|
||||
capture_ga = &capture_local;
|
||||
ga_init(capture_ga, (int)sizeof(char), 80);
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
msg_silent = save_msg_silent;
|
||||
|
||||
ga_append(capture_ga, NUL);
|
||||
rettv->v_type = VAR_STRING;
|
||||
rettv->vval.v_string = capture_ga->ga_data;
|
||||
|
||||
capture_ga = save_capture_ga;
|
||||
}
|
||||
|
||||
/*
|
||||
* "ceil({float})" function
|
||||
*/
|
||||
|
@ -985,10 +985,11 @@ EXTERN int keep_help_flag INIT(= FALSE); /* doing :ta from help file */
|
||||
*/
|
||||
EXTERN char_u *empty_option INIT(= (char_u *)"");
|
||||
|
||||
EXTERN int redir_off INIT(= FALSE); /* no redirection for a moment */
|
||||
EXTERN FILE *redir_fd INIT(= NULL); /* message redirection file */
|
||||
EXTERN int redir_reg INIT(= 0); /* message redirection register */
|
||||
EXTERN int redir_vname INIT(= 0); /* message redirection variable */
|
||||
EXTERN int redir_off INIT(= false); // no redirection for a moment
|
||||
EXTERN FILE *redir_fd INIT(= NULL); // message redirection file
|
||||
EXTERN int redir_reg INIT(= 0); // message redirection register
|
||||
EXTERN int redir_vname INIT(= 0); // message redirection variable
|
||||
EXTERN garray_T *capture_ga INIT(= NULL); // capture() buffer
|
||||
|
||||
EXTERN char_u langmap_mapchar[256]; /* mapping for language keys */
|
||||
|
||||
|
@ -2392,6 +2392,19 @@ static void redir_write(char_u *str, int maxlen)
|
||||
char_u *s = str;
|
||||
static int cur_col = 0;
|
||||
|
||||
if (maxlen == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Append output to capture().
|
||||
if (capture_ga) {
|
||||
size_t len = 0;
|
||||
while (str[len] && (maxlen < 0 ? 1 : (len < (size_t)maxlen))) {
|
||||
len++;
|
||||
}
|
||||
ga_concat_len(capture_ga, (const char *)str, len);
|
||||
}
|
||||
|
||||
/* Don't do anything for displaying prompts and the like. */
|
||||
if (redir_off)
|
||||
return;
|
||||
|
86
test/functional/eval/capture_spec.lua
Normal file
86
test/functional/eval/capture_spec.lua
Normal file
@ -0,0 +1,86 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local eq = helpers.eq
|
||||
local eval = helpers.eval
|
||||
local clear = helpers.clear
|
||||
local source = helpers.source
|
||||
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
|
||||
|
||||
describe('capture()', function()
|
||||
before_each(clear)
|
||||
|
||||
it('returns the same result with :redir', function()
|
||||
eq(redir_exec('messages'), funcs.capture('messages'))
|
||||
end)
|
||||
|
||||
it('returns the output of the commands if the argument is List', function()
|
||||
eq("foobar", funcs.capture({'echon "foo"', 'echon "bar"'}))
|
||||
eq("\nfoo\nbar", funcs.capture({'echo "foo"', 'echo "bar"'}))
|
||||
end)
|
||||
|
||||
it('supports the nested redirection', function()
|
||||
source([[
|
||||
function! g:Foo()
|
||||
let a = ''
|
||||
redir => a
|
||||
silent echon "foo"
|
||||
redir END
|
||||
return a
|
||||
endfunction
|
||||
function! g:Bar()
|
||||
let a = ''
|
||||
redir => a
|
||||
call g:Foo()
|
||||
redir END
|
||||
return a
|
||||
endfunction
|
||||
]])
|
||||
eq('foo', funcs.capture('call g:Bar()'))
|
||||
|
||||
eq('42', funcs.capture([[echon capture("echon capture('echon 42')")]]))
|
||||
end)
|
||||
|
||||
it('returns the transformed string', function()
|
||||
eq('^A', funcs.capture('echon "\\<C-a>"'))
|
||||
end)
|
||||
|
||||
it('returns the empty string if the argument list is empty', function()
|
||||
eq('', funcs.capture({}))
|
||||
eq(0, exc_exec('let g:ret = capture(v:_null_list)'))
|
||||
eq('', eval('g:ret'))
|
||||
end)
|
||||
|
||||
it('returns the errors', function()
|
||||
local ret
|
||||
ret = exc_exec('call capture(0.0)')
|
||||
eq('Vim(call):E806: using Float as a String', ret)
|
||||
ret = exc_exec('call capture(v:_null_dict)')
|
||||
eq('Vim(call):E731: using Dictionary as a String', ret)
|
||||
ret = exc_exec('call capture(function("tr"))')
|
||||
eq('Vim(call):E729: using Funcref as a String', ret)
|
||||
ret = exc_exec('call capture(["echo 42", 0.0, "echo 44"])')
|
||||
eq('Vim(call):E806: using Float as a String', ret)
|
||||
ret = exc_exec('call capture(["echo 42", v:_null_dict, "echo 44"])')
|
||||
eq('Vim(call):E731: using Dictionary as a String', ret)
|
||||
ret = exc_exec('call capture(["echo 42", function("tr"), "echo 44"])')
|
||||
eq('Vim(call):E729: using Funcref as a String', ret)
|
||||
end)
|
||||
|
||||
it('silences command run inside', function()
|
||||
local screen = Screen.new(20, 5)
|
||||
screen:attach()
|
||||
screen:set_default_attr_ignore({{bold=true, foreground=255}})
|
||||
feed(':let g:mes = capture("echon 42")<CR>')
|
||||
screen:expect([[
|
||||
^ |
|
||||
~ |
|
||||
~ |
|
||||
~ |
|
||||
|
|
||||
]])
|
||||
eq('42', eval('g:mes'))
|
||||
end)
|
||||
end)
|
Loading…
Reference in New Issue
Block a user