mirror of
https://github.com/neovim/neovim.git
synced 2025-10-05 09:26:30 +00:00
API: nvim_source: fix multiline input
- DOCMD_REPEAT is needed to source all lines of input. - Fix ":verbose set {option}?" by handling SID_STR in get_scriptname(). closes #8722
This commit is contained in:
@@ -77,7 +77,7 @@ void nvim_source(String command, Error *err)
|
|||||||
FUNC_API_SINCE(7)
|
FUNC_API_SINCE(7)
|
||||||
{
|
{
|
||||||
try_start();
|
try_start();
|
||||||
do_source_str((char_u *)command.data);
|
do_source_str(command.data);
|
||||||
try_end(err);
|
try_end(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -3020,6 +3020,11 @@ typedef struct {
|
|||||||
size_t offset;
|
size_t offset;
|
||||||
} GetStrLineCookie;
|
} GetStrLineCookie;
|
||||||
|
|
||||||
|
/// Get one full line from a sourced string (in-memory, no file).
|
||||||
|
/// Called by do_cmdline() when it's called from do_source_str().
|
||||||
|
///
|
||||||
|
/// @return pointer to allocated line, or NULL for end-of-file or
|
||||||
|
/// 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 ident)
|
||||||
{
|
{
|
||||||
GetStrLineCookie *p = cookie;
|
GetStrLineCookie *p = cookie;
|
||||||
@@ -3034,18 +3039,19 @@ static char_u *get_str_line(int c, void *cookie, int ident)
|
|||||||
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(_("nvim_source error parsing command %s"), p->buf);
|
smsg(_(":source error parsing command %s"), p->buf);
|
||||||
|
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(char_u *cmd)
|
int do_source_str(const char *cmd)
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
GetStrLineCookie cookie = {
|
GetStrLineCookie cookie = {
|
||||||
.buf = cmd,
|
.buf = (char_u *)cmd,
|
||||||
.offset = 0,
|
.offset = 0,
|
||||||
};
|
};
|
||||||
const sctx_T save_current_sctx = current_sctx;
|
const sctx_T save_current_sctx = current_sctx;
|
||||||
@@ -3053,7 +3059,7 @@ int do_source_str(char_u *cmd)
|
|||||||
current_sctx.sc_seq = 0;
|
current_sctx.sc_seq = 0;
|
||||||
current_sctx.sc_lnum = 0;
|
current_sctx.sc_lnum = 0;
|
||||||
retval = do_cmdline(NULL, get_str_line, (void *)&cookie,
|
retval = do_cmdline(NULL, get_str_line, (void *)&cookie,
|
||||||
DOCMD_NOWAIT);
|
DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT);
|
||||||
current_sctx = save_current_sctx;
|
current_sctx = save_current_sctx;
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
@@ -3402,6 +3408,8 @@ char_u *get_scriptname(LastSet last_set, bool *should_free)
|
|||||||
_("API client (channel id %" PRIu64 ")"),
|
_("API client (channel id %" PRIu64 ")"),
|
||||||
last_set.channel_id);
|
last_set.channel_id);
|
||||||
return IObuff;
|
return IObuff;
|
||||||
|
case SID_STR:
|
||||||
|
return (char_u *)_(":source (no file)");
|
||||||
default:
|
default:
|
||||||
*should_free = true;
|
*should_free = true;
|
||||||
return home_replace_save(NULL,
|
return home_replace_save(NULL,
|
||||||
|
@@ -16,6 +16,7 @@ local parse_context = helpers.parse_context
|
|||||||
local request = helpers.request
|
local request = helpers.request
|
||||||
local source = helpers.source
|
local source = helpers.source
|
||||||
local next_msg = helpers.next_msg
|
local next_msg = helpers.next_msg
|
||||||
|
local write_file = helpers.write_file
|
||||||
|
|
||||||
local pcall_err = helpers.pcall_err
|
local pcall_err = helpers.pcall_err
|
||||||
local format_string = helpers.format_string
|
local format_string = helpers.format_string
|
||||||
@@ -75,80 +76,94 @@ describe('API', function()
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
describe('nvim_source', function()
|
describe('nvim_source', function()
|
||||||
it('works with a one-liner', function()
|
it('one-line input', function()
|
||||||
nvim('source', "let x1 = 'a'")
|
nvim('source', "let x1 = 'a'")
|
||||||
eq(nvim('get_var', 'x1'), 'a')
|
eq('a', nvim('get_var', 'x1'))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('works with stray newline character', function()
|
it(':verbose set {option}?', function()
|
||||||
|
nvim('source', 'set nowrap')
|
||||||
|
eq('nowrap\n\tLast set from :source (no file)',
|
||||||
|
nvim('command_output', 'verbose set wrap?'))
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('multiline input', function()
|
||||||
|
-- Heredoc + empty lines.
|
||||||
nvim('source', "let x2 = 'a'\n")
|
nvim('source', "let x2 = 'a'\n")
|
||||||
eq(nvim('get_var', 'x2'),'a')
|
eq('a', nvim('get_var', 'x2'))
|
||||||
end)
|
|
||||||
|
|
||||||
it('works with multiline command', function()
|
|
||||||
nvim('source', 'lua <<EOF\ny=3\nEOF')
|
|
||||||
eq(nvim('command_output', "echo luaeval('y')"),'3')
|
|
||||||
end)
|
|
||||||
|
|
||||||
it('works with multiple stray newline character', function()
|
|
||||||
nvim('source','lua <<EOF\n\n\n\ny=3\n\n\nEOF')
|
nvim('source','lua <<EOF\n\n\n\ny=3\n\n\nEOF')
|
||||||
eq(nvim('command_output', "echo luaeval('y')"), '3')
|
eq(3, nvim('eval', "luaeval('y')"))
|
||||||
|
|
||||||
|
nvim('source', 'lua <<EOF\ny=3\nEOF')
|
||||||
|
eq(3, nvim('eval', "luaeval('y')"))
|
||||||
|
|
||||||
|
-- Multiple statements
|
||||||
|
nvim('source', 'let x1=1\nlet x2=2\nlet x3=3\n')
|
||||||
|
eq(1, nvim('eval', 'x1'))
|
||||||
|
eq(2, nvim('eval', 'x2'))
|
||||||
|
eq(3, nvim('eval', 'x3'))
|
||||||
|
|
||||||
|
-- Functions
|
||||||
|
nvim('source', 'function Foo()\ncall setline(1,["xxx"])\nendfunction')
|
||||||
|
eq(nvim('get_current_line'), '')
|
||||||
|
nvim('source', 'call Foo()')
|
||||||
|
eq(nvim('get_current_line'), 'xxx')
|
||||||
|
|
||||||
|
-- Autocmds
|
||||||
|
nvim('source','autocmd BufAdd * :let x1 = "Hello"')
|
||||||
|
nvim('command', 'new foo')
|
||||||
|
eq('Hello', request('nvim_eval', 'g:x1'))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('works with utf-8', function()
|
it('non-ASCII input', function()
|
||||||
nvim('command', 'new')
|
nvim('source', [=[
|
||||||
nvim('command', 'normal i ax \n Ax ')
|
new
|
||||||
nvim('source', ":%s/ax/--a1234--/g | :%s/Ax/--A1234--/g")
|
exe "normal! i ax \n Ax "
|
||||||
nvim('command','1')
|
:%s/ax/--a1234--/g | :%s/Ax/--A1234--/g
|
||||||
eq(' --a1234-- ',nvim('get_current_line'))
|
]=])
|
||||||
nvim('command','2')
|
nvim('command', '1')
|
||||||
eq(' --A1234-- ',nvim('get_current_line'))
|
eq(' --a1234-- ', nvim('get_current_line'))
|
||||||
|
nvim('command', '2')
|
||||||
|
eq(' --A1234-- ', nvim('get_current_line'))
|
||||||
|
|
||||||
|
nvim('source', [[
|
||||||
|
new
|
||||||
|
call setline(1,['xxx'])
|
||||||
|
call feedkeys('r')
|
||||||
|
call feedkeys('ñ', 'xt')
|
||||||
|
]])
|
||||||
|
eq('ñxx', nvim('get_current_line'))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('works with latin characters', function()
|
it('execution error', function()
|
||||||
nvim('command', 'new')
|
eq('Vim:E492: Not an editor command: bogus_command',
|
||||||
nvim('command', "call setline(1,['xxx'])")
|
pcall_err(request, 'nvim_source', 'bogus_command'))
|
||||||
nvim('source', "call feedkeys('r')|call feedkeys('ñ', 'xt')")
|
eq('', nvim('eval', 'v:errmsg')) -- v:errmsg was not updated.
|
||||||
eq('ñxx',nvim('get_current_line'))
|
|
||||||
end)
|
|
||||||
|
|
||||||
it('nvim_source validation error:fails with specific error', function()
|
|
||||||
local status, rv = pcall(nvim, "source", "bogus_command")
|
|
||||||
eq(false, status) -- nvim_command() failed.
|
|
||||||
eq("E492:", string.match(rv, "E%d*:")) -- VimL error was returned.
|
|
||||||
eq('', nvim('eval', 'v:errmsg')) -- v:errmsg was not updated.
|
|
||||||
eq('', eval('v:exception'))
|
eq('', eval('v:exception'))
|
||||||
end)
|
|
||||||
|
|
||||||
it('nvim_source execution error: fails with specific error', function()
|
eq('Vim(buffer):E86: Buffer 23487 does not exist',
|
||||||
local status, rv = pcall(nvim, "source", "buffer 23487")
|
pcall_err(request, 'nvim_source', 'buffer 23487'))
|
||||||
eq(false, status) -- nvim_command() failed.
|
|
||||||
eq("E86: Buffer 23487 does not exist", string.match(rv, "E%d*:.*"))
|
|
||||||
eq('', eval('v:errmsg')) -- v:errmsg was not updated.
|
eq('', eval('v:errmsg')) -- v:errmsg was not updated.
|
||||||
eq('', eval('v:exception'))
|
eq('', eval('v:exception'))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('nvim_source autocommands work', function()
|
it('recursion', function()
|
||||||
nvim('source','autocmd BufCreate * :let x1 = "Hello"')
|
|
||||||
local fname = helpers.tmpname()
|
local fname = helpers.tmpname()
|
||||||
nvim('command', 'new '..fname)
|
write_file(fname, 'let x1 = "set from :source file"\n')
|
||||||
eq(nvim('command_output','echo x1'),"Hello")
|
-- nvim_source
|
||||||
end)
|
-- :source
|
||||||
|
-- nvim_source
|
||||||
it('nvim_source: recursive source works', function()
|
request('nvim_source', [[
|
||||||
local fname = helpers.tmpname()
|
let x2 = substitute('foo','o','X','g')
|
||||||
nvim('command', 'new')
|
let x4 = 'should be overwritten'
|
||||||
nvim('command','edit '..fname)
|
call nvim_source("source ]]..fname..[[\nlet x3 = substitute('foo','foo','set by recursive nvim_source','g')\nlet x5='overwritten'\nlet x4=x5\n")
|
||||||
nvim('command','normal ilet x1 = "a"')
|
]])
|
||||||
nvim('command','w')
|
eq('set from :source file', request('nvim_get_var', 'x1'))
|
||||||
nvim('source','call nvim_source("source '..fname..'")')
|
eq('fXX', request('nvim_get_var', 'x2'))
|
||||||
eq(nvim('get_var','x1'),'a')
|
eq('set by recursive nvim_source', request('nvim_get_var', 'x3'))
|
||||||
end)
|
eq('overwritten', request('nvim_get_var', 'x4'))
|
||||||
|
eq('overwritten', request('nvim_get_var', 'x5'))
|
||||||
it('nvim_source: functions work', function()
|
os.remove(fname)
|
||||||
nvim('source','function Foo()\ncall setline(1,["xxx"])\nendfunction')
|
|
||||||
nvim('source','call Foo()')
|
|
||||||
eq(nvim('get_current_line'),'xxx')
|
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user