aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/nvim/api/vim.c10
-rw-r--r--src/nvim/ex_cmds2.c40
-rw-r--r--test/functional/api/vim_spec.lua78
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()