diff options
-rw-r--r-- | src/nvim/api/vim.c | 2 | ||||
-rw-r--r-- | src/nvim/ex_cmds2.c | 16 | ||||
-rw-r--r-- | test/functional/api/vim_spec.lua | 131 |
3 files changed, 86 insertions, 63 deletions
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 95f6de94a4..10ece6bc22 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -77,7 +77,7 @@ void nvim_source(String command, Error *err) FUNC_API_SINCE(7) { try_start(); - do_source_str((char_u *)command.data); + do_source_str(command.data); try_end(err); } diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index edfa3fea9a..eec689a28d 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -3020,6 +3020,11 @@ typedef struct { size_t offset; } 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) { GetStrLineCookie *p = cookie; @@ -3034,18 +3039,19 @@ static char_u *get_str_line(int c, void *cookie, int ident) 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); + smsg(_(":source error parsing command %s"), p->buf); + return NULL; } buf[i-p->offset]='\0'; p->offset = i + 1; return (char_u *)xstrdup(buf); } -int do_source_str(char_u *cmd) +int do_source_str(const char *cmd) { int retval; GetStrLineCookie cookie = { - .buf = cmd, + .buf = (char_u *)cmd, .offset = 0, }; 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_lnum = 0; retval = do_cmdline(NULL, get_str_line, (void *)&cookie, - DOCMD_NOWAIT); + DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT); current_sctx = save_current_sctx; return retval; } @@ -3402,6 +3408,8 @@ char_u *get_scriptname(LastSet last_set, bool *should_free) _("API client (channel id %" PRIu64 ")"), last_set.channel_id); return IObuff; + case SID_STR: + return (char_u *)_(":source (no file)"); default: *should_free = true; return home_replace_save(NULL, diff --git a/test/functional/api/vim_spec.lua b/test/functional/api/vim_spec.lua index 14ed474eb1..a01ef2d6dd 100644 --- a/test/functional/api/vim_spec.lua +++ b/test/functional/api/vim_spec.lua @@ -16,6 +16,7 @@ local parse_context = helpers.parse_context local request = helpers.request local source = helpers.source local next_msg = helpers.next_msg +local write_file = helpers.write_file local pcall_err = helpers.pcall_err local format_string = helpers.format_string @@ -75,80 +76,94 @@ describe('API', function() end) describe('nvim_source', function() - it('works with a one-liner', function() + it('one-line input', function() nvim('source', "let x1 = 'a'") - eq(nvim('get_var', 'x1'), 'a') + eq('a', nvim('get_var', 'x1')) 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') + 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('works with multiple stray newline character', function() + it('multiline input', function() + -- Heredoc + empty lines. + nvim('source', "let x2 = 'a'\n") + eq('a', nvim('get_var', 'x2')) nvim('source','lua <<EOF\n\n\n\ny=3\n\n\nEOF') - eq(nvim('command_output', "echo luaeval('y')"), '3') - end) + eq(3, nvim('eval', "luaeval('y')")) - 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')) + 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) + + it('non-ASCII input', function() + nvim('source', [=[ + new + exe "normal! i ax \n Ax " + :%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')) + + nvim('source', [[ + new + call setline(1,['xxx']) + 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. + it('execution error', function() + eq('Vim:E492: Not an editor command: bogus_command', + pcall_err(request, 'nvim_source', 'bogus_command')) + 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('Vim(buffer):E86: Buffer 23487 does not exist', + pcall_err(request, 'nvim_source', 'buffer 23487')) 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"') + it('recursion', function() 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') + write_file(fname, 'let x1 = "set from :source file"\n') + -- nvim_source + -- :source + -- nvim_source + request('nvim_source', [[ + let x2 = substitute('foo','o','X','g') + let x4 = 'should be overwritten' + call nvim_source("source ]]..fname..[[\nlet x3 = substitute('foo','foo','set by recursive nvim_source','g')\nlet x5='overwritten'\nlet x4=x5\n") + ]]) + eq('set from :source file', request('nvim_get_var', 'x1')) + eq('fXX', request('nvim_get_var', 'x2')) + eq('set by recursive nvim_source', request('nvim_get_var', 'x3')) + eq('overwritten', request('nvim_get_var', 'x4')) + eq('overwritten', request('nvim_get_var', 'x5')) + os.remove(fname) end) end) |