mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
API: nvim_source_output
- Similar to nvim_source but will capture the output - Add meaningful VimL tracebacks for nvim_source - Handle got_int - Add error reporting
This commit is contained in:
parent
276c2da286
commit
bd43e011b5
@ -73,14 +73,63 @@ void api_vim_free_all_mem(void)
|
|||||||
map_free(String, handle_T)(namespace_ids);
|
map_free(String, handle_T)(namespace_ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nvim_source(String command, Error *err)
|
/// Executes a multiline block of ex-commands from a string.
|
||||||
FUNC_API_SINCE(7)
|
///
|
||||||
|
/// On execution error: fails with VimL error, does not update v:errmsg.
|
||||||
|
///
|
||||||
|
/// @param src String containing the ex-commands
|
||||||
|
/// @param[out] err Error details (Vim error), if any
|
||||||
|
void nvim_source(String src, Error *err) FUNC_API_SINCE(7)
|
||||||
{
|
{
|
||||||
try_start();
|
try_start();
|
||||||
do_source_str(command.data);
|
do_source_str(src.data, "nvim_source(..)");
|
||||||
try_end(err);
|
try_end(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Executes a multiline block of ex-commands from a string and returns its
|
||||||
|
/// (non-error) output. Shell |:!| output is not captured.
|
||||||
|
///
|
||||||
|
/// On execution error: fails with VimL error, does not update v:errmsg.
|
||||||
|
///
|
||||||
|
/// @param src String containing the ex-commands
|
||||||
|
/// @param[out] err Error details (Vim error), if any
|
||||||
|
String nvim_source_output(String src, Error *err) FUNC_API_SINCE(7)
|
||||||
|
{
|
||||||
|
const int save_msg_silent = msg_silent;
|
||||||
|
garray_T *const save_capture_ga = capture_ga;
|
||||||
|
garray_T capture_local;
|
||||||
|
ga_init(&capture_local, 1, 80);
|
||||||
|
|
||||||
|
try_start();
|
||||||
|
msg_silent++;
|
||||||
|
capture_ga = &capture_local;
|
||||||
|
do_source_str(src.data, "nvim_source_output(..)");
|
||||||
|
capture_ga = save_capture_ga;
|
||||||
|
msg_silent = save_msg_silent;
|
||||||
|
try_end(err);
|
||||||
|
|
||||||
|
if (ERROR_SET(err)) {
|
||||||
|
goto theend;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (capture_local.ga_len > 1) {
|
||||||
|
String s = (String){
|
||||||
|
.data = capture_local.ga_data,
|
||||||
|
.size = (size_t)capture_local.ga_len,
|
||||||
|
};
|
||||||
|
// redir usually (except :echon) prepends a newline.
|
||||||
|
if (s.data[0] == '\n') {
|
||||||
|
memmove(s.data, s.data + 1, s.size - 1);
|
||||||
|
s.data[s.size - 1] = '\0';
|
||||||
|
s.size = s.size - 1;
|
||||||
|
}
|
||||||
|
return s; // Caller will free the memory.
|
||||||
|
}
|
||||||
|
theend:
|
||||||
|
ga_clear(&capture_local);
|
||||||
|
return (String)STRING_INIT;
|
||||||
|
}
|
||||||
|
|
||||||
/// Executes an ex-command.
|
/// Executes an ex-command.
|
||||||
///
|
///
|
||||||
/// On execution error: fails with VimL error, does not update v:errmsg.
|
/// On execution error: fails with VimL error, does not update v:errmsg.
|
||||||
|
@ -3025,7 +3025,7 @@ typedef struct {
|
|||||||
///
|
///
|
||||||
/// @return pointer to allocated line, or NULL for end-of-file or
|
/// @return pointer to allocated line, or NULL for end-of-file or
|
||||||
/// some error.
|
/// some error.
|
||||||
static char_u *get_str_line(int c, void *cookie, int ident)
|
static char_u *get_str_line(int c, void *cookie, int indent, bool do_concat)
|
||||||
{
|
{
|
||||||
GetStrLineCookie *p = cookie;
|
GetStrLineCookie *p = cookie;
|
||||||
size_t i = p->offset;
|
size_t i = p->offset;
|
||||||
@ -3037,19 +3037,31 @@ static char_u *get_str_line(int c, void *cookie, int ident)
|
|||||||
}
|
}
|
||||||
char buf[2046];
|
char buf[2046];
|
||||||
char *dst;
|
char *dst;
|
||||||
dst = xstpncpy(buf, (char *)p->buf+p->offset, i - p->offset);
|
dst = xstpncpy(buf, (char *)p->buf + p->offset, i - p->offset);
|
||||||
if ((uint32_t)(dst - buf) != i - p->offset) {
|
if ((uint32_t)(dst - buf) != i - p->offset) {
|
||||||
smsg(_(":source error parsing command %s"), p->buf);
|
smsg(_(":source error parsing command %s"), p->buf);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
buf[i-p->offset]='\0';
|
buf[i - p->offset] = '\0';
|
||||||
p->offset = i + 1;
|
p->offset = i + 1;
|
||||||
return (char_u *)xstrdup(buf);
|
return (char_u *)xstrdup(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
int do_source_str(const char *cmd)
|
int do_source_str(const char *cmd, const char *traceback_name)
|
||||||
{
|
{
|
||||||
int retval;
|
char_u *save_sourcing_name = sourcing_name;
|
||||||
|
linenr_T save_sourcing_lnum = sourcing_lnum;
|
||||||
|
char_u sourcing_name_buf[256];
|
||||||
|
if (save_sourcing_name == NULL) {
|
||||||
|
sourcing_name = (char_u *)traceback_name;
|
||||||
|
} else {
|
||||||
|
snprintf((char *)sourcing_name_buf, sizeof sourcing_name_buf,
|
||||||
|
"%s called at %s:%"PRIdLINENR, traceback_name, save_sourcing_name,
|
||||||
|
save_sourcing_lnum);
|
||||||
|
sourcing_name = sourcing_name_buf;
|
||||||
|
}
|
||||||
|
sourcing_lnum = 0;
|
||||||
|
|
||||||
GetStrLineCookie cookie = {
|
GetStrLineCookie cookie = {
|
||||||
.buf = (char_u *)cmd,
|
.buf = (char_u *)cmd,
|
||||||
.offset = 0,
|
.offset = 0,
|
||||||
@ -3057,10 +3069,18 @@ int do_source_str(const char *cmd)
|
|||||||
const sctx_T save_current_sctx = current_sctx;
|
const sctx_T save_current_sctx = current_sctx;
|
||||||
current_sctx.sc_sid = SID_STR;
|
current_sctx.sc_sid = SID_STR;
|
||||||
current_sctx.sc_seq = 0;
|
current_sctx.sc_seq = 0;
|
||||||
current_sctx.sc_lnum = 0;
|
current_sctx.sc_lnum = save_sourcing_lnum;
|
||||||
retval = do_cmdline(NULL, get_str_line, (void *)&cookie,
|
int retval = FAIL;
|
||||||
DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
|
do_cmdline(NULL, get_str_line, (void *)&cookie,
|
||||||
|
DOCMD_VERBOSE | DOCMD_NOWAIT | DOCMD_REPEAT);
|
||||||
|
retval = OK;
|
||||||
|
if (got_int) {
|
||||||
|
EMSG(_(e_interr));
|
||||||
|
}
|
||||||
|
|
||||||
current_sctx = save_current_sctx;
|
current_sctx = save_current_sctx;
|
||||||
|
sourcing_lnum = save_sourcing_lnum;
|
||||||
|
sourcing_name = save_sourcing_name;
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ describe('API', function()
|
|||||||
it(':verbose set {option}?', function()
|
it(':verbose set {option}?', function()
|
||||||
nvim('source', 'set nowrap')
|
nvim('source', 'set nowrap')
|
||||||
eq('nowrap\n\tLast set from :source (no file)',
|
eq('nowrap\n\tLast set from :source (no file)',
|
||||||
nvim('command_output', 'verbose set wrap?'))
|
nvim('source_output', 'verbose set wrap?'))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('multiline input', function()
|
it('multiline input', function()
|
||||||
@ -165,6 +165,36 @@ describe('API', function()
|
|||||||
eq('overwritten', request('nvim_get_var', 'x5'))
|
eq('overwritten', request('nvim_get_var', 'x5'))
|
||||||
os.remove(fname)
|
os.remove(fname)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('traceback', function()
|
||||||
|
local fname = helpers.tmpname()
|
||||||
|
write_file(fname, 'echo "hello"\n')
|
||||||
|
local sourcing_fname = helpers.tmpname()
|
||||||
|
write_file(sourcing_fname, 'call nvim_source("source '..fname..'")\n')
|
||||||
|
meths.source('set verbose=2')
|
||||||
|
print()
|
||||||
|
local traceback_output = 'line 0: sourcing "'..sourcing_fname..'"\n'..
|
||||||
|
'line 0: sourcing "'..fname..'"\n'..
|
||||||
|
'hello\n'..
|
||||||
|
'finished sourcing '..fname..'\n'..
|
||||||
|
'continuing in nvim_source(..) called at '..sourcing_fname..':1\n'..
|
||||||
|
'finished sourcing '..sourcing_fname..'\n'..
|
||||||
|
'continuing in nvim_source(..) called at nvim_source_output(..):0'
|
||||||
|
eq(traceback_output, meths.source_output('call nvim_source("source '..sourcing_fname..'")'))
|
||||||
|
os.remove(fname)
|
||||||
|
os.remove(sourcing_fname)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
describe('nvim_source_output', function()
|
||||||
|
it('multiline input', function()
|
||||||
|
eq('this is spinal tap',
|
||||||
|
nvim('source_output', 'lua <<EOF\n\n\nprint("this is spinal tap")\n\n\nEOF'))
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('empty output', function()
|
||||||
|
eq('', nvim('source_output', 'echo'))
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe('nvim_command', function()
|
describe('nvim_command', function()
|
||||||
|
Loading…
Reference in New Issue
Block a user