diff options
author | zeertzjq <zeertzjq@outlook.com> | 2022-08-14 05:18:21 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-08-14 05:18:21 +0800 |
commit | 8cd116729fe2a15d62cd10e5ba7d3dcf1f677337 (patch) | |
tree | c3697b80da96e6e1165742979deb121ca491b1d0 /src | |
parent | c1cbe3fb3d2ec1dbcfdc14ee2d9a5e8049d494ae (diff) | |
parent | 1ca2247639424994890ef70ab34f2bffa23ddd9f (diff) | |
download | rneovim-8cd116729fe2a15d62cd10e5ba7d3dcf1f677337.tar.gz rneovim-8cd116729fe2a15d62cd10e5ba7d3dcf1f677337.tar.bz2 rneovim-8cd116729fe2a15d62cd10e5ba7d3dcf1f677337.zip |
Merge pull request #19752 from zeertzjq/vim-8.2.0056
vim-patch:8.2.{0056,0061,0078,0097,0823}: execution stack
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/autocmd.c | 24 | ||||
-rw-r--r-- | src/nvim/autocmd.h | 21 | ||||
-rw-r--r-- | src/nvim/buffer.c | 15 | ||||
-rw-r--r-- | src/nvim/debugger.c | 36 | ||||
-rw-r--r-- | src/nvim/eval.c | 25 | ||||
-rw-r--r-- | src/nvim/eval/funcs.c | 13 | ||||
-rw-r--r-- | src/nvim/eval/typval.h | 2 | ||||
-rw-r--r-- | src/nvim/eval/userfunc.c | 162 | ||||
-rw-r--r-- | src/nvim/ex_docmd.c | 46 | ||||
-rw-r--r-- | src/nvim/ex_eval.c | 20 | ||||
-rw-r--r-- | src/nvim/ex_eval_defs.h | 6 | ||||
-rw-r--r-- | src/nvim/globals.h | 8 | ||||
-rw-r--r-- | src/nvim/highlight_group.c | 14 | ||||
-rw-r--r-- | src/nvim/lua/executor.c | 6 | ||||
-rw-r--r-- | src/nvim/main.c | 19 | ||||
-rw-r--r-- | src/nvim/mapping.c | 5 | ||||
-rw-r--r-- | src/nvim/message.c | 57 | ||||
-rw-r--r-- | src/nvim/option.c | 2 | ||||
-rw-r--r-- | src/nvim/profile.c | 11 | ||||
-rw-r--r-- | src/nvim/runtime.c | 140 | ||||
-rw-r--r-- | src/nvim/runtime.h | 37 | ||||
-rw-r--r-- | src/nvim/spellfile.c | 13 | ||||
-rw-r--r-- | src/nvim/testdir/test_autocmd.vim | 22 | ||||
-rw-r--r-- | src/nvim/testdir/test_vimscript.vim | 17 | ||||
-rw-r--r-- | src/nvim/testing.c | 15 | ||||
-rw-r--r-- | src/nvim/usercmd.c | 5 |
26 files changed, 463 insertions, 278 deletions
diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c index 4ffd7a4850..0d8efbb830 100644 --- a/src/nvim/autocmd.c +++ b/src/nvim/autocmd.c @@ -27,6 +27,7 @@ #include "nvim/os/input.h" #include "nvim/profile.h" #include "nvim/regexp.h" +#include "nvim/runtime.h" #include "nvim/search.h" #include "nvim/state.h" #include "nvim/ui_compositor.h" @@ -1143,7 +1144,7 @@ int autocmd_register(int64_t id, event_T event, char *pat, int patlen, int group ac->id = id; ac->exec = aucmd_exec_copy(aucmd); ac->script_ctx = current_sctx; - ac->script_ctx.sc_lnum += sourcing_lnum; + ac->script_ctx.sc_lnum += SOURCING_LNUM; nlua_set_sctx(&ac->script_ctx); ac->next = NULL; ac->once = once; @@ -1771,10 +1772,9 @@ bool apply_autocmds_group(event_T event, char *fname, char *fname_io, bool force // Don't redraw while doing autocommands. RedrawingDisabled++; - char *save_sourcing_name = sourcing_name; - sourcing_name = NULL; // don't free this one - linenr_T save_sourcing_lnum = sourcing_lnum; - sourcing_lnum = 0; // no line number here + + // name and lnum are filled in later + estack_push(ETYPE_AUCMD, NULL, 0); const sctx_T save_current_sctx = current_sctx; @@ -1878,9 +1878,8 @@ bool apply_autocmds_group(event_T event, char *fname, char *fname_io, bool force autocmd_busy = save_autocmd_busy; filechangeshell_busy = false; autocmd_nested = save_autocmd_nested; - xfree(sourcing_name); - sourcing_name = save_sourcing_name; - sourcing_lnum = save_sourcing_lnum; + xfree(SOURCING_NAME); + estack_pop(); xfree(autocmd_fname); autocmd_fname = save_autocmd_fname; autocmd_bufnr = save_autocmd_bufnr; @@ -1983,8 +1982,9 @@ void auto_next_pat(AutoPatCmd *apc, int stop_at_last) AutoPat *ap; AutoCmd *cp; char *s; + char **const sourcing_namep = &SOURCING_NAME; - XFREE_CLEAR(sourcing_name); + XFREE_CLEAR(*sourcing_namep); for (ap = apc->curpat; ap != NULL && !got_int; ap = ap->next) { apc->curpat = NULL; @@ -2009,11 +2009,11 @@ void auto_next_pat(AutoPatCmd *apc, int stop_at_last) const size_t sourcing_name_len = (STRLEN(s) + strlen(name) + (size_t)ap->patlen + 1); - sourcing_name = xmalloc(sourcing_name_len); - snprintf(sourcing_name, sourcing_name_len, s, name, ap->pat); + *sourcing_namep = xmalloc(sourcing_name_len); + snprintf(*sourcing_namep, sourcing_name_len, s, name, ap->pat); if (p_verbose >= 8) { verbose_enter(); - smsg(_("Executing %s"), sourcing_name); + smsg(_("Executing %s"), *sourcing_namep); verbose_leave(); } diff --git a/src/nvim/autocmd.h b/src/nvim/autocmd.h index a085a03455..d559d8c3d2 100644 --- a/src/nvim/autocmd.h +++ b/src/nvim/autocmd.h @@ -22,7 +22,8 @@ typedef struct { bool save_VIsual_active; ///< saved VIsual_active } aco_save_T; -typedef struct AutoCmd { +typedef struct AutoCmd_S AutoCmd; +struct AutoCmd_S { AucmdExecutable exec; bool once; // "One shot": removed after execution bool nested; // If autocommands nest here @@ -30,11 +31,12 @@ typedef struct AutoCmd { int64_t id; // ID used for uniquely tracking an autocmd. sctx_T script_ctx; // script context where defined char *desc; // Description for the autocmd. - struct AutoCmd *next; // Next AutoCmd in list -} AutoCmd; + AutoCmd *next; // Next AutoCmd in list +}; -typedef struct AutoPat { - struct AutoPat *next; // next AutoPat in AutoPat list; MUST +typedef struct AutoPat_S AutoPat; +struct AutoPat_S { + AutoPat *next; // next AutoPat in AutoPat list; MUST // be the first entry char *pat; // pattern as typed (NULL when pattern // has been removed) @@ -45,10 +47,11 @@ typedef struct AutoPat { int buflocal_nr; // !=0 for buffer-local AutoPat char allow_dirs; // Pattern may match whole path char last; // last pattern for apply_autocmds() -} AutoPat; +}; /// Struct used to keep status while executing autocommands for an event. -typedef struct AutoPatCmd { +typedef struct AutoPatCmd_S AutoPatCmd; +struct AutoPatCmd_S { AutoPat *curpat; // next AutoPat to examine AutoCmd *nextcmd; // next AutoCmd to execute int group; // group being used @@ -58,8 +61,8 @@ typedef struct AutoPatCmd { event_T event; // current event int arg_bufnr; // initially equal to <abuf>, set to zero when buf is deleted Object *data; // arbitrary data - struct AutoPatCmd *next; // chain of active apc-s for auto-invalidation -} AutoPatCmd; + AutoPatCmd *next; // chain of active apc-s for auto-invalidation +}; // Set by the apply_autocmds_group function if the given event is equal to // EVENT_FILETYPE. Used by the readfile function in order to determine if diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index be376c2109..6262f2d61c 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -70,6 +70,7 @@ #include "nvim/plines.h" #include "nvim/quickfix.h" #include "nvim/regexp.h" +#include "nvim/runtime.h" #include "nvim/screen.h" #include "nvim/sign.h" #include "nvim/spell.h" @@ -5149,8 +5150,6 @@ static int chk_modeline(linenr_T lnum, int flags) intmax_t vers; int end; int retval = OK; - char *save_sourcing_name; - linenr_T save_sourcing_lnum; prev = -1; for (s = (char *)ml_get(lnum); *s != NUL; s++) { @@ -5195,10 +5194,8 @@ static int chk_modeline(linenr_T lnum, int flags) s = linecopy = xstrdup(s); // copy the line, it will change - save_sourcing_lnum = sourcing_lnum; - save_sourcing_name = sourcing_name; - sourcing_lnum = lnum; // prepare for emsg() - sourcing_name = "modelines"; + // prepare for emsg() + estack_push(ETYPE_MODELINE, "modelines", lnum); end = false; while (end == false) { @@ -5238,7 +5235,7 @@ static int chk_modeline(linenr_T lnum, int flags) const sctx_T save_current_sctx = current_sctx; current_sctx.sc_sid = SID_MODELINE; current_sctx.sc_seq = 0; - current_sctx.sc_lnum = 0; + current_sctx.sc_lnum = lnum; // Make sure no risky things are executed as a side effect. secure = 1; @@ -5253,9 +5250,7 @@ static int chk_modeline(linenr_T lnum, int flags) s = e + 1; // advance to next part } - sourcing_lnum = save_sourcing_lnum; - sourcing_name = save_sourcing_name; - + estack_pop(); xfree(linecopy); return retval; diff --git a/src/nvim/debugger.c b/src/nvim/debugger.c index 0eaff06833..76e1caff49 100644 --- a/src/nvim/debugger.c +++ b/src/nvim/debugger.c @@ -17,6 +17,7 @@ #include "nvim/os/os.h" #include "nvim/pos.h" #include "nvim/regexp.h" +#include "nvim/runtime.h" #include "nvim/screen.h" #include "nvim/types.h" #include "nvim/vim.h" @@ -98,14 +99,17 @@ void do_debug(char_u *cmd) xfree(debug_newval); debug_newval = NULL; } - if (sourcing_name != NULL) { - msg(sourcing_name); + char *sname = estack_sfile(); + if (sname != NULL) { + msg(sname); } - if (sourcing_lnum != 0) { - smsg(_("line %" PRId64 ": %s"), (int64_t)sourcing_lnum, cmd); + xfree(sname); + if (SOURCING_LNUM != 0) { + smsg(_("line %" PRId64 ": %s"), (int64_t)SOURCING_LNUM, cmd); } else { smsg(_("cmd: %s"), cmd); } + // Repeat getting a command and executing it. for (;;) { msg_scroll = true; @@ -287,12 +291,12 @@ void do_debug(char_u *cmd) debug_did_msg = true; } -static int get_maxbacktrace_level(void) +static int get_maxbacktrace_level(char *sname) { int maxbacktrace = 0; - if (sourcing_name != NULL) { - char *p = sourcing_name; + if (sname != NULL) { + char *p = sname; char *q; while ((q = strstr(p, "..")) != NULL) { p = q + 2; @@ -320,20 +324,24 @@ static void do_checkbacktracelevel(void) debug_backtrace_level = 0; msg(_("frame is zero")); } else { - int max = get_maxbacktrace_level(); + char *sname = estack_sfile(); + int max = get_maxbacktrace_level(sname); + if (debug_backtrace_level > max) { debug_backtrace_level = max; smsg(_("frame at highest level: %d"), max); } + xfree(sname); } } static void do_showbacktrace(char_u *cmd) { - if (sourcing_name != NULL) { + char *sname = estack_sfile(); + int max = get_maxbacktrace_level(sname); + if (sname != NULL) { int i = 0; - int max = get_maxbacktrace_level(); - char *cur = sourcing_name; + char *cur = sname; while (!got_int) { char *next = strstr(cur, ".."); if (next != NULL) { @@ -351,9 +359,11 @@ static void do_showbacktrace(char_u *cmd) *next = '.'; cur = next + 2; } + xfree(sname); } - if (sourcing_lnum != 0) { - smsg(_("line %" PRId64 ": %s"), (int64_t)sourcing_lnum, cmd); + + if (SOURCING_LNUM != 0) { + smsg(_("line %" PRId64 ": %s"), (int64_t)SOURCING_LNUM, cmd); } else { smsg(_("cmd: %s"), cmd); } diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 0cd2c7314d..ff94cf5944 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -49,6 +49,7 @@ #include "nvim/profile.h" #include "nvim/quickfix.h" #include "nvim/regexp.h" +#include "nvim/runtime.h" #include "nvim/screen.h" #include "nvim/search.h" #include "nvim/sign.h" @@ -4187,6 +4188,23 @@ bool garbage_collect(bool testing) garbage_collect_at_exit = false; } + // The execution stack can grow big, limit the size. + if (exestack.ga_maxlen - exestack.ga_len > 500) { + // Keep 150% of the current size, with a minimum of the growth size. + int n = exestack.ga_len / 2; + if (n < exestack.ga_growsize) { + n = exestack.ga_growsize; + } + + // Don't make it bigger though. + if (exestack.ga_len + n < exestack.ga_maxlen) { + size_t new_len = (size_t)exestack.ga_itemsize * (size_t)(exestack.ga_len + n); + char *pp = xrealloc(exestack.ga_data, new_len); + exestack.ga_maxlen = exestack.ga_len + n; + exestack.ga_data = pp; + } + } + // We advance by two (COPYID_INC) because we add one for items referenced // through previous_funccal. const int copyID = get_copyID(); @@ -8613,8 +8631,7 @@ typval_T eval_call_provider(char *provider, char *method, list_T *arguments, boo struct caller_scope saved_provider_caller_scope = provider_caller_scope; provider_caller_scope = (struct caller_scope) { .script_ctx = current_sctx, - .sourcing_name = sourcing_name, - .sourcing_lnum = sourcing_lnum, + .es_entry = ((estack_T *)exestack.ga_data)[exestack.ga_len - 1], .autocmd_fname = autocmd_fname, .autocmd_match = autocmd_match, .autocmd_bufnr = autocmd_bufnr, @@ -8713,8 +8730,8 @@ bool eval_has_provider(const char *feat) /// Writes "<sourcing_name>:<sourcing_lnum>" to `buf[bufsize]`. void eval_fmt_source_name_line(char *buf, size_t bufsize) { - if (sourcing_name) { - snprintf(buf, bufsize, "%s:%" PRIdLINENR, sourcing_name, sourcing_lnum); + if (SOURCING_NAME) { + snprintf(buf, bufsize, "%s:%" PRIdLINENR, SOURCING_NAME, SOURCING_LNUM); } else { snprintf(buf, bufsize, "?"); } diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index e13046ef82..fe3c0f825e 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -62,6 +62,7 @@ #include "nvim/profile.h" #include "nvim/quickfix.h" #include "nvim/regexp.h" +#include "nvim/runtime.h" #include "nvim/screen.h" #include "nvim/search.h" #include "nvim/sha256.h" @@ -7317,8 +7318,7 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, FunPtr fptr) } sctx_T save_current_sctx; - char *save_sourcing_name, *save_autocmd_fname, *save_autocmd_match; - linenr_T save_sourcing_lnum; + char *save_autocmd_fname, *save_autocmd_match; int save_autocmd_bufnr; funccal_entry_T funccal_entry; @@ -7326,16 +7326,14 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, FunPtr fptr) // If this is called from a provider function, restore the scope // information of the caller. save_current_sctx = current_sctx; - save_sourcing_name = sourcing_name; - save_sourcing_lnum = sourcing_lnum; save_autocmd_fname = autocmd_fname; save_autocmd_match = autocmd_match; save_autocmd_bufnr = autocmd_bufnr; save_funccal(&funccal_entry); current_sctx = provider_caller_scope.script_ctx; - sourcing_name = provider_caller_scope.sourcing_name; - sourcing_lnum = provider_caller_scope.sourcing_lnum; + ga_grow(&exestack, 1); + ((estack_T *)exestack.ga_data)[exestack.ga_len++] = provider_caller_scope.es_entry; autocmd_fname = provider_caller_scope.autocmd_fname; autocmd_match = provider_caller_scope.autocmd_match; autocmd_bufnr = provider_caller_scope.autocmd_bufnr; @@ -7352,8 +7350,7 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, FunPtr fptr) if (l_provider_call_nesting) { current_sctx = save_current_sctx; - sourcing_name = save_sourcing_name; - sourcing_lnum = save_sourcing_lnum; + exestack.ga_len--; autocmd_fname = save_autocmd_fname; autocmd_match = save_autocmd_match; autocmd_bufnr = save_autocmd_bufnr; diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h index e411419a07..c4bc9f603b 100644 --- a/src/nvim/eval/typval.h +++ b/src/nvim/eval/typval.h @@ -355,6 +355,8 @@ struct ufunc { ///< used for s: variables int uf_refcount; ///< reference count, see func_name_refcount() funccall_T *uf_scoped; ///< l: local variables for closure + char_u *uf_name_exp; ///< if "uf_name[]" starts with SNR the name with + ///< "<SNR>" as a string, otherwise NULL char_u uf_name[]; ///< Name of function (actual size equals name); ///< can start with <SNR>123_ ///< (<SNR> is K_SPECIAL KS_EXTRA KE_SNR) diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index 3a69e40acb..c527c70be0 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -23,6 +23,7 @@ #include "nvim/os/input.h" #include "nvim/profile.h" #include "nvim/regexp.h" +#include "nvim/runtime.h" #include "nvim/search.h" #include "nvim/ui.h" #include "nvim/vim.h" @@ -219,6 +220,17 @@ char_u *get_lambda_name(void) return name; } +static void set_ufunc_name(ufunc_T *fp, char_u *name) +{ + STRCPY(fp->uf_name, name); + + if (name[0] == K_SPECIAL) { + fp->uf_name_exp = xmalloc(STRLEN(name) + 3); + STRCPY(fp->uf_name_exp, "<SNR>"); + STRCAT(fp->uf_name_exp, fp->uf_name + 3); + } +} + /// Parse a lambda expression and get a Funcref from "*arg". /// /// @return OK or FAIL. Returns NOTDONE for dict or {expr}. @@ -297,7 +309,7 @@ int get_lambda_tv(char **arg, typval_T *rettv, bool evaluate) } fp->uf_refcount = 1; - STRCPY(fp->uf_name, name); + set_ufunc_name(fp, name); hash_add(&func_hashtab, UF2HIKEY(fp)); fp->uf_args = newargs; ga_init(&fp->uf_def_args, (int)sizeof(char_u *), 1); @@ -319,7 +331,7 @@ int get_lambda_tv(char **arg, typval_T *rettv, bool evaluate) fp->uf_flags = flags; fp->uf_calls = 0; fp->uf_script_ctx = current_sctx; - fp->uf_script_ctx.sc_lnum += sourcing_lnum - newlines.ga_len; + fp->uf_script_ctx.sc_lnum += SOURCING_LNUM - newlines.ga_len; pt->pt_func = fp; pt->pt_refcount = 1; @@ -744,6 +756,7 @@ static void func_clear_items(ufunc_T *fp) ga_clear_strings(&(fp->uf_args)); ga_clear_strings(&(fp->uf_def_args)); ga_clear_strings(&(fp->uf_lines)); + XFREE_CLEAR(fp->uf_name_exp); if (fp->uf_cb_free != NULL) { fp->uf_cb_free(fp->uf_cb_state); @@ -807,8 +820,6 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett linenr_T firstline, linenr_T lastline, dict_T *selfdict) FUNC_ATTR_NONNULL_ARG(1, 3, 4) { - char_u *save_sourcing_name; - linenr_T save_sourcing_lnum; bool using_sandbox = false; funccall_T *fc; int save_did_emsg; @@ -998,73 +1009,49 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett // Don't redraw while executing the function. RedrawingDisabled++; - save_sourcing_name = (char_u *)sourcing_name; - save_sourcing_lnum = sourcing_lnum; - sourcing_lnum = 1; if (fp->uf_flags & FC_SANDBOX) { using_sandbox = true; sandbox++; } - // need space for new sourcing_name: - // * save_sourcing_name - // * "["number"].." or "function " - // * "<SNR>" + fp->uf_name - 3 - // * terminating NUL - size_t len = (save_sourcing_name == NULL ? 0 : STRLEN(save_sourcing_name)) - + STRLEN(fp->uf_name) + 27; - sourcing_name = xmalloc(len); - { - if (save_sourcing_name != NULL - && STRNCMP(save_sourcing_name, "function ", 9) == 0) { - vim_snprintf(sourcing_name, - len, - "%s[%" PRId64 "]..", - save_sourcing_name, - (int64_t)save_sourcing_lnum); - } else { - STRCPY(sourcing_name, "function "); - } - cat_func_name((char_u *)sourcing_name + STRLEN(sourcing_name), fp); - - if (p_verbose >= 12) { - ++no_wait_return; - verbose_enter_scroll(); + estack_push_ufunc(fp, 1); + if (p_verbose >= 12) { + ++no_wait_return; + verbose_enter_scroll(); - smsg(_("calling %s"), sourcing_name); - if (p_verbose >= 14) { - msg_puts("("); - for (int i = 0; i < argcount; i++) { - if (i > 0) { - msg_puts(", "); - } - if (argvars[i].v_type == VAR_NUMBER) { - msg_outnum((long)argvars[i].vval.v_number); - } else { - // Do not want errors such as E724 here. - emsg_off++; - char *tofree = encode_tv2string(&argvars[i], NULL); - emsg_off--; - if (tofree != NULL) { - char *s = tofree; - char buf[MSG_BUF_LEN]; - if (vim_strsize(s) > MSG_BUF_CLEN) { - trunc_string(s, buf, MSG_BUF_CLEN, sizeof(buf)); - s = buf; - } - msg_puts(s); - xfree(tofree); + smsg(_("calling %s"), SOURCING_NAME); + if (p_verbose >= 14) { + msg_puts("("); + for (int i = 0; i < argcount; i++) { + if (i > 0) { + msg_puts(", "); + } + if (argvars[i].v_type == VAR_NUMBER) { + msg_outnum((long)argvars[i].vval.v_number); + } else { + // Do not want errors such as E724 here. + emsg_off++; + char *tofree = encode_tv2string(&argvars[i], NULL); + emsg_off--; + if (tofree != NULL) { + char *s = tofree; + char buf[MSG_BUF_LEN]; + if (vim_strsize(s) > MSG_BUF_CLEN) { + trunc_string(s, buf, MSG_BUF_CLEN, sizeof(buf)); + s = buf; } + msg_puts(s); + xfree(tofree); } } - msg_puts(")"); } - msg_puts("\n"); // don't overwrite this either - - verbose_leave_scroll(); - --no_wait_return; + msg_puts(")"); } + msg_puts("\n"); // don't overwrite this either + + verbose_leave_scroll(); + --no_wait_return; } const bool do_profiling_yes = do_profiling == PROF_YES; @@ -1148,10 +1135,10 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett verbose_enter_scroll(); if (aborting()) { - smsg(_("%s aborted"), sourcing_name); + smsg(_("%s aborted"), SOURCING_NAME); } else if (fc->rettv->v_type == VAR_NUMBER) { smsg(_("%s returning #%" PRId64 ""), - sourcing_name, (int64_t)fc->rettv->vval.v_number); + SOURCING_NAME, (int64_t)fc->rettv->vval.v_number); } else { char buf[MSG_BUF_LEN]; @@ -1167,7 +1154,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett trunc_string(s, buf, MSG_BUF_CLEN, MSG_BUF_LEN); s = buf; } - smsg(_("%s returning %s"), sourcing_name, s); + smsg(_("%s returning %s"), SOURCING_NAME, s); xfree(tofree); } } @@ -1177,9 +1164,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett --no_wait_return; } - xfree(sourcing_name); - sourcing_name = (char *)save_sourcing_name; - sourcing_lnum = save_sourcing_lnum; + estack_pop(); current_sctx = save_current_sctx; if (do_profiling_yes) { script_prof_restore(&wait_start); @@ -1188,15 +1173,15 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rett sandbox--; } - if (p_verbose >= 12 && sourcing_name != NULL) { - ++no_wait_return; + if (p_verbose >= 12 && SOURCING_NAME != NULL) { + no_wait_return++; verbose_enter_scroll(); - smsg(_("continuing in %s"), sourcing_name); + smsg(_("continuing in %s"), SOURCING_NAME); msg_puts("\n"); // don't overwrite this either verbose_leave_scroll(); - --no_wait_return; + no_wait_return--; } did_emsg |= save_did_emsg; @@ -1637,9 +1622,8 @@ static void list_func_head(ufunc_T *fp, int indent, bool force) msg_puts(" "); } msg_puts(force ? "function! " : "function "); - if (fp->uf_name[0] == K_SPECIAL) { - msg_puts_attr("<SNR>", HL_ATTR(HLF_8)); - msg_puts((const char *)fp->uf_name + 3); + if (fp->uf_name_exp != NULL) { + msg_puts((const char *)fp->uf_name_exp); } else { msg_puts((const char *)fp->uf_name); } @@ -2196,7 +2180,7 @@ void ex_function(exarg_T *eap) } // Save the starting line number. - sourcing_lnum_top = sourcing_lnum; + sourcing_lnum_top = SOURCING_LNUM; indent = 2; nesting = 0; @@ -2238,10 +2222,10 @@ void ex_function(exarg_T *eap) ui_ext_cmdline_block_append((size_t)indent, (const char *)theline); } - // Detect line continuation: sourcing_lnum increased more than one. + // Detect line continuation: SOURCING_LNUM increased more than one. sourcing_lnum_off = get_sourced_lnum(eap->getline, eap->cookie); - if (sourcing_lnum < sourcing_lnum_off) { - sourcing_lnum_off -= sourcing_lnum; + if (SOURCING_LNUM < sourcing_lnum_off) { + sourcing_lnum_off -= SOURCING_LNUM; } else { sourcing_lnum_off = 0; } @@ -2458,9 +2442,12 @@ void ex_function(exarg_T *eap) fp = NULL; overwrite = true; } else { - // redefine existing function + char_u *exp_name = fp->uf_name_exp; + // redefine existing function, keep the expanded name XFREE_CLEAR(name); + fp->uf_name_exp = NULL; func_clear_items(fp); + fp->uf_name_exp = exp_name; fp->uf_profiling = false; fp->uf_prof_initialized = false; } @@ -2499,13 +2486,12 @@ void ex_function(exarg_T *eap) // Check that the autoload name matches the script name. int j = FAIL; - if (sourcing_name != NULL) { + if (SOURCING_NAME != NULL) { scriptname = (char_u *)autoload_name((const char *)name, STRLEN(name)); p = (char_u *)vim_strchr((char *)scriptname, '/'); plen = (int)STRLEN(p); - slen = (int)STRLEN(sourcing_name); - if (slen > plen && FNAMECMP(p, - sourcing_name + slen - plen) == 0) { + slen = (int)STRLEN(SOURCING_NAME); + if (slen > plen && FNAMECMP(p, SOURCING_NAME + slen - plen) == 0) { j = OK; } xfree(scriptname); @@ -2540,7 +2526,7 @@ void ex_function(exarg_T *eap) } // insert the new function in the function list - STRCPY(fp->uf_name, name); + set_ufunc_name(fp, name); if (overwrite) { hi = hash_find(&func_hashtab, (char *)name); hi->hi_key = UF2HIKEY(fp); @@ -3148,8 +3134,7 @@ char *get_func_line(int c, void *cookie, int indent, bool do_concat) // If breakpoints have been added/deleted need to check for it. if (fcp->dbg_tick != debug_tick) { - fcp->breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name, - sourcing_lnum); + fcp->breakpoint = dbg_find_breakpoint(false, fp->uf_name, SOURCING_LNUM); fcp->dbg_tick = debug_tick; } if (do_profiling == PROF_YES) { @@ -3170,7 +3155,7 @@ char *get_func_line(int c, void *cookie, int indent, bool do_concat) retval = NULL; } else { retval = (char_u *)xstrdup(((char **)(gap->ga_data))[fcp->linenr++]); - sourcing_lnum = fcp->linenr; + SOURCING_LNUM = fcp->linenr; if (do_profiling == PROF_YES) { func_line_start(cookie); } @@ -3178,11 +3163,10 @@ char *get_func_line(int c, void *cookie, int indent, bool do_concat) } // Did we encounter a breakpoint? - if (fcp->breakpoint != 0 && fcp->breakpoint <= sourcing_lnum) { - dbg_breakpoint(fp->uf_name, sourcing_lnum); + if (fcp->breakpoint != 0 && fcp->breakpoint <= SOURCING_LNUM) { + dbg_breakpoint(fp->uf_name, SOURCING_LNUM); // Find next breakpoint. - fcp->breakpoint = dbg_find_breakpoint(false, fp->uf_name, - sourcing_lnum); + fcp->breakpoint = dbg_find_breakpoint(false, fp->uf_name, SOURCING_LNUM); fcp->dbg_tick = debug_tick; } diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index a681b3c693..5ea6a224d6 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -373,7 +373,7 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) breakpoint = func_breakpoint(real_cookie); dbg_tick = func_dbg_tick(real_cookie); } else if (getline_equal(fgetline, cookie, getsourceline)) { - fname = sourcing_name; + fname = SOURCING_NAME; breakpoint = source_breakpoint(real_cookie); dbg_tick = source_dbg_tick(real_cookie); } @@ -466,20 +466,19 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) if (breakpoint != NULL && dbg_tick != NULL && *dbg_tick != debug_tick) { *breakpoint = dbg_find_breakpoint(getline_equal(fgetline, cookie, getsourceline), - (char_u *)fname, sourcing_lnum); + (char_u *)fname, SOURCING_LNUM); *dbg_tick = debug_tick; } next_cmdline = ((wcmd_T *)(lines_ga.ga_data))[current_line].line; - sourcing_lnum = ((wcmd_T *)(lines_ga.ga_data))[current_line].lnum; + SOURCING_LNUM = ((wcmd_T *)(lines_ga.ga_data))[current_line].lnum; // Did we encounter a breakpoint? - if (breakpoint != NULL && *breakpoint != 0 - && *breakpoint <= sourcing_lnum) { - dbg_breakpoint((char_u *)fname, sourcing_lnum); + if (breakpoint != NULL && *breakpoint != 0 && *breakpoint <= SOURCING_LNUM) { + dbg_breakpoint((char_u *)fname, SOURCING_LNUM); // Find next breakpoint. *breakpoint = dbg_find_breakpoint(getline_equal(fgetline, cookie, getsourceline), - (char_u *)fname, sourcing_lnum); + (char_u *)fname, SOURCING_LNUM); *dbg_tick = debug_tick; } if (do_profiling == PROF_YES) { @@ -582,8 +581,8 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) } } - if ((p_verbose >= 15 && sourcing_name != NULL) || p_verbose >= 16) { - msg_verbose_cmd(sourcing_lnum, cmdline_copy); + if ((p_verbose >= 15 && SOURCING_NAME != NULL) || p_verbose >= 16) { + msg_verbose_cmd(SOURCING_LNUM, cmdline_copy); } /* @@ -683,7 +682,7 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) */ if (cstack.cs_looplevel == 0) { if (!GA_EMPTY(&lines_ga)) { - sourcing_lnum = ((wcmd_T *)lines_ga.ga_data)[lines_ga.ga_len - 1].lnum; + SOURCING_LNUM = ((wcmd_T *)lines_ga.ga_data)[lines_ga.ga_len - 1].lnum; GA_DEEP_CLEAR(&lines_ga, wcmd_T, FREE_WCMD); } current_line = 0; @@ -800,8 +799,6 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) // commands are executed. if (current_exception) { char *p = NULL; - char *saved_sourcing_name; - linenr_T saved_sourcing_lnum; msglist_T *messages = NULL; msglist_T *next; @@ -826,10 +823,7 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) break; } - saved_sourcing_name = sourcing_name; - saved_sourcing_lnum = sourcing_lnum; - sourcing_name = current_exception->throw_name; - sourcing_lnum = current_exception->throw_lnum; + estack_push(ETYPE_EXCEPT, current_exception->throw_name, current_exception->throw_lnum); current_exception->throw_name = NULL; discard_current_exception(); // uses IObuff if 'verbose' @@ -849,9 +843,8 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) emsg(p); xfree(p); } - xfree(sourcing_name); - sourcing_name = saved_sourcing_name; - sourcing_lnum = saved_sourcing_lnum; + xfree(SOURCING_NAME); + estack_pop(); } else if (got_int || (did_emsg && force_abort)) { // On an interrupt or an aborting error not converted to an exception, // disable the conversion of errors to exceptions. (Interrupts are not @@ -979,7 +972,7 @@ static char *get_loop_line(int c, void *cookie, int indent, bool do_concat) KeyTyped = false; cp->current_line++; wp = (wcmd_T *)(cp->lines_gap->ga_data) + cp->current_line; - sourcing_lnum = wp->lnum; + SOURCING_LNUM = wp->lnum; return xstrdup(wp->line); } @@ -988,7 +981,7 @@ static void store_loop_line(garray_T *gap, char *line) { wcmd_T *p = GA_APPEND_VIA_PTR(wcmd_T, gap); p->line = xstrdup(line); - p->lnum = sourcing_lnum; + p->lnum = SOURCING_LNUM; } /// If "fgetline" is get_loop_line(), return TRUE if the getline it uses equals @@ -7919,29 +7912,30 @@ char_u *eval_vars(char_u *src, char_u *srcstart, size_t *usedlen, linenr_T *lnum break; case SPEC_SFILE: // file name for ":so" command - result = sourcing_name; + result = estack_sfile(); if (result == NULL) { *errormsg = _("E498: no :source file name to substitute for \"<sfile>\""); return NULL; } + resultbuf = result; // remember allocated string break; case SPEC_SLNUM: // line in file for ":so" command - if (sourcing_name == NULL || sourcing_lnum == 0) { + if (SOURCING_NAME == NULL || SOURCING_LNUM == 0) { *errormsg = _("E842: no line number to use for \"<slnum>\""); return NULL; } - snprintf(strbuf, sizeof(strbuf), "%" PRIdLINENR, sourcing_lnum); + snprintf(strbuf, sizeof(strbuf), "%" PRIdLINENR, SOURCING_LNUM); result = strbuf; break; case SPEC_SFLNUM: // line in script file - if (current_sctx.sc_lnum + sourcing_lnum == 0) { + if (current_sctx.sc_lnum + SOURCING_LNUM == 0) { *errormsg = _("E961: no line number to use for \"<sflnum>\""); return NULL; } snprintf((char *)strbuf, sizeof(strbuf), "%" PRIdLINENR, - current_sctx.sc_lnum + sourcing_lnum); + current_sctx.sc_lnum + SOURCING_LNUM); result = strbuf; break; diff --git a/src/nvim/ex_eval.c b/src/nvim/ex_eval.c index 9e029aa68a..66c782d12e 100644 --- a/src/nvim/ex_eval.c +++ b/src/nvim/ex_eval.c @@ -275,6 +275,11 @@ bool cause_errthrow(const char *mesg, bool severe, bool *ignore) (*msg_list)->throw_msg = tmsg; } } + + // Get the source name and lnum now, it may change before + // reaching do_errthrow(). + elem->sfile = estack_sfile(); + elem->slnum = SOURCING_LNUM; } return true; } @@ -289,6 +294,7 @@ static void free_msglist(msglist_T *l) while (messages != NULL) { next = messages->next; xfree(messages->msg); + xfree(messages->sfile); xfree(messages); messages = next; } @@ -478,8 +484,18 @@ static int throw_exception(void *value, except_type_T type, char *cmdname) } excp->type = type; - excp->throw_name = xstrdup(sourcing_name == NULL ? "" : sourcing_name); - excp->throw_lnum = sourcing_lnum; + if (type == ET_ERROR && ((msglist_T *)value)->sfile != NULL) { + msglist_T *entry = (msglist_T *)value; + excp->throw_name = entry->sfile; + entry->sfile = NULL; + excp->throw_lnum = entry->slnum; + } else { + excp->throw_name = estack_sfile(); + if (excp->throw_name == NULL) { + excp->throw_name = xstrdup(""); + } + excp->throw_lnum = SOURCING_LNUM; + } if (p_verbose >= 13 || debug_break_level > 0) { int save_msg_silent = msg_silent; diff --git a/src/nvim/ex_eval_defs.h b/src/nvim/ex_eval_defs.h index 75150d6da4..9da0c9ad12 100644 --- a/src/nvim/ex_eval_defs.h +++ b/src/nvim/ex_eval_defs.h @@ -38,11 +38,13 @@ enum { /// A list of error messages that can be converted to an exception. "throw_msg" /// is only set in the first element of the list. Usually, it points to the /// original message stored in that element, but sometimes it points to a later -/// message in the list. See cause_errthrow() below. +/// message in the list. See cause_errthrow(). typedef struct msglist msglist_T; struct msglist { - char *msg; ///< original message + char *msg; ///< original message, allocated char *throw_msg; ///< msg to throw: usually original one + char *sfile; ///< value from estack_sfile(), allocated + linenr_T slnum; ///< line number for "sfile" msglist_T *next; ///< next of several messages in a row }; diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 199dd7e8e2..a3ef859276 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -12,6 +12,7 @@ #include "nvim/mbyte.h" #include "nvim/menu.h" #include "nvim/os/os_defs.h" +#include "nvim/runtime.h" #include "nvim/syntax_defs.h" #include "nvim/types.h" @@ -248,9 +249,6 @@ EXTERN int lines_left INIT(= -1); // lines left for listing EXTERN int msg_no_more INIT(= false); // don't use more prompt, truncate // messages -EXTERN char *sourcing_name INIT(= NULL); // name of error message source -EXTERN linenr_T sourcing_lnum INIT(= 0); // line number of the source file - EXTERN int ex_nesting_level INIT(= 0); // nesting level EXTERN int debug_break_level INIT(= -1); // break below this level EXTERN bool debug_did_msg INIT(= false); // did "debug mode" message @@ -348,8 +346,8 @@ EXTERN bool did_source_packages INIT(= false); // provider function call EXTERN struct caller_scope { sctx_T script_ctx; - char *sourcing_name, *autocmd_fname, *autocmd_match; - linenr_T sourcing_lnum; + estack_T es_entry; + char *autocmd_fname, *autocmd_match; int autocmd_bufnr; void *funccalp; } provider_caller_scope; diff --git a/src/nvim/highlight_group.c b/src/nvim/highlight_group.c index 42db85b3eb..d79283d3e3 100644 --- a/src/nvim/highlight_group.c +++ b/src/nvim/highlight_group.c @@ -691,12 +691,12 @@ void set_hl_group(int id, HlAttrs attrs, Dict(highlight) *dict, int link_id) g->sg_cleared = false; g->sg_link = link_id; g->sg_script_ctx = current_sctx; - g->sg_script_ctx.sc_lnum += sourcing_lnum; + g->sg_script_ctx.sc_lnum += SOURCING_LNUM; g->sg_set |= SG_LINK; if (is_default) { g->sg_deflink = link_id; g->sg_deflink_sctx = current_sctx; - g->sg_deflink_sctx.sc_lnum += sourcing_lnum; + g->sg_deflink_sctx.sc_lnum += SOURCING_LNUM; } return; } @@ -735,7 +735,7 @@ void set_hl_group(int id, HlAttrs attrs, Dict(highlight) *dict, int link_id) g->sg_blend = attrs.hl_blend; g->sg_script_ctx = current_sctx; - g->sg_script_ctx.sc_lnum += sourcing_lnum; + g->sg_script_ctx.sc_lnum += SOURCING_LNUM; g->sg_attr = hl_get_syn_attr(0, id, attrs); @@ -863,7 +863,7 @@ void do_highlight(const char *line, const bool forceit, const bool init) if (dodefault && (forceit || hlgroup->sg_deflink == 0)) { hlgroup->sg_deflink = to_id; hlgroup->sg_deflink_sctx = current_sctx; - hlgroup->sg_deflink_sctx.sc_lnum += sourcing_lnum; + hlgroup->sg_deflink_sctx.sc_lnum += SOURCING_LNUM; nlua_set_sctx(&hlgroup->sg_deflink_sctx); } } @@ -873,7 +873,7 @@ void do_highlight(const char *line, const bool forceit, const bool init) // for the group, unless '!' is used if (to_id > 0 && !forceit && !init && hl_has_settings(from_id - 1, dodefault)) { - if (sourcing_name == NULL && !dodefault) { + if (SOURCING_NAME == NULL && !dodefault) { emsg(_("E414: group has settings, highlight link ignored")); } } else if (hlgroup->sg_link != to_id @@ -884,7 +884,7 @@ void do_highlight(const char *line, const bool forceit, const bool init) } hlgroup->sg_link = to_id; hlgroup->sg_script_ctx = current_sctx; - hlgroup->sg_script_ctx.sc_lnum += sourcing_lnum; + hlgroup->sg_script_ctx.sc_lnum += SOURCING_LNUM; nlua_set_sctx(&hlgroup->sg_script_ctx); hlgroup->sg_cleared = false; redraw_all_later(SOME_VALID); @@ -1274,7 +1274,7 @@ void do_highlight(const char *line, const bool forceit, const bool init) set_hl_attr(idx); } hl_table[idx].sg_script_ctx = current_sctx; - hl_table[idx].sg_script_ctx.sc_lnum += sourcing_lnum; + hl_table[idx].sg_script_ctx.sc_lnum += SOURCING_LNUM; nlua_set_sctx(&hl_table[idx].sg_script_ctx); // Only call highlight_changed() once, after a sequence of highlight diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 2ce564c011..2e5b411fad 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -37,6 +37,7 @@ #include "nvim/msgpack_rpc/channel.h" #include "nvim/os/os.h" #include "nvim/profile.h" +#include "nvim/runtime.h" #include "nvim/screen.h" #include "nvim/undo.h" #include "nvim/usercmd.h" @@ -1313,12 +1314,11 @@ static void nlua_typval_exec(const char *lcmd, size_t lcmd_len, const char *name int nlua_source_using_linegetter(LineGetter fgetline, void *cookie, char *name) { - const linenr_T save_sourcing_lnum = sourcing_lnum; const sctx_T save_current_sctx = current_sctx; current_sctx.sc_sid = SID_STR; current_sctx.sc_seq = 0; current_sctx.sc_lnum = 0; - sourcing_lnum = 0; + estack_push(ETYPE_SCRIPT, NULL, 0); garray_T ga; char_u *line = NULL; @@ -1331,7 +1331,7 @@ int nlua_source_using_linegetter(LineGetter fgetline, void *cookie, char *name) size_t len = strlen(code); nlua_typval_exec(code, len, name, NULL, 0, false, NULL); - sourcing_lnum = save_sourcing_lnum; + estack_pop(); current_sctx = save_current_sctx; ga_clear_strings(&ga); xfree(code); diff --git a/src/nvim/main.c b/src/nvim/main.c index 378ca6ba71..4dacf6948f 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -60,6 +60,7 @@ #include "nvim/popupmnu.h" #include "nvim/profile.h" #include "nvim/quickfix.h" +#include "nvim/runtime.h" #include "nvim/screen.h" #include "nvim/shada.h" #include "nvim/sign.h" @@ -159,6 +160,7 @@ bool event_teardown(void) void early_init(mparm_T *paramp) { env_init(); + estack_init(); cmdline_init(); eval_init(); // init global variables init_path(argv0 ? argv0 : "nvim"); @@ -1814,12 +1816,12 @@ static void exe_pre_commands(mparm_T *parmp) if (cnt > 0) { curwin->w_cursor.lnum = 0; // just in case.. - sourcing_name = _("pre-vimrc command line"); + estack_push(ETYPE_ARGS, _("pre-vimrc command line"), 0); current_sctx.sc_sid = SID_CMDARG; for (i = 0; i < cnt; i++) { do_cmdline_cmd(cmds[i]); } - sourcing_name = NULL; + estack_pop(); current_sctx.sc_sid = 0; TIME_MSG("--cmd commands"); } @@ -1841,7 +1843,7 @@ static void exe_commands(mparm_T *parmp) if (parmp->tagname == NULL && curwin->w_cursor.lnum <= 1) { curwin->w_cursor.lnum = 0; } - sourcing_name = "command line"; + estack_push(ETYPE_ARGS, "command line", 0); current_sctx.sc_sid = SID_CARG; current_sctx.sc_seq = 0; for (i = 0; i < parmp->n_commands; i++) { @@ -1850,7 +1852,7 @@ static void exe_commands(mparm_T *parmp) xfree(parmp->commands[i]); } } - sourcing_name = NULL; + estack_pop(); current_sctx.sc_sid = 0; if (curwin->w_cursor.lnum == 0) { curwin->w_cursor.lnum = 1; @@ -2059,17 +2061,14 @@ static int execute_env(char *env) { const char *initstr = os_getenv(env); if (initstr != NULL) { - char_u *save_sourcing_name = (char_u *)sourcing_name; - linenr_T save_sourcing_lnum = sourcing_lnum; - sourcing_name = env; - sourcing_lnum = 0; + estack_push(ETYPE_ENV, env, 0); const sctx_T save_current_sctx = current_sctx; current_sctx.sc_sid = SID_ENV; current_sctx.sc_seq = 0; current_sctx.sc_lnum = 0; do_cmdline_cmd((char *)initstr); - sourcing_name = (char *)save_sourcing_name; - sourcing_lnum = save_sourcing_lnum; + + estack_pop(); current_sctx = save_current_sctx; return OK; } diff --git a/src/nvim/mapping.c b/src/nvim/mapping.c index a3d8587a97..64a798a27b 100644 --- a/src/nvim/mapping.c +++ b/src/nvim/mapping.c @@ -29,6 +29,7 @@ #include "nvim/message.h" #include "nvim/option.h" #include "nvim/regexp.h" +#include "nvim/runtime.h" #include "nvim/ui.h" #include "nvim/vim.h" @@ -469,7 +470,7 @@ static void map_add(buf_T *buf, mapblock_T **map_table, mapblock_T **abbr_table, mp->m_script_ctx.sc_lnum = lnum; } else { mp->m_script_ctx = current_sctx; - mp->m_script_ctx.sc_lnum += sourcing_lnum; + mp->m_script_ctx.sc_lnum += SOURCING_LNUM; nlua_set_sctx(&mp->m_script_ctx); } mp->m_desc = NULL; @@ -776,7 +777,7 @@ static int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, mp->m_expr = args->expr; mp->m_replace_keycodes = args->replace_keycodes; mp->m_script_ctx = current_sctx; - mp->m_script_ctx.sc_lnum += sourcing_lnum; + mp->m_script_ctx.sc_lnum += SOURCING_LNUM; nlua_set_sctx(&mp->m_script_ctx); if (args->desc != NULL) { mp->m_desc = xstrdup(args->desc); diff --git a/src/nvim/message.c b/src/nvim/message.c index adab7c1c7b..cdbd7369b3 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -38,6 +38,7 @@ #include "nvim/os/os.h" #include "nvim/os/time.h" #include "nvim/regexp.h" +#include "nvim/runtime.h" #include "nvim/screen.h" #include "nvim/strings.h" #include "nvim/syntax.h" @@ -524,7 +525,7 @@ int smsg_attr_keep(int attr, const char *s, ...) * isn't printed each time when it didn't change. */ static int last_sourcing_lnum = 0; -static char_u *last_sourcing_name = NULL; +static char *last_sourcing_name = NULL; /// Reset the last used sourcing name/lnum. Makes sure it is displayed again /// for the next error message; @@ -534,16 +535,16 @@ void reset_last_sourcing(void) last_sourcing_lnum = 0; } -/// @return TRUE if "sourcing_name" differs from "last_sourcing_name". -static int other_sourcing_name(void) +/// @return true if "SOURCING_NAME" differs from "last_sourcing_name". +static bool other_sourcing_name(void) { - if (sourcing_name != NULL) { + if (SOURCING_NAME != NULL) { if (last_sourcing_name != NULL) { - return STRCMP(sourcing_name, last_sourcing_name) != 0; + return strcmp(SOURCING_NAME, last_sourcing_name) != 0; } - return TRUE; + return true; } - return FALSE; + return false; } /// Get the message about the source, as used for an error message @@ -553,11 +554,19 @@ static int other_sourcing_name(void) static char *get_emsg_source(void) FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT { - if (sourcing_name != NULL && other_sourcing_name()) { + if (SOURCING_NAME != NULL && other_sourcing_name()) { + char *sname = estack_sfile(); + char *tofree = sname; + + if (sname == NULL) { + sname = SOURCING_NAME; + } + const char *const p = _("Error detected while processing %s:"); - const size_t buf_len = STRLEN(sourcing_name) + strlen(p) + 1; + const size_t buf_len = STRLEN(sname) + strlen(p) + 1; char *const buf = xmalloc(buf_len); - snprintf(buf, buf_len, p, sourcing_name); + snprintf(buf, buf_len, p, sname); + xfree(tofree); return buf; } return NULL; @@ -572,13 +581,13 @@ static char *get_emsg_lnum(void) { // lnum is 0 when executing a command from the command line // argument, we don't want a line number then - if (sourcing_name != NULL - && (other_sourcing_name() || sourcing_lnum != last_sourcing_lnum) - && sourcing_lnum != 0) { + if (SOURCING_NAME != NULL + && (other_sourcing_name() || SOURCING_LNUM != last_sourcing_lnum) + && SOURCING_LNUM != 0) { const char *const p = _("line %4ld:"); const size_t buf_len = 20 + strlen(p); char *const buf = xmalloc(buf_len); - snprintf(buf, buf_len, p, (long)sourcing_lnum); + snprintf(buf, buf_len, p, (long)SOURCING_LNUM); return buf; } return NULL; @@ -599,16 +608,16 @@ void msg_source(int attr) if (p != NULL) { msg_attr(p, HL_ATTR(HLF_N)); xfree(p); - last_sourcing_lnum = sourcing_lnum; // only once for each line + last_sourcing_lnum = SOURCING_LNUM; // only once for each line } // remember the last sourcing name printed, also when it's empty - if (sourcing_name == NULL || other_sourcing_name()) { + if (SOURCING_NAME == NULL || other_sourcing_name()) { xfree(last_sourcing_name); - if (sourcing_name == NULL) { + if (SOURCING_NAME == NULL) { last_sourcing_name = NULL; } else { - last_sourcing_name = vim_strsave((char_u *)sourcing_name); + last_sourcing_name = xstrdup(SOURCING_NAME); } } --no_wait_return; @@ -686,9 +695,9 @@ static bool emsg_multiline(const char *s, bool multiline) } // Log (silent) errors as debug messages. - if (sourcing_name != NULL && sourcing_lnum != 0) { + if (SOURCING_NAME != NULL && SOURCING_LNUM != 0) { DLOG("(:silent) %s (%s (line %ld))", - s, sourcing_name, (long)sourcing_lnum); + s, SOURCING_NAME, (long)SOURCING_LNUM); } else { DLOG("(:silent) %s", s); } @@ -697,8 +706,8 @@ static bool emsg_multiline(const char *s, bool multiline) } // Log editor errors as INFO. - if (sourcing_name != NULL && sourcing_lnum != 0) { - ILOG("%s (%s (line %ld))", s, sourcing_name, (long)sourcing_lnum); + if (SOURCING_NAME != NULL && SOURCING_LNUM != 0) { + ILOG("%s (%s (line %ld))", s, SOURCING_NAME, (long)SOURCING_LNUM); } else { ILOG("%s", s); } @@ -2457,7 +2466,7 @@ void msg_reset_scroll(void) static void inc_msg_scrolled(void) { if (*get_vim_var_str(VV_SCROLLSTART) == NUL) { - char *p = sourcing_name; + char *p = SOURCING_NAME; char *tofree = NULL; // v:scrollstart is empty, set it to the script/function name and line @@ -2468,7 +2477,7 @@ static void inc_msg_scrolled(void) size_t len = strlen(p) + 40; tofree = xmalloc(len); vim_snprintf(tofree, len, _("%s line %" PRId64), - p, (int64_t)sourcing_lnum); + p, (int64_t)SOURCING_LNUM); p = tofree; } set_vim_var_string(VV_SCROLLSTART, p, -1); diff --git a/src/nvim/option.c b/src/nvim/option.c index 916c460ed6..5e88ed98e8 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -3996,7 +3996,7 @@ static void set_option_sctx_idx(int opt_idx, int opt_flags, sctx_T script_ctx) .script_ctx = { script_ctx.sc_sid, script_ctx.sc_seq, - script_ctx.sc_lnum + sourcing_lnum + script_ctx.sc_lnum + SOURCING_LNUM }, current_channel_id }; diff --git a/src/nvim/profile.c b/src/nvim/profile.c index b05ba0d8f8..d4f3756f4d 100644 --- a/src/nvim/profile.c +++ b/src/nvim/profile.c @@ -532,9 +532,8 @@ void func_line_start(void *cookie) funccall_T *fcp = (funccall_T *)cookie; ufunc_T *fp = fcp->func; - if (fp->uf_profiling && sourcing_lnum >= 1 - && sourcing_lnum <= fp->uf_lines.ga_len) { - fp->uf_tml_idx = sourcing_lnum - 1; + if (fp->uf_profiling && SOURCING_LNUM >= 1 && SOURCING_LNUM <= fp->uf_lines.ga_len) { + fp->uf_tml_idx = SOURCING_LNUM - 1; // Skip continuation lines. while (fp->uf_tml_idx > 0 && FUNCLINE(fp, fp->uf_tml_idx) == NULL) { fp->uf_tml_idx--; @@ -798,11 +797,11 @@ void script_line_start(void) return; } si = &SCRIPT_ITEM(current_sctx.sc_sid); - if (si->sn_prof_on && sourcing_lnum >= 1) { + if (si->sn_prof_on && SOURCING_LNUM >= 1) { // Grow the array before starting the timer, so that the time spent // here isn't counted. - (void)ga_grow(&si->sn_prl_ga, sourcing_lnum - si->sn_prl_ga.ga_len); - si->sn_prl_idx = sourcing_lnum - 1; + (void)ga_grow(&si->sn_prl_ga, SOURCING_LNUM - si->sn_prl_ga.ga_len); + si->sn_prl_idx = SOURCING_LNUM - 1; while (si->sn_prl_ga.ga_len <= si->sn_prl_idx && si->sn_prl_ga.ga_len < si->sn_prl_ga.ga_maxlen) { // Zero counters for a line that was not used before. diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c index 89848b43bd..8299f8ec45 100644 --- a/src/nvim/runtime.c +++ b/src/nvim/runtime.c @@ -50,8 +50,94 @@ struct source_cookie { # include "runtime.c.generated.h" #endif +garray_T exestack = { 0, 0, sizeof(estack_T), 50, NULL }; garray_T script_items = { 0, 0, sizeof(scriptitem_T), 4, NULL }; +/// Initialize the execution stack. +void estack_init(void) +{ + ga_grow(&exestack, 10); + estack_T *entry = ((estack_T *)exestack.ga_data) + exestack.ga_len; + entry->es_type = ETYPE_TOP; + entry->es_name = NULL; + entry->es_lnum = 0; + entry->es_info.ufunc = NULL; + exestack.ga_len++; +} + +/// Add an item to the execution stack. +/// @return the new entry +estack_T *estack_push(etype_T type, char *name, linenr_T lnum) +{ + ga_grow(&exestack, 1); + estack_T *entry = ((estack_T *)exestack.ga_data) + exestack.ga_len; + entry->es_type = type; + entry->es_name = name; + entry->es_lnum = lnum; + entry->es_info.ufunc = NULL; + exestack.ga_len++; + return entry; +} + +/// Add a user function to the execution stack. +void estack_push_ufunc(ufunc_T *ufunc, linenr_T lnum) +{ + estack_T *entry = estack_push(ETYPE_UFUNC, + (char *)(ufunc->uf_name_exp != NULL + ? ufunc->uf_name_exp : ufunc->uf_name), + lnum); + if (entry != NULL) { + entry->es_info.ufunc = ufunc; + } +} + +/// Take an item off of the execution stack. +void estack_pop(void) +{ + if (exestack.ga_len > 1) { + exestack.ga_len--; + } +} + +/// Get the current value for <sfile> in allocated memory. +char *estack_sfile(void) +{ + estack_T *entry = ((estack_T *)exestack.ga_data) + exestack.ga_len - 1; + if (entry->es_name == NULL) { + return NULL; + } + if (entry->es_info.ufunc == NULL) { + return xstrdup(entry->es_name); + } + + // For a function we compose the call stack, as it was done in the past: + // "function One[123]..Two[456]..Three" + size_t len = STRLEN(entry->es_name) + 10; + int idx; + for (idx = exestack.ga_len - 2; idx >= 0; idx--) { + entry = ((estack_T *)exestack.ga_data) + idx; + if (entry->es_name == NULL || entry->es_info.ufunc == NULL) { + idx++; + break; + } + len += STRLEN(entry->es_name) + 15; + } + + char *res = (char *)xmalloc(len); + STRCPY(res, "function "); + size_t done; + while (idx < exestack.ga_len - 1) { + done = STRLEN(res); + entry = ((estack_T *)exestack.ga_data) + idx; + vim_snprintf(res + done, len - done, "%s[%" PRIdLINENR "]..", entry->es_name, entry->es_lnum); + idx++; + } + done = STRLEN(res); + entry = ((estack_T *)exestack.ga_data) + idx; + vim_snprintf(res + done, len - done, "%s", entry->es_name); + return res; +} + static bool runtime_search_path_valid = false; static int *runtime_search_path_ref = NULL; static RuntimeSearchPath runtime_search_path; @@ -1645,18 +1731,19 @@ scriptitem_T *new_script_item(char *const name, scid_T *const sid_out) static int source_using_linegetter(void *cookie, LineGetter fgetline, const char *traceback_name) { - char *save_sourcing_name = sourcing_name; - linenr_T save_sourcing_lnum = sourcing_lnum; + char *save_sourcing_name = SOURCING_NAME; + linenr_T save_sourcing_lnum = SOURCING_LNUM; char sourcing_name_buf[256]; + char *sname; if (save_sourcing_name == NULL) { - sourcing_name = (char *)traceback_name; + sname = (char *)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; // -V507 reassigned below, before return. + sname = sourcing_name_buf; } - sourcing_lnum = 0; + estack_push(ETYPE_SCRIPT, sname, 0); const sctx_T save_current_sctx = current_sctx; if (current_sctx.sc_sid != SID_LUA) { @@ -1668,8 +1755,7 @@ static int source_using_linegetter(void *cookie, LineGetter fgetline, const char save_funccal(&entry); int retval = do_cmdline(NULL, fgetline, cookie, DOCMD_VERBOSE | DOCMD_NOWAIT | DOCMD_REPEAT); - sourcing_lnum = save_sourcing_lnum; - sourcing_name = save_sourcing_name; + estack_pop(); current_sctx = save_current_sctx; restore_funccal(); return retval; @@ -1736,8 +1822,6 @@ int do_source_str(const char *cmd, const char *traceback_name) int do_source(char *fname, int check_other, int is_vimrc) { struct source_cookie cookie; - char *save_sourcing_name; - linenr_T save_sourcing_lnum; char *p; char *fname_exp; uint8_t *firstline = NULL; @@ -1791,11 +1875,11 @@ int do_source(char *fname, int check_other, int is_vimrc) if (cookie.fp == NULL) { if (p_verbose > 1) { verbose_enter(); - if (sourcing_name == NULL) { + if (SOURCING_NAME == NULL) { smsg(_("could not source \"%s\""), fname); } else { smsg(_("line %" PRId64 ": could not source \"%s\""), - (int64_t)sourcing_lnum, fname); + (int64_t)SOURCING_LNUM, fname); } verbose_leave(); } @@ -1807,11 +1891,10 @@ int do_source(char *fname, int check_other, int is_vimrc) // - For a vimrc file, may want to call vimrc_found(). if (p_verbose > 1) { verbose_enter(); - if (sourcing_name == NULL) { + if (SOURCING_NAME == NULL) { smsg(_("sourcing \"%s\""), fname); } else { - smsg(_("line %" PRId64 ": sourcing \"%s\""), - (int64_t)sourcing_lnum, fname); + smsg(_("line %" PRId64 ": sourcing \"%s\""), (int64_t)SOURCING_LNUM, fname); } verbose_leave(); } @@ -1841,10 +1924,7 @@ int do_source(char *fname, int check_other, int is_vimrc) cookie.level = ex_nesting_level; // Keep the sourcing name/lnum, for recursive calls. - save_sourcing_name = sourcing_name; - sourcing_name = fname_exp; - save_sourcing_lnum = sourcing_lnum; - sourcing_lnum = 0; + estack_push(ETYPE_SCRIPT, fname_exp, 0); // start measuring script load time if --startuptime was passed and // time_fd was successfully opened afterwards. @@ -1901,14 +1981,13 @@ int do_source(char *fname, int check_other, int is_vimrc) if (path_with_extension((const char *)fname_exp, "lua")) { const sctx_T current_sctx_backup = current_sctx; - const linenr_T sourcing_lnum_backup = sourcing_lnum; current_sctx.sc_sid = SID_LUA; current_sctx.sc_lnum = 0; - sourcing_lnum = 0; + estack_push(ETYPE_SCRIPT, NULL, 0); // Source the file as lua nlua_exec_file((const char *)fname_exp); current_sctx = current_sctx_backup; - sourcing_lnum = sourcing_lnum_backup; + estack_pop(); } else { // Call do_cmdline, which will call getsourceline() to get the lines. do_cmdline((char *)firstline, getsourceline, (void *)&cookie, @@ -1931,13 +2010,12 @@ int do_source(char *fname, int check_other, int is_vimrc) if (got_int) { emsg(_(e_interr)); } - sourcing_name = save_sourcing_name; - sourcing_lnum = save_sourcing_lnum; + estack_pop(); if (p_verbose > 1) { verbose_enter(); smsg(_("finished sourcing %s"), fname); - if (sourcing_name != NULL) { - smsg(_("continuing in %s"), sourcing_name); + if (SOURCING_NAME != NULL) { + smsg(_("continuing in %s"), SOURCING_NAME); } verbose_leave(); } @@ -2110,7 +2188,7 @@ linenr_T get_sourced_lnum(LineGetter fgetline, void *cookie) { return fgetline == getsourceline ? ((struct source_cookie *)cookie)->sourcing_lnum - : sourcing_lnum; + : SOURCING_LNUM; } /// Get one full line from a sourced file. @@ -2126,14 +2204,14 @@ char *getsourceline(int c, void *cookie, int indent, bool do_concat) // If breakpoints have been added/deleted need to check for it. if (sp->dbg_tick < debug_tick) { - sp->breakpoint = dbg_find_breakpoint(true, (char_u *)sp->fname, sourcing_lnum); + sp->breakpoint = dbg_find_breakpoint(true, (char_u *)sp->fname, SOURCING_LNUM); sp->dbg_tick = debug_tick; } if (do_profiling == PROF_YES) { script_line_end(); } // Set the current sourcing line number. - sourcing_lnum = sp->sourcing_lnum + 1; + SOURCING_LNUM = sp->sourcing_lnum + 1; // Get current line. If there is a read-ahead line, use it, otherwise get // one now. if (sp->finished) { @@ -2191,10 +2269,10 @@ char *getsourceline(int c, void *cookie, int indent, bool do_concat) } // Did we encounter a breakpoint? - if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum) { - dbg_breakpoint((char_u *)sp->fname, sourcing_lnum); + if (sp->breakpoint != 0 && sp->breakpoint <= SOURCING_LNUM) { + dbg_breakpoint((char_u *)sp->fname, SOURCING_LNUM); // Find next breakpoint. - sp->breakpoint = dbg_find_breakpoint(true, (char_u *)sp->fname, sourcing_lnum); + sp->breakpoint = dbg_find_breakpoint(true, (char_u *)sp->fname, SOURCING_LNUM); sp->dbg_tick = debug_tick; } diff --git a/src/nvim/runtime.h b/src/nvim/runtime.h index fb12029693..6f9f31c9c4 100644 --- a/src/nvim/runtime.h +++ b/src/nvim/runtime.h @@ -3,7 +3,44 @@ #include <stdbool.h> +#include "nvim/autocmd.h" +#include "nvim/eval/typval.h" #include "nvim/ex_cmds_defs.h" +#include "nvim/ex_eval_defs.h" + +typedef enum { + ETYPE_TOP, ///< toplevel + ETYPE_SCRIPT, ///< sourcing script, use es_info.sctx + ETYPE_UFUNC, ///< user function, use es_info.ufunc + ETYPE_AUCMD, ///< autocomand, use es_info.aucmd + ETYPE_MODELINE, ///< modeline, use es_info.sctx + ETYPE_EXCEPT, ///< exception, use es_info.exception + ETYPE_ARGS, ///< command line argument + ETYPE_ENV, ///< environment variable + ETYPE_INTERNAL, ///< internal operation + ETYPE_SPELL, ///< loading spell file +} etype_T; + +/// Entry in the execution stack "exestack". +typedef struct { + linenr_T es_lnum; ///< replaces "sourcing_lnum" + char *es_name; ///< replaces "sourcing_name" + etype_T es_type; + union { + sctx_T *sctx; ///< script and modeline info + ufunc_T *ufunc; ///< function info + AutoPatCmd *aucmd; ///< autocommand info + except_T *except; ///< exception info + } es_info; +} estack_T; + +/// Stack of execution contexts. Each entry is an estack_T. +/// Current context is at ga_len - 1. +extern garray_T exestack; +/// name of error message source +#define SOURCING_NAME (((estack_T *)exestack.ga_data)[exestack.ga_len - 1].es_name) +/// line number in the message source or zero +#define SOURCING_LNUM (((estack_T *)exestack.ga_data)[exestack.ga_len - 1].es_lnum) typedef struct scriptitem_S { char_u *sn_name; diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c index 36df7695ff..58a66f0635 100644 --- a/src/nvim/spellfile.c +++ b/src/nvim/spellfile.c @@ -242,6 +242,7 @@ #include "nvim/os/os.h" #include "nvim/path.h" #include "nvim/regexp.h" +#include "nvim/runtime.h" #include "nvim/screen.h" #include "nvim/spell.h" #include "nvim/spell_defs.h" @@ -576,11 +577,10 @@ slang_T *spell_load_file(char_u *fname, char_u *lang, slang_T *old_lp, bool sile char_u *p; int n; int len; - char_u *save_sourcing_name = (char_u *)sourcing_name; - linenr_T save_sourcing_lnum = sourcing_lnum; slang_T *lp = NULL; int c = 0; int res; + bool did_estack_push = false; fd = os_fopen((char *)fname, "r"); if (fd == NULL) { @@ -612,8 +612,8 @@ slang_T *spell_load_file(char_u *fname, char_u *lang, slang_T *old_lp, bool sile } // Set sourcing_name, so that error messages mention the file name. - sourcing_name = (char *)fname; - sourcing_lnum = 0; + estack_push(ETYPE_SPELL, (char *)fname, 0); + did_estack_push = true; // <HEADER>: <fileID> const int scms_ret = spell_check_magic_string(fd); @@ -809,8 +809,9 @@ endOK: if (fd != NULL) { fclose(fd); } - sourcing_name = (char *)save_sourcing_name; - sourcing_lnum = save_sourcing_lnum; + if (did_estack_push) { + estack_pop(); + } return lp; } diff --git a/src/nvim/testdir/test_autocmd.vim b/src/nvim/testdir/test_autocmd.vim index 1c2f86a584..89e3c9927b 100644 --- a/src/nvim/testdir/test_autocmd.vim +++ b/src/nvim/testdir/test_autocmd.vim @@ -2614,6 +2614,28 @@ func Test_BufWrite_lockmarks() call delete('Xtest2') endfunc +func Test_FileType_spell() + if !isdirectory('/tmp') + throw "Skipped: requires /tmp directory" + endif + + " this was crashing with an invalid free() + setglobal spellfile=/tmp/en.utf-8.add + augroup crash + autocmd! + autocmd BufNewFile,BufReadPost crashfile setf somefiletype + autocmd BufNewFile,BufReadPost crashfile set ft=anotherfiletype + autocmd FileType anotherfiletype setlocal spell + augroup END + func! NoCrash() abort + edit /tmp/crashfile + endfunc + call NoCrash() + + au! crash + setglobal spellfile= +endfunc + " Test closing a window or editing another buffer from a FileChangedRO handler " in a readonly buffer func Test_FileChangedRO_winclose() diff --git a/src/nvim/testdir/test_vimscript.vim b/src/nvim/testdir/test_vimscript.vim index d16783cf31..0f204cdd0c 100644 --- a/src/nvim/testdir/test_vimscript.vim +++ b/src/nvim/testdir/test_vimscript.vim @@ -1573,6 +1573,23 @@ func Test_script_local_func() enew! | close endfunc +func Test_script_expand_sfile() + let lines =<< trim END + func s:snr() + return expand('<sfile>') + endfunc + let g:result = s:snr() + END + call writefile(lines, 'Xexpand') + source Xexpand + call assert_match('<SNR>\d\+_snr', g:result) + source Xexpand + call assert_match('<SNR>\d\+_snr', g:result) + + call delete('Xexpand') + unlet g:result +endfunc + func Test_compound_assignment_operators() " Test for number let x = 1 diff --git a/src/nvim/testing.c b/src/nvim/testing.c index 69b687e44f..de6d445ba3 100644 --- a/src/nvim/testing.c +++ b/src/nvim/testing.c @@ -7,6 +7,7 @@ #include "nvim/eval/encode.h" #include "nvim/ex_docmd.h" #include "nvim/os/os.h" +#include "nvim/runtime.h" #include "nvim/testing.h" #ifdef INCLUDE_GENERATED_DECLARATIONS @@ -17,21 +18,23 @@ static void prepare_assert_error(garray_T *gap) { char buf[NUMBUFLEN]; + char *sname = estack_sfile(); ga_init(gap, 1, 100); - if (sourcing_name != NULL) { - ga_concat(gap, (char *)sourcing_name); - if (sourcing_lnum > 0) { + if (sname != NULL) { + ga_concat(gap, sname); + if (SOURCING_LNUM > 0) { ga_concat(gap, " "); } } - if (sourcing_lnum > 0) { - vim_snprintf(buf, ARRAY_SIZE(buf), "line %" PRId64, (int64_t)sourcing_lnum); + if (SOURCING_LNUM > 0) { + vim_snprintf(buf, ARRAY_SIZE(buf), "line %" PRId64, (int64_t)SOURCING_LNUM); ga_concat(gap, buf); } - if (sourcing_name != NULL || sourcing_lnum > 0) { + if (sname != NULL || SOURCING_LNUM > 0) { ga_concat(gap, ": "); } + xfree(sname); } /// Append "p[clen]" to "gap", escaping unprintable characters. diff --git a/src/nvim/usercmd.c b/src/nvim/usercmd.c index bf5faf7bc9..59b8d10200 100644 --- a/src/nvim/usercmd.c +++ b/src/nvim/usercmd.c @@ -17,6 +17,7 @@ #include "nvim/garray.h" #include "nvim/lua/executor.h" #include "nvim/os/input.h" +#include "nvim/runtime.h" #include "nvim/usercmd.h" #include "nvim/window.h" @@ -168,7 +169,7 @@ char *find_ucmd(exarg_T *eap, char *p, int *full, expand_T *xp, int *complp) xp->xp_luaref = uc->uc_compl_luaref; xp->xp_arg = (char *)uc->uc_compl_arg; xp->xp_script_ctx = uc->uc_script_ctx; - xp->xp_script_ctx.sc_lnum += sourcing_lnum; + xp->xp_script_ctx.sc_lnum += SOURCING_LNUM; } // Do not search for further abbreviations // if this is an exact match. @@ -890,7 +891,7 @@ int uc_add_command(char *name, size_t name_len, const char *rep, uint32_t argt, cmd->uc_def = def; cmd->uc_compl = compl; cmd->uc_script_ctx = current_sctx; - cmd->uc_script_ctx.sc_lnum += sourcing_lnum; + cmd->uc_script_ctx.sc_lnum += SOURCING_LNUM; nlua_set_sctx(&cmd->uc_script_ctx); cmd->uc_compl_arg = (char_u *)compl_arg; cmd->uc_compl_luaref = compl_luaref; |