vim-patch:8.2.0056: execution stack is incomplete and inefficient

Problem:    Execution stack is incomplete and inefficient.
Solution:   Introduce a proper execution stack and use it instead of
            sourcing_name/sourcing_lnum.  Create a string only when used.
1a47ae32cd

Omit test_debugger.vim: superseded by later patches.
Omit check_map_keycodes(): N/A.
Omit kword_test.c: N/A (converted to a unit test).
This commit is contained in:
zeertzjq 2022-08-13 13:48:11 +08:00
parent c1cbe3fb3d
commit f52c236c5b
23 changed files with 372 additions and 252 deletions

View File

@ -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();
}

View File

@ -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

View File

@ -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;

View File

@ -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);
}

View File

@ -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"
@ -8613,8 +8614,8 @@ 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,
.sourcing_name = SOURCING_NAME,
.sourcing_lnum = SOURCING_LNUM,
.autocmd_fname = autocmd_fname,
.autocmd_match = autocmd_match,
.autocmd_bufnr = autocmd_bufnr,
@ -8713,8 +8714,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, "?");
}

View File

@ -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"
@ -7292,6 +7293,7 @@ static void f_rpcnotify(typval_T *argvars, typval_T *rettv, FunPtr fptr)
/// "rpcrequest()" function
static void f_rpcrequest(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
#if 0 // TODO:
rettv->v_type = VAR_NUMBER;
rettv->vval.v_number = 0;
const int l_provider_call_nesting = provider_call_nesting;
@ -7385,6 +7387,7 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, FunPtr fptr)
end:
arena_mem_free(res_mem, NULL);
api_clear_error(&err);
#endif
}
/// "rpcstart()" function (DEPRECATED)

View File

@ -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)

View File

@ -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);
estack_push_ufunc(ETYPE_UFUNC, fp, 1);
if (p_verbose >= 12) {
++no_wait_return;
verbose_enter_scroll();
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;
}
@ -2499,13 +2483,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 +2523,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 +3131,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 +3152,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 +3160,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;
}

View File

@ -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;

View File

@ -478,8 +478,11 @@ 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;
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;

View File

@ -248,9 +248,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

View File

@ -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

View File

@ -1313,6 +1313,7 @@ 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)
{
#if 0 // TODO:
const linenr_T save_sourcing_lnum = sourcing_lnum;
const sctx_T save_current_sctx = current_sctx;
current_sctx.sc_sid = SID_STR;
@ -1336,6 +1337,7 @@ int nlua_source_using_linegetter(LineGetter fgetline, void *cookie, char *name)
ga_clear_strings(&ga);
xfree(code);
return OK;
#endif
}
/// Call a LuaCallable given some typvals

View File

@ -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;
}

View File

@ -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);

View File

@ -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);

View File

@ -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
};

View File

@ -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.

View File

@ -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(etype_T type, ufunc_T *ufunc, linenr_T lnum)
{
estack_T *entry = estack_push(type,
(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,6 +1731,7 @@ 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)
{
#if 0 // TODO:
char *save_sourcing_name = sourcing_name;
linenr_T save_sourcing_lnum = sourcing_lnum;
char sourcing_name_buf[256];
@ -1673,6 +1760,7 @@ static int source_using_linegetter(void *cookie, LineGetter fgetline, const char
current_sctx = save_current_sctx;
restore_funccal();
return retval;
#endif
}
static void cmd_source_buffer(const exarg_T *const eap)
@ -1736,8 +1824,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 +1877,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 +1893,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 +1926,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.
@ -1900,6 +1982,7 @@ int do_source(char *fname, int check_other, int is_vimrc)
}
if (path_with_extension((const char *)fname_exp, "lua")) {
#if 0 // TODO:
const sctx_T current_sctx_backup = current_sctx;
const linenr_T sourcing_lnum_backup = sourcing_lnum;
current_sctx.sc_sid = SID_LUA;
@ -1909,6 +1992,7 @@ int do_source(char *fname, int check_other, int is_vimrc)
nlua_exec_file((const char *)fname_exp);
current_sctx = current_sctx_backup;
sourcing_lnum = sourcing_lnum_backup;
#endif
} else {
// Call do_cmdline, which will call getsourceline() to get the lines.
do_cmdline((char *)firstline, getsourceline, (void *)&cookie,
@ -1931,13 +2015,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 +2193,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 +2209,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 +2274,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;
}

View File

@ -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"
/// Entry in the execution stack "exestack".
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;
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;

View File

@ -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,8 +577,6 @@ 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;
@ -612,8 +611,7 @@ 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);
// <HEADER>: <fileID>
const int scms_ret = spell_check_magic_string(fd);
@ -809,8 +807,7 @@ endOK:
if (fd != NULL) {
fclose(fd);
}
sourcing_name = (char *)save_sourcing_name;
sourcing_lnum = save_sourcing_lnum;
estack_pop();
return lp;
}

View File

@ -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.

View File

@ -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;