diff options
-rw-r--r-- | src/nvim/api/vim.c | 10 | ||||
-rw-r--r-- | src/nvim/ex_cmds2.c | 40 | ||||
-rw-r--r-- | test/functional/api/vim_spec.lua | 78 |
3 files changed, 127 insertions, 1 deletions
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index e4a9bd64ff..ee36ae28e6 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -25,6 +25,7 @@ #include "nvim/highlight.h" #include "nvim/window.h" #include "nvim/types.h" +#include "nvim/ex_cmds2.h" #include "nvim/ex_docmd.h" #include "nvim/screen.h" #include "nvim/memline.h" @@ -72,6 +73,15 @@ void api_vim_free_all_mem(void) map_free(String, handle_T)(namespace_ids); } +void nvim_source(String command, Error *err) + FUNC_API_SINCE(5) +{ + try_start(); + do_source_str((char_u *)command.data); + update_screen(VALID); + try_end(err); +} + /// Executes an ex-command. /// /// On execution error: fails with VimL error, does not update v:errmsg. diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index 84291b3637..904a3d10e5 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -1193,7 +1193,7 @@ static void script_dump_profile(FILE *fd) /// profiled. bool prof_def_func(void) { - if (current_sctx.sc_sid > 0) { + if (current_sctx.sc_sid > 0 && current_SID < 999999) { return SCRIPT_ITEM(current_sctx.sc_sid).sn_pr_force; } return false; @@ -3015,6 +3015,44 @@ static FILE *fopen_noinh_readbin(char *filename) return fdopen(fd_tmp, READBIN); } +typedef struct { + char_u *buf; + size_t offset; +} GetStrLineCookie; + +static char_u *get_str_line(int c, void *cookie, int ident) +{ + GetStrLineCookie *p = cookie; + size_t i = p->offset; + if (strlen((char *)p->buf) <= p->offset) { + return NULL; + } + while (!(p->buf[i] == '\n' || p->buf[i] == '\0')) { + i++; + } + char buf[2046]; + char *dst; + dst = xstpncpy(buf, (char *)p->buf+p->offset, i - p->offset); + if ((uint32_t)(dst - buf) != i - p->offset) { + smsg(_("nvim_source error parsing command %s"), p->buf); + } + buf[i-p->offset]='\0'; + p->offset = i + 1; + return (char_u *)xstrdup(buf); +} + +int do_source_str(char_u *cmd) +{ + int retval; + GetStrLineCookie cookie = { + .buf = cmd, + .offset = 0, + }; + current_SID = 999999; + retval = do_cmdline(NULL, get_str_line, (void *)&cookie, + DOCMD_NOWAIT); + return retval; +} /// Read the file "fname" and execute its lines as EX commands. /// diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 8b77dbcaa6..14ed474eb1 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -74,6 +74,84 @@ describe('API', function() eq({mode='i', blocking=false}, nvim("get_mode")) end) + describe('nvim_source', function() + it('works with a one-liner', function() + nvim('source', "let x1 = 'a'") + eq(nvim('get_var', 'x1'), 'a') + end) + + it('works with stray newline character', function() + nvim('source', "let x2 = 'a'\n") + eq(nvim('get_var', 'x2'),'a') + 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') + eq(nvim('command_output', "echo luaeval('y')"), '3') + end) + + it('works with utf-8', function() + nvim('command', 'new') + nvim('command', 'normal i ax \n Ax ') + nvim('source', ":%s/ax/--a1234--/g | :%s/Ax/--A1234--/g") + nvim('command','1') + eq(' --a1234-- ',nvim('get_current_line')) + nvim('command','2') + eq(' --A1234-- ',nvim('get_current_line')) + end) + + it('works with latin characters', function() + nvim('command', 'new') + nvim('command', "call setline(1,['xxx'])") + nvim('source', "call feedkeys('r')|call feedkeys('ñ', 'xt')") + 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')) + end) + + it('nvim_source execution error: fails with specific error', function() + local status, rv = pcall(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:exception')) + end) + + it('nvim_source autocommands work', function() + nvim('source','autocmd BufCreate * :let x1 = "Hello"') + local fname = helpers.tmpname() + nvim('command', 'new '..fname) + eq(nvim('command_output','echo x1'),"Hello") + end) + + it('nvim_source: recursive source works', function() + local fname = helpers.tmpname() + nvim('command', 'new') + nvim('command','edit '..fname) + nvim('command','normal ilet x1 = "a"') + nvim('command','w') + nvim('source','call nvim_source("source '..fname..'")') + eq(nvim('get_var','x1'),'a') + end) + + it('nvim_source: functions work', function() + nvim('source','function Foo()\ncall setline(1,["xxx"])\nendfunction') + nvim('source','call Foo()') + eq(nvim('get_current_line'),'xxx') + end) + end) + describe('nvim_command', function() it('works', function() local fname = helpers.tmpname() |