From 6aa03e86da041284b5f27a59f73cef0991fc577e Mon Sep 17 00:00:00 2001 From: Siddhant Gupta Date: Sun, 6 Oct 2019 13:37:54 -0700 Subject: API: nvim_source --- src/nvim/api/vim.c | 10 ++++++++++ src/nvim/ex_cmds2.c | 40 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 49 insertions(+), 1 deletion(-) (limited to 'src') 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. /// -- cgit From 0a8d145075d3ce5fffe2df190992f624ae931809 Mon Sep 17 00:00:00 2001 From: Vikram Pal Date: Sat, 5 Oct 2019 20:07:27 +0530 Subject: API: nvim_source: save/restore script context #11159 Use a constant for the script id. --- src/nvim/api/vim.c | 9 ++++----- src/nvim/ex_cmds2.c | 8 ++++++-- src/nvim/globals.h | 1 + 3 files changed, 11 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index ee36ae28e6..95f6de94a4 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -74,12 +74,11 @@ void api_vim_free_all_mem(void) } void nvim_source(String command, Error *err) - FUNC_API_SINCE(5) + FUNC_API_SINCE(7) { - try_start(); - do_source_str((char_u *)command.data); - update_screen(VALID); - try_end(err); + try_start(); + do_source_str((char_u *)command.data); + try_end(err); } /// Executes an ex-command. diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index 904a3d10e5..edfa3fea9a 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 && current_SID < 999999) { + if (current_sctx.sc_sid > 0) { return SCRIPT_ITEM(current_sctx.sc_sid).sn_pr_force; } return false; @@ -3048,9 +3048,13 @@ int do_source_str(char_u *cmd) .buf = cmd, .offset = 0, }; - current_SID = 999999; + const sctx_T save_current_sctx = current_sctx; + current_sctx.sc_sid = SID_STR; + current_sctx.sc_seq = 0; + current_sctx.sc_lnum = 0; retval = do_cmdline(NULL, get_str_line, (void *)&cookie, DOCMD_NOWAIT); + current_sctx = save_current_sctx; return retval; } diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 15ad6d8767..172c190df2 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -331,6 +331,7 @@ EXTERN int garbage_collect_at_exit INIT(= false); #define SID_NONE -6 // don't set scriptID #define SID_LUA -7 // for Lua scripts/chunks #define SID_API_CLIENT -8 // for API clients +#define SID_STR -9 // for sourcing a string // Script CTX being sourced or was sourced to define the current function. EXTERN sctx_T current_sctx INIT(= { 0 COMMA 0 COMMA 0 }); -- cgit From 276c2da28616d7a4f504c328dbb8857d38ab7a4a Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 6 Oct 2019 19:40:36 -0700 Subject: 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 --- src/nvim/api/vim.c | 2 +- src/nvim/ex_cmds2.c | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) (limited to 'src') 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, -- cgit From bd43e011b5b0feba644ec5feae6c174def31a9e4 Mon Sep 17 00:00:00 2001 From: Vikram Pal Date: Wed, 9 Oct 2019 18:34:37 +0530 Subject: 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 --- src/nvim/api/vim.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++--- src/nvim/ex_cmds2.c | 36 +++++++++++++++++++++++++++-------- 2 files changed, 80 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 10ece6bc22..bf722b4f4e 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -73,14 +73,63 @@ void api_vim_free_all_mem(void) map_free(String, handle_T)(namespace_ids); } -void nvim_source(String command, Error *err) - FUNC_API_SINCE(7) +/// Executes a multiline block of ex-commands from a string. +/// +/// 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(); - do_source_str(command.data); + do_source_str(src.data, "nvim_source(..)"); 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. /// /// 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 eec689a28d..bda7b4e8b5 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -3025,7 +3025,7 @@ typedef struct { /// /// @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 indent, bool do_concat) { GetStrLineCookie *p = cookie; 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 *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) { smsg(_(":source error parsing command %s"), p->buf); return NULL; } - buf[i-p->offset]='\0'; + buf[i - p->offset] = '\0'; p->offset = i + 1; 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 = { .buf = (char_u *)cmd, .offset = 0, @@ -3057,10 +3069,18 @@ int do_source_str(const char *cmd) const sctx_T save_current_sctx = current_sctx; current_sctx.sc_sid = SID_STR; current_sctx.sc_seq = 0; - current_sctx.sc_lnum = 0; - retval = do_cmdline(NULL, get_str_line, (void *)&cookie, - DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_REPEAT); + current_sctx.sc_lnum = save_sourcing_lnum; + int retval = FAIL; + 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; + sourcing_lnum = save_sourcing_lnum; + sourcing_name = save_sourcing_name; return retval; } -- cgit From b1991f66d5845ccb72c73fdf39153a0e1fbb1124 Mon Sep 17 00:00:00 2001 From: "Justin M. Keyes" Date: Sun, 1 Dec 2019 22:26:36 -0800 Subject: API: rename nvim_source => nvim_exec - Eliminate nvim_source_output(): add boolean `output` param to nvim_exec() instead. --- src/nvim/api/vim.c | 39 +++++++++++++++++++++------------------ src/nvim/ex_cmds2.c | 19 +++++++++---------- src/nvim/ex_docmd.c | 9 ++++----- 3 files changed, 34 insertions(+), 33 deletions(-) (limited to 'src') diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index bf722b4f4e..6763a3a936 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -73,28 +73,29 @@ void api_vim_free_all_mem(void) map_free(String, handle_T)(namespace_ids); } -/// Executes a multiline block of ex-commands from a string. +/// Executes Vimscript (multiline block of Ex-commands), like anonymous +/// |:source|. /// -/// 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(); - do_source_str(src.data, "nvim_source(..)"); - try_end(err); -} - -/// Executes a multiline block of ex-commands from a string and returns its -/// (non-error) output. Shell |:!| output is not captured. +/// Optionally returns (non-error, non-shell |:!|) output. /// /// On execution error: fails with VimL error, does not update v:errmsg. /// -/// @param src String containing the ex-commands +/// @see |execute()| +/// @see |nvim_command()| +/// +/// @param src Vimscript code +/// @param output Capture and return all (non-error, non-shell |:!|) output /// @param[out] err Error details (Vim error), if any -String nvim_source_output(String src, Error *err) FUNC_API_SINCE(7) +String nvim_exec(String src, Boolean output, Error *err) + FUNC_API_SINCE(7) { + if (!output) { + try_start(); + do_source_str(src.data, "nvim_exec()"); + try_end(err); + return (String)STRING_INIT; + } + const int save_msg_silent = msg_silent; garray_T *const save_capture_ga = capture_ga; garray_T capture_local; @@ -103,7 +104,7 @@ String nvim_source_output(String src, Error *err) FUNC_API_SINCE(7) try_start(); msg_silent++; capture_ga = &capture_local; - do_source_str(src.data, "nvim_source_output(..)"); + do_source_str(src.data, "nvim_exec()"); capture_ga = save_capture_ga; msg_silent = save_msg_silent; try_end(err); @@ -134,6 +135,8 @@ theend: /// /// On execution error: fails with VimL error, does not update v:errmsg. /// +/// @see |nvim_exec()| +/// /// @param command Ex-command string /// @param[out] err Error details (Vim error), if any void nvim_command(String command, Error *err) @@ -436,7 +439,7 @@ theend: return (String)STRING_INIT; } -/// Evaluates a VimL expression (:help expression). +/// Evaluates a VimL |expression|. /// Dictionaries and Lists are recursively expanded. /// /// 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 bda7b4e8b5..8479c15b40 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -3047,6 +3047,9 @@ static char_u *get_str_line(int c, void *cookie, int indent, bool do_concat) return (char_u *)xstrdup(buf); } +/// Executes lines in `src` as Ex commands. +/// +/// @see do_source() int do_source_str(const char *cmd, const char *traceback_name) { char_u *save_sourcing_name = sourcing_name; @@ -3055,7 +3058,7 @@ int do_source_str(const char *cmd, const char *traceback_name) if (save_sourcing_name == NULL) { sourcing_name = (char_u *)traceback_name; } else { - snprintf((char *)sourcing_name_buf, sizeof sourcing_name_buf, + 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; @@ -3070,24 +3073,20 @@ int do_source_str(const char *cmd, const char *traceback_name) current_sctx.sc_sid = SID_STR; current_sctx.sc_seq = 0; current_sctx.sc_lnum = save_sourcing_lnum; - int retval = FAIL; - do_cmdline(NULL, get_str_line, (void *)&cookie, - DOCMD_VERBOSE | DOCMD_NOWAIT | DOCMD_REPEAT); - retval = OK; - if (got_int) { - EMSG(_(e_interr)); - } - + int retval = do_cmdline(NULL, get_str_line, (void *)&cookie, + DOCMD_VERBOSE | DOCMD_NOWAIT | DOCMD_REPEAT); current_sctx = save_current_sctx; sourcing_lnum = save_sourcing_lnum; sourcing_name = save_sourcing_name; return retval; } -/// Read the file "fname" and execute its lines as EX commands. +/// Reads the file `fname` and executes its lines as Ex commands. /// /// This function may be called recursively! /// +/// @see do_source_str +/// /// @param fname /// @param check_other check for .vimrc and _vimrc /// @param is_vimrc DOSO_ value diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 743286c64a..dc2726709f 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -421,13 +421,12 @@ int do_cmdline(char_u *cmdline, LineGetter fgetline, // If force_abort is set, we cancel everything. did_emsg = false; - /* - * KeyTyped is only set when calling vgetc(). Reset it here when not - * calling vgetc() (sourced command lines). - */ + // KeyTyped is only set when calling vgetc(). Reset it here when not + // calling vgetc() (sourced command lines). if (!(flags & DOCMD_KEYTYPED) - && !getline_equal(fgetline, cookie, getexline)) + && !getline_equal(fgetline, cookie, getexline)) { KeyTyped = false; + } /* * Continue executing command lines: -- cgit