Patch 8.2.0056

9 views
Skip to first unread message

Bram Moolenaar

unread,
Dec 29, 2019, 5:05:29 PM12/29/19
to vim...@googlegroups.com

Patch 8.2.0056
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.
Files: src/structs.h, src/globals.h, src/autocmd.c, src/buffer.c
src/debugger.c, src/ex_docmd.c, src/ex_eval.c, src/highlight.c,
src/main.c, src/map.c, src/message.c, src/proto/scriptfile.pro,
src/scriptfile.c, src/option.c, src/profiler.c, src/spellfile.c,
src/term.c, src/testing.c, src/usercmd.c, src/userfunc.c,
src/kword_test.c, src/testdir/test_debugger.vim


*** ../vim-8.2.0055/src/structs.h 2019-12-25 18:14:10.481839651 +0100
--- src/structs.h 2019-12-29 19:12:06.660504770 +0100
***************
*** 1496,1501 ****
--- 1496,1503 ----
// 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[1]; // name of function (actually longer); can
// start with <SNR>123_ (<SNR> is K_SPECIAL
// KS_EXTRA KE_SNR)
***************
*** 1665,1670 ****
--- 1667,1704 ----
dict_T *pt_dict; // dict for "self"
};

+ typedef struct AutoPatCmd_S AutoPatCmd;
+
+ /*
+ * 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 {
+ long es_lnum; // replaces "sourcing_lnum"
+ char_u *es_name; // replaces "sourcing_name"
+ etype_T es_type;
+ union {
+ sctx_T *sctx; // script and modeline info
+ #if defined(FEAT_EVAL)
+ ufunc_T *ufunc; // function info
+ #endif
+ AutoPatCmd *aucmd; // autocommand info
+ except_T *except; // exception info
+ } es_info;
+ } estack_T;
+
// Information returned by get_tty_info().
typedef struct {
int backspace; // what the Backspace key produces
*** ../vim-8.2.0055/src/globals.h 2019-12-27 13:49:19.984946890 +0100
--- src/globals.h 2019-12-29 16:39:23.656982200 +0100
***************
*** 266,273 ****
EXTERN int msg_no_more INIT(= FALSE); // don't use more prompt, truncate
// messages

! EXTERN char_u *sourcing_name INIT( = NULL);// name of error message source
! EXTERN linenr_T sourcing_lnum INIT(= 0); // line number of the source file

#ifdef FEAT_EVAL
EXTERN int ex_nesting_level INIT(= 0); // nesting level
--- 266,280 ----
EXTERN int msg_no_more INIT(= FALSE); // don't use more prompt, truncate
// messages

! /*
! * Stack of execution contexts. Each entry is an estack_T.
! * Current context is at ga_len - 1.
! */
! EXTERN garray_T exestack INIT(= {0 COMMA 0 COMMA sizeof(estack_T) COMMA 50 COMMA NULL});
! // 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)

#ifdef FEAT_EVAL
EXTERN int ex_nesting_level INIT(= 0); // nesting level
*** ../vim-8.2.0055/src/autocmd.c 2019-11-30 20:32:37.000000000 +0100
--- src/autocmd.c 2019-12-29 16:39:45.052886815 +0100
***************
*** 218,224 ****
/*
* struct used to keep status while executing autocommands for an event.
*/
! typedef struct AutoPatCmd
{
AutoPat *curpat; // next AutoPat to examine
AutoCmd *nextcmd; // next AutoCmd to execute
--- 218,224 ----
/*
* struct used to keep status while executing autocommands for an event.
*/
! struct AutoPatCmd_S
{
AutoPat *curpat; // next AutoPat to examine
AutoCmd *nextcmd; // next AutoCmd to execute
***************
*** 229,236 ****
event_T event; // current event
int arg_bufnr; // Initially equal to <abuf>, set to zero when
// buf is deleted.
! struct AutoPatCmd *next; // chain of active apc-s for auto-invalidation
! } AutoPatCmd;

static AutoPatCmd *active_apc_list = NULL; // stack of active autocommands

--- 229,236 ----
event_T event; // current event
int arg_bufnr; // Initially equal to <abuf>, set to zero when
// buf is deleted.
! AutoPatCmd *next; // chain of active apc-s for auto-invalidation
! };

static AutoPatCmd *active_apc_list = NULL; // stack of active autocommands

***************
*** 1242,1248 ****
ac->cmd = vim_strsave(cmd);
#ifdef FEAT_EVAL
ac->script_ctx = current_sctx;
! ac->script_ctx.sc_lnum += sourcing_lnum;
#endif
if (ac->cmd == NULL)
{
--- 1242,1248 ----
ac->cmd = vim_strsave(cmd);
#ifdef FEAT_EVAL
ac->script_ctx = current_sctx;
! ac->script_ctx.sc_lnum += SOURCING_LNUM;
#endif
if (ac->cmd == NULL)
{
***************
*** 1805,1812 ****
int save_changed;
buf_T *old_curbuf;
int retval = FALSE;
- char_u *save_sourcing_name;
- linenr_T save_sourcing_lnum;
char_u *save_autocmd_fname;
int save_autocmd_fname_full;
int save_autocmd_bufnr;
--- 1805,1810 ----
***************
*** 2020,2029 ****

// Don't redraw while doing autocommands.
++RedrawingDisabled;
! save_sourcing_name = sourcing_name;
! sourcing_name = NULL; // don't free this one
! save_sourcing_lnum = sourcing_lnum;
! sourcing_lnum = 0; // no line number here

#ifdef FEAT_EVAL
save_current_sctx = current_sctx;
--- 2018,2026 ----

// Don't redraw while doing autocommands.
++RedrawingDisabled;
!
! // name and lnum are filled in later
! estack_push(ETYPE_AUCMD, NULL, 0);

#ifdef FEAT_EVAL
save_current_sctx = current_sctx;
***************
*** 2126,2134 ****
autocmd_busy = save_autocmd_busy;
filechangeshell_busy = FALSE;
autocmd_nested = save_autocmd_nested;
! vim_free(sourcing_name);
! sourcing_name = save_sourcing_name;
! sourcing_lnum = save_sourcing_lnum;
vim_free(autocmd_fname);
autocmd_fname = save_autocmd_fname;
autocmd_fname_full = save_autocmd_fname_full;
--- 2123,2130 ----
autocmd_busy = save_autocmd_busy;
filechangeshell_busy = FALSE;
autocmd_nested = save_autocmd_nested;
! vim_free(SOURCING_NAME);
! estack_pop();
vim_free(autocmd_fname);
autocmd_fname = save_autocmd_fname;
autocmd_fname_full = save_autocmd_fname_full;
***************
*** 2256,2263 ****
AutoCmd *cp;
char_u *name;
char *s;

! VIM_CLEAR(sourcing_name);

for (ap = apc->curpat; ap != NULL && !got_int; ap = ap->next)
{
--- 2252,2260 ----
AutoCmd *cp;
char_u *name;
char *s;
+ char_u **sourcing_namep = &SOURCING_NAME;

! VIM_CLEAR(*sourcing_namep);

for (ap = apc->curpat; ap != NULL && !got_int; ap = ap->next)
{
***************
*** 2277,2292 ****
{
name = event_nr2name(apc->event);
s = _("%s Autocommands for \"%s\"");
! sourcing_name = alloc(STRLEN(s)
+ STRLEN(name) + ap->patlen + 1);
! if (sourcing_name != NULL)
{
! sprintf((char *)sourcing_name, s,
(char *)name, (char *)ap->pat);
if (p_verbose >= 8)
{
verbose_enter();
! smsg(_("Executing %s"), sourcing_name);
verbose_leave();
}
}
--- 2274,2289 ----
{
name = event_nr2name(apc->event);
s = _("%s Autocommands for \"%s\"");
! *sourcing_namep = alloc(STRLEN(s)
+ STRLEN(name) + ap->patlen + 1);
! if (*sourcing_namep != NULL)
{
! sprintf((char *)*sourcing_namep, s,
(char *)name, (char *)ap->pat);
if (p_verbose >= 8)
{
verbose_enter();
! smsg(_("Executing %s"), *sourcing_namep);
verbose_leave();
}
}
*** ../vim-8.2.0055/src/buffer.c 2019-12-29 13:56:28.692861883 +0100
--- src/buffer.c 2019-12-29 16:17:22.877768244 +0100
***************
*** 5279,5286 ****
int vers;
int end;
int retval = OK;
- char_u *save_sourcing_name;
- linenr_T save_sourcing_lnum;
#ifdef FEAT_EVAL
sctx_T save_current_sctx;
#endif
--- 5279,5284 ----
***************
*** 5325,5334 ****
if (linecopy == NULL)
return FAIL;

! save_sourcing_lnum = sourcing_lnum;
! save_sourcing_name = sourcing_name;
! sourcing_lnum = lnum; // prepare for emsg()
! sourcing_name = (char_u *)"modelines";

end = FALSE;
while (end == FALSE)
--- 5323,5330 ----
if (linecopy == NULL)
return FAIL;

! // prepare for emsg()
! estack_push(ETYPE_MODELINE, (char_u *)"modelines", lnum);

end = FALSE;
while (end == FALSE)
***************
*** 5371,5377 ****
save_current_sctx = current_sctx;
current_sctx.sc_sid = SID_MODELINE;
current_sctx.sc_seq = 0;
! current_sctx.sc_lnum = 0;
current_sctx.sc_version = 1;
#endif
// Make sure no risky things are executed as a side effect.
--- 5367,5373 ----
save_current_sctx = current_sctx;
current_sctx.sc_sid = SID_MODELINE;
current_sctx.sc_seq = 0;
! current_sctx.sc_lnum = lnum;
current_sctx.sc_version = 1;
#endif
// Make sure no risky things are executed as a side effect.
***************
*** 5389,5397 ****
s = e + 1; // advance to next part
}

! sourcing_lnum = save_sourcing_lnum;
! sourcing_name = save_sourcing_name;
!
vim_free(linecopy);
}
return retval;
--- 5385,5391 ----
s = e + 1; // advance to next part
}

! estack_pop();
vim_free(linecopy);
}
return retval;
*** ../vim-8.2.0055/src/debugger.c 2019-12-25 18:14:10.481839651 +0100
--- src/debugger.c 2019-12-29 21:00:17.504117635 +0100
***************
*** 51,56 ****
--- 51,57 ----
int n;
char_u *cmdline = NULL;
char_u *p;
+ char_u *sname;
char *tail = NULL;
static int last_cmd = 0;
#define CMD_CONT 1
***************
*** 104,113 ****
vim_free(debug_newval);
debug_newval = NULL;
}
! if (sourcing_name != NULL)
! msg((char *)sourcing_name);
! if (sourcing_lnum != 0)
! smsg(_("line %ld: %s"), (long)sourcing_lnum, cmd);
else
smsg(_("cmd: %s"), cmd);

--- 105,116 ----
vim_free(debug_newval);
debug_newval = NULL;
}
! sname = estack_sfile();
! if (sname != NULL)
! msg((char *)sname);
! vim_free(sname);
! if (SOURCING_LNUM != 0)
! smsg(_("line %ld: %s"), SOURCING_LNUM, cmd);
else
smsg(_("cmd: %s"), cmd);

***************
*** 300,313 ****
}

static int
! get_maxbacktrace_level(void)
{
char *p, *q;
int maxbacktrace = 0;

! if (sourcing_name != NULL)
{
! p = (char *)sourcing_name;
while ((q = strstr(p, "..")) != NULL)
{
p = q + 2;
--- 303,316 ----
}

static int
! get_maxbacktrace_level(char_u *sname)
{
char *p, *q;
int maxbacktrace = 0;

! if (sname != NULL)
{
! p = (char *)sname;
while ((q = strstr(p, "..")) != NULL)
{
p = q + 2;
***************
*** 341,367 ****
}
else
{
! int max = get_maxbacktrace_level();

if (debug_backtrace_level > max)
{
debug_backtrace_level = max;
smsg(_("frame at highest level: %d"), max);
}
}
}

static void
do_showbacktrace(char_u *cmd)
{
char *cur;
char *next;
int i = 0;
! int max = get_maxbacktrace_level();

! if (sourcing_name != NULL)
{
! cur = (char *)sourcing_name;
while (!got_int)
{
next = strstr(cur, "..");
--- 344,375 ----
}
else
{
! char_u *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);
}
+ vim_free(sname);
}
}

static void
do_showbacktrace(char_u *cmd)
{
+ char_u *sname;
char *cur;
char *next;
int i = 0;
! int max;

! sname = estack_sfile();
! max = get_maxbacktrace_level(sname);
! if (sname != NULL)
{
! cur = (char *)sname;
while (!got_int)
{
next = strstr(cur, "..");
***************
*** 377,385 ****
*next = '.';
cur = next + 2;
}
}
! if (sourcing_lnum != 0)
! smsg(_("line %ld: %s"), (long)sourcing_lnum, cmd);
else
smsg(_("cmd: %s"), cmd);
}
--- 385,395 ----
*next = '.';
cur = next + 2;
}
+ vim_free(sname);
}
!
! if (SOURCING_LNUM != 0)
! smsg(_("line %ld: %s"), (long)SOURCING_LNUM, cmd);
else
smsg(_("cmd: %s"), cmd);
}
*** ../vim-8.2.0055/src/ex_docmd.c 2019-12-16 17:10:30.291144418 +0100
--- src/ex_docmd.c 2019-12-29 18:44:31.113192680 +0100
***************
*** 703,709 ****
}
else if (getline_equal(fgetline, cookie, getsourceline))
{
! fname = sourcing_name;
breakpoint = source_breakpoint(real_cookie);
dbg_tick = source_dbg_tick(real_cookie);
}
--- 703,709 ----
}
else if (getline_equal(fgetline, cookie, getsourceline))
{
! fname = SOURCING_NAME;
breakpoint = source_breakpoint(real_cookie);
dbg_tick = source_dbg_tick(real_cookie);
}
***************
*** 819,840 ****
{
*breakpoint = dbg_find_breakpoint(
getline_equal(fgetline, cookie, getsourceline),
! 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;

// Did we encounter a breakpoint?
if (breakpoint != NULL && *breakpoint != 0
! && *breakpoint <= sourcing_lnum)
{
! dbg_breakpoint(fname, sourcing_lnum);
// Find next breakpoint.
*breakpoint = dbg_find_breakpoint(
getline_equal(fgetline, cookie, getsourceline),
! fname, sourcing_lnum);
*dbg_tick = debug_tick;
}
# ifdef FEAT_PROFILE
--- 819,840 ----
{
*breakpoint = dbg_find_breakpoint(
getline_equal(fgetline, cookie, getsourceline),
! 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;

// Did we encounter a breakpoint?
if (breakpoint != NULL && *breakpoint != 0
! && *breakpoint <= SOURCING_LNUM)
{
! dbg_breakpoint(fname, SOURCING_LNUM);
// Find next breakpoint.
*breakpoint = dbg_find_breakpoint(
getline_equal(fgetline, cookie, getsourceline),
! fname, SOURCING_LNUM);
*dbg_tick = debug_tick;
}
# ifdef FEAT_PROFILE
***************
*** 963,970 ****
}
}

! if (p_verbose >= 15 && sourcing_name != NULL)
! msg_verbose_cmd(sourcing_lnum, cmdline_copy);

/*
* 2. Execute one '|' separated command.
--- 963,970 ----
}
}

! if (p_verbose >= 15 && SOURCING_NAME != NULL)
! msg_verbose_cmd(SOURCING_LNUM, cmdline_copy);

/*
* 2. Execute one '|' separated command.
***************
*** 1081,1087 ****
// Check for the next breakpoint after a watchexpression
if (breakpoint != NULL && has_watchexpr())
{
! *breakpoint = dbg_find_breakpoint(FALSE, fname, sourcing_lnum);
*dbg_tick = debug_tick;
}

--- 1081,1087 ----
// Check for the next breakpoint after a watchexpression
if (breakpoint != NULL && has_watchexpr())
{
! *breakpoint = dbg_find_breakpoint(FALSE, fname, SOURCING_LNUM);
*dbg_tick = debug_tick;
}

***************
*** 1092,1098 ****
{
if (lines_ga.ga_len > 0)
{
! sourcing_lnum =
((wcmd_T *)lines_ga.ga_data)[lines_ga.ga_len - 1].lnum;
free_cmdlines(&lines_ga);
}
--- 1092,1098 ----
{
if (lines_ga.ga_len > 0)
{
! SOURCING_LNUM =
((wcmd_T *)lines_ga.ga_data)[lines_ga.ga_len - 1].lnum;
free_cmdlines(&lines_ga);
}
***************
*** 1234,1241 ****
if (did_throw)
{
void *p = NULL;
- char_u *saved_sourcing_name;
- int saved_sourcing_lnum;
struct msglist *messages = NULL, *next;

/*
--- 1234,1239 ----
***************
*** 1260,1269 ****
break;
}

! saved_sourcing_name = sourcing_name;
! saved_sourcing_lnum = sourcing_lnum;
! sourcing_name = current_exception->throw_name;
! sourcing_lnum = current_exception->throw_lnum;
current_exception->throw_name = NULL;

discard_current_exception(); // uses IObuff if 'verbose'
--- 1258,1265 ----
break;
}

! estack_push(ETYPE_EXCEPT, current_exception->throw_name,
! current_exception->throw_lnum);
current_exception->throw_name = NULL;

discard_current_exception(); // uses IObuff if 'verbose'
***************
*** 1287,1295 ****
emsg(p);
vim_free(p);
}
! vim_free(sourcing_name);
! sourcing_name = saved_sourcing_name;
! sourcing_lnum = saved_sourcing_lnum;
}

/*
--- 1283,1290 ----
emsg(p);
vim_free(p);
}
! vim_free(SOURCING_NAME);
! estack_pop();
}

/*
***************
*** 1428,1434 ****
KeyTyped = FALSE;
++cp->current_line;
wp = (wcmd_T *)(cp->lines_gap->ga_data) + cp->current_line;
! sourcing_lnum = wp->lnum;
return vim_strsave(wp->line);
}

--- 1423,1429 ----
KeyTyped = FALSE;
++cp->current_line;
wp = (wcmd_T *)(cp->lines_gap->ga_data) + cp->current_line;
! SOURCING_LNUM = wp->lnum;
return vim_strsave(wp->line);
}

***************
*** 1441,1447 ****
if (ga_grow(gap, 1) == FAIL)
return FAIL;
((wcmd_T *)(gap->ga_data))[gap->ga_len].line = vim_strsave(line);
! ((wcmd_T *)(gap->ga_data))[gap->ga_len].lnum = sourcing_lnum;
++gap->ga_len;
return OK;
}
--- 1436,1442 ----
if (ga_grow(gap, 1) == FAIL)
return FAIL;
((wcmd_T *)(gap->ga_data))[gap->ga_len].line = vim_strsave(line);
! ((wcmd_T *)(gap->ga_data))[gap->ga_len].lnum = SOURCING_LNUM;
++gap->ga_len;
return OK;
}
***************
*** 8171,8203 ****
break;

case SPEC_SFILE: // file name for ":so" command
! result = sourcing_name;
if (result == NULL)
{
*errormsg = _("E498: no :source file name to substitute for \"<sfile>\"");
return NULL;
}
break;

case SPEC_SLNUM: // line in file for ":so" command
! if (sourcing_name == NULL || sourcing_lnum == 0)
{
*errormsg = _("E842: no line number to use for \"<slnum>\"");
return NULL;
}
! sprintf((char *)strbuf, "%ld", (long)sourcing_lnum);
result = strbuf;
break;

#ifdef FEAT_EVAL
case SPEC_SFLNUM: // line in script file
! if (current_sctx.sc_lnum + sourcing_lnum == 0)
{
*errormsg = _("E961: no line number to use for \"<sflnum>\"");
return NULL;
}
sprintf((char *)strbuf, "%ld",
! (long)(current_sctx.sc_lnum + sourcing_lnum));
result = strbuf;
break;
#endif
--- 8166,8199 ----
break;

case SPEC_SFILE: // file name for ":so" command
! 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)
{
*errormsg = _("E842: no line number to use for \"<slnum>\"");
return NULL;
}
! sprintf((char *)strbuf, "%ld", SOURCING_LNUM);
result = strbuf;
break;

#ifdef FEAT_EVAL
case SPEC_SFLNUM: // line in script file
! if (current_sctx.sc_lnum + SOURCING_LNUM == 0)
{
*errormsg = _("E961: no line number to use for \"<sflnum>\"");
return NULL;
}
sprintf((char *)strbuf, "%ld",
! (long)(current_sctx.sc_lnum + SOURCING_LNUM));
result = strbuf;
break;
#endif
*** ../vim-8.2.0055/src/ex_eval.c 2019-12-16 17:10:30.291144418 +0100
--- src/ex_eval.c 2019-12-29 22:50:57.021592930 +0100
***************
*** 534,548 ****
goto nomem;

excp->type = type;
! excp->throw_name = vim_strsave(sourcing_name == NULL
! ? (char_u *)"" : sourcing_name);
if (excp->throw_name == NULL)
{
if (should_free)
vim_free(excp->value);
goto nomem;
}
! excp->throw_lnum = sourcing_lnum;

if (p_verbose >= 13 || debug_break_level > 0)
{
--- 534,549 ----
goto nomem;

excp->type = type;
! excp->throw_name = estack_sfile();
! if (excp->throw_name == NULL)
! excp->throw_name = vim_strsave((char_u *)"");
if (excp->throw_name == NULL)
{
if (should_free)
vim_free(excp->value);
goto nomem;
}
! excp->throw_lnum = SOURCING_LNUM;

if (p_verbose >= 13 || debug_break_level > 0)
{
*** ../vim-8.2.0055/src/highlight.c 2019-12-24 15:38:18.059988789 +0100
--- src/highlight.c 2019-12-29 16:41:16.584486153 +0100
***************
*** 748,754 ****
if (to_id > 0 && !forceit && !init
&& hl_has_settings(from_id - 1, dodefault))
{
! if (sourcing_name == NULL && !dodefault)
emsg(_("E414: group has settings, highlight link ignored"));
}
else if (HL_TABLE()[from_id - 1].sg_link != to_id
--- 748,754 ----
if (to_id > 0 && !forceit && !init
&& hl_has_settings(from_id - 1, dodefault))
{
! if (SOURCING_NAME == NULL && !dodefault)
emsg(_("E414: group has settings, highlight link ignored"));
}
else if (HL_TABLE()[from_id - 1].sg_link != to_id
***************
*** 763,769 ****
HL_TABLE()[from_id - 1].sg_link = to_id;
#ifdef FEAT_EVAL
HL_TABLE()[from_id - 1].sg_script_ctx = current_sctx;
! HL_TABLE()[from_id - 1].sg_script_ctx.sc_lnum += sourcing_lnum;
#endif
HL_TABLE()[from_id - 1].sg_cleared = FALSE;
redraw_all_later(SOME_VALID);
--- 763,769 ----
HL_TABLE()[from_id - 1].sg_link = to_id;
#ifdef FEAT_EVAL
HL_TABLE()[from_id - 1].sg_script_ctx = current_sctx;
! HL_TABLE()[from_id - 1].sg_script_ctx.sc_lnum += SOURCING_LNUM;
#endif
HL_TABLE()[from_id - 1].sg_cleared = FALSE;
redraw_all_later(SOME_VALID);
***************
*** 1518,1524 ****
set_hl_attr(idx);
#ifdef FEAT_EVAL
HL_TABLE()[idx].sg_script_ctx = current_sctx;
! HL_TABLE()[idx].sg_script_ctx.sc_lnum += sourcing_lnum;
#endif
}

--- 1518,1524 ----
set_hl_attr(idx);
#ifdef FEAT_EVAL
HL_TABLE()[idx].sg_script_ctx = current_sctx;
! HL_TABLE()[idx].sg_script_ctx.sc_lnum += SOURCING_LNUM;
#endif
}

*** ../vim-8.2.0055/src/main.c 2019-12-23 22:59:14.264820697 +0100
--- src/main.c 2019-12-29 16:26:59.455699649 +0100
***************
*** 911,916 ****
--- 911,917 ----
void
common_init(mparm_T *paramp)
{
+ estack_init();
cmdline_init();

(void)mb_init(); // init mb_bytelen_tab[] to ones
***************
*** 3089,3101 ****
if (cnt > 0)
{
curwin->w_cursor.lnum = 0; // just in case..
! sourcing_name = (char_u *)_("pre-vimrc command line");
# ifdef FEAT_EVAL
current_sctx.sc_sid = SID_CMDARG;
# endif
for (i = 0; i < cnt; ++i)
do_cmdline_cmd(cmds[i]);
! sourcing_name = NULL;
# ifdef FEAT_EVAL
current_sctx.sc_sid = 0;
# endif
--- 3090,3102 ----
if (cnt > 0)
{
curwin->w_cursor.lnum = 0; // just in case..
! estack_push(ETYPE_ARGS, (char_u *)_("pre-vimrc command line"), 0);
# ifdef FEAT_EVAL
current_sctx.sc_sid = SID_CMDARG;
# endif
for (i = 0; i < cnt; ++i)
do_cmdline_cmd(cmds[i]);
! estack_pop();
# ifdef FEAT_EVAL
current_sctx.sc_sid = 0;
# endif
***************
*** 3119,3125 ****
msg_scroll = TRUE;
if (parmp->tagname == NULL && curwin->w_cursor.lnum <= 1)
curwin->w_cursor.lnum = 0;
! sourcing_name = (char_u *)"command line";
#ifdef FEAT_EVAL
current_sctx.sc_sid = SID_CARG;
current_sctx.sc_seq = 0;
--- 3120,3126 ----
msg_scroll = TRUE;
if (parmp->tagname == NULL && curwin->w_cursor.lnum <= 1)
curwin->w_cursor.lnum = 0;
! estack_push(ETYPE_ARGS, (char_u *)"command line", 0);
#ifdef FEAT_EVAL
current_sctx.sc_sid = SID_CARG;
current_sctx.sc_seq = 0;
***************
*** 3130,3136 ****
if (parmp->cmds_tofree[i])
vim_free(parmp->commands[i]);
}
! sourcing_name = NULL;
#ifdef FEAT_EVAL
current_sctx.sc_sid = 0;
#endif
--- 3131,3137 ----
if (parmp->cmds_tofree[i])
vim_free(parmp->commands[i]);
}
! estack_pop();
#ifdef FEAT_EVAL
current_sctx.sc_sid = 0;
#endif
***************
*** 3336,3343 ****
int is_viminit) // when TRUE, called for VIMINIT
{
char_u *initstr;
- char_u *save_sourcing_name;
- linenr_T save_sourcing_lnum;
#ifdef FEAT_EVAL
sctx_T save_current_sctx;
#endif
--- 3337,3342 ----
***************
*** 3346,3355 ****
{
if (is_viminit)
vimrc_found(NULL, NULL);
! save_sourcing_name = sourcing_name;
! save_sourcing_lnum = sourcing_lnum;
! sourcing_name = env;
! sourcing_lnum = 0;
#ifdef FEAT_EVAL
save_current_sctx = current_sctx;
current_sctx.sc_sid = SID_ENV;
--- 3345,3351 ----
{
if (is_viminit)
vimrc_found(NULL, NULL);
! estack_push(ETYPE_ENV, env, 0);
#ifdef FEAT_EVAL
save_current_sctx = current_sctx;
current_sctx.sc_sid = SID_ENV;
***************
*** 3358,3365 ****
current_sctx.sc_version = 1;
#endif
do_cmdline_cmd(initstr);
! sourcing_name = save_sourcing_name;
! sourcing_lnum = save_sourcing_lnum;
#ifdef FEAT_EVAL
current_sctx = save_current_sctx;
#endif
--- 3354,3361 ----
current_sctx.sc_version = 1;
#endif
do_cmdline_cmd(initstr);
!
! estack_pop();
#ifdef FEAT_EVAL
current_sctx = save_current_sctx;
#endif
*** ../vim-8.2.0055/src/map.c 2019-11-02 22:51:27.000000000 +0100
--- src/map.c 2019-12-29 16:41:26.320444196 +0100
***************
*** 697,703 ****
#ifdef FEAT_EVAL
mp->m_expr = expr;
mp->m_script_ctx = current_sctx;
! mp->m_script_ctx.sc_lnum += sourcing_lnum;
#endif
did_it = TRUE;
}
--- 697,703 ----
#ifdef FEAT_EVAL
mp->m_expr = expr;
mp->m_script_ctx = current_sctx;
! mp->m_script_ctx.sc_lnum += SOURCING_LNUM;
#endif
did_it = TRUE;
}
***************
*** 796,802 ****
#ifdef FEAT_EVAL
mp->m_expr = expr;
mp->m_script_ctx = current_sctx;
! mp->m_script_ctx.sc_lnum += sourcing_lnum;
#endif

// add the new entry in front of the abbrlist or maphash[] list
--- 796,802 ----
#ifdef FEAT_EVAL
mp->m_expr = expr;
mp->m_script_ctx = current_sctx;
! mp->m_script_ctx.sc_lnum += SOURCING_LNUM;
#endif

// add the new entry in front of the abbrlist or maphash[] list
***************
*** 1915,1928 ****
char_u *p;
int i;
char_u buf[3];
- char_u *save_name;
int abbr;
int hash;
buf_T *bp;

validate_maphash();
! save_name = sourcing_name;
! sourcing_name = (char_u *)"mappings"; // avoids giving error messages

// Do this once for each buffer, and then once for global
// mappings/abbreviations with bp == NULL
--- 1915,1927 ----
char_u *p;
int i;
char_u buf[3];
int abbr;
int hash;
buf_T *bp;

validate_maphash();
! // avoids giving error messages
! estack_push(ETYPE_INTERNAL, (char_u *)"mappings", 0);

// Do this once for each buffer, and then once for global
// mappings/abbreviations with bp == NULL
***************
*** 1979,1985 ****
if (bp == NULL)
break;
}
! sourcing_name = save_name;
}

#if defined(FEAT_EVAL) || defined(PROTO)
--- 1978,1984 ----
if (bp == NULL)
break;
}
! estack_pop();
}

#if defined(FEAT_EVAL) || defined(PROTO)
*** ../vim-8.2.0055/src/message.c 2019-12-23 22:59:14.260820709 +0100
--- src/message.c 2019-12-29 20:09:53.238576174 +0100
***************
*** 434,448 ****
}

/*
! * Return TRUE if "sourcing_name" differs from "last_sourcing_name".
*/
static int
other_sourcing_name(void)
{
! if (sourcing_name != NULL)
{
if (last_sourcing_name != NULL)
! return STRCMP(sourcing_name, last_sourcing_name) != 0;
return TRUE;
}
return FALSE;
--- 434,448 ----
}

/*
! * Return TRUE if "SOURCING_NAME" differs from "last_sourcing_name".
*/
static int
other_sourcing_name(void)
{
! if (SOURCING_NAME != NULL)
{
if (last_sourcing_name != NULL)
! return STRCMP(SOURCING_NAME, last_sourcing_name) != 0;
return TRUE;
}
return FALSE;
***************
*** 458,469 ****
{
char_u *Buf, *p;

! if (sourcing_name != NULL && other_sourcing_name())
{
p = (char_u *)_("Error detected while processing %s:");
! Buf = alloc(STRLEN(sourcing_name) + STRLEN(p));
if (Buf != NULL)
! sprintf((char *)Buf, (char *)p, sourcing_name);
return Buf;
}
return NULL;
--- 458,476 ----
{
char_u *Buf, *p;

! if (SOURCING_NAME != NULL && other_sourcing_name())
{
+ char_u *sname = estack_sfile();
+ char_u *tofree = sname;
+
+ if (sname == NULL)
+ sname = SOURCING_NAME;
+
p = (char_u *)_("Error detected while processing %s:");
! Buf = alloc(STRLEN(sname) + STRLEN(p));
if (Buf != NULL)
! sprintf((char *)Buf, (char *)p, sname);
! vim_free(tofree);
return Buf;
}
return NULL;
***************
*** 481,494 ****

// 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)
{
p = (char_u *)_("line %4ld:");
Buf = alloc(STRLEN(p) + 20);
if (Buf != NULL)
! sprintf((char *)Buf, (char *)p, (long)sourcing_lnum);
return Buf;
}
return NULL;
--- 488,501 ----

// 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)
{
p = (char_u *)_("line %4ld:");
Buf = alloc(STRLEN(p) + 20);
if (Buf != NULL)
! sprintf((char *)Buf, (char *)p, (long)SOURCING_LNUM);
return Buf;
}
return NULL;
***************
*** 516,532 ****
{
msg_attr((char *)p, HL_ATTR(HLF_N));
vim_free(p);
! 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())
{
vim_free(last_sourcing_name);
! if (sourcing_name == NULL)
last_sourcing_name = NULL;
else
! last_sourcing_name = vim_strsave(sourcing_name);
}
--no_wait_return;
}
--- 523,539 ----
{
msg_attr((char *)p, HL_ATTR(HLF_N));
vim_free(p);
! 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())
{
vim_free(last_sourcing_name);
! if (SOURCING_NAME == NULL)
last_sourcing_name = NULL;
else
! last_sourcing_name = vim_strsave(SOURCING_NAME);
}
--no_wait_return;
}
***************
*** 2312,2318 ****
#ifdef FEAT_EVAL
if (*get_vim_var_str(VV_SCROLLSTART) == NUL)
{
! char_u *p = sourcing_name;
char_u *tofree = NULL;
int len;

--- 2319,2325 ----
#ifdef FEAT_EVAL
if (*get_vim_var_str(VV_SCROLLSTART) == NUL)
{
! char_u *p = SOURCING_NAME;
char_u *tofree = NULL;
int len;

***************
*** 2327,2333 ****
if (tofree != NULL)
{
vim_snprintf((char *)tofree, len, _("%s line %ld"),
! p, (long)sourcing_lnum);
p = tofree;
}
}
--- 2334,2340 ----
if (tofree != NULL)
{
vim_snprintf((char *)tofree, len, _("%s line %ld"),
! p, (long)SOURCING_LNUM);
p = tofree;
}
}
*** ../vim-8.2.0055/src/proto/scriptfile.pro 2019-12-12 12:55:32.000000000 +0100
--- src/proto/scriptfile.pro 2019-12-29 18:48:29.056368319 +0100
***************
*** 1,4 ****
--- 1,9 ----
/* scriptfile.c */
+ void estack_init(void);
+ estack_T *estack_push(etype_T type, char_u *name, long lnum);
+ void estack_push_ufunc(etype_T type, ufunc_T *ufunc, long lnum);
+ void estack_pop(void);
+ char_u *estack_sfile(void);
void ex_runtime(exarg_T *eap);
int do_in_path(char_u *path, char_u *name, int flags, void (*callback)(char_u *fname, void *ck), void *cookie);
int do_in_runtimepath(char_u *name, int flags, void (*callback)(char_u *fname, void *ck), void *cookie);
*** ../vim-8.2.0055/src/scriptfile.c 2019-12-05 21:04:06.000000000 +0100
--- src/scriptfile.c 2019-12-29 20:57:44.184820163 +0100
***************
*** 19,24 ****
--- 19,140 ----
#endif

/*
+ * Initialize the execution stack.
+ */
+ void
+ estack_init(void)
+ {
+ estack_T *entry;
+
+ if (ga_grow(&exestack, 10) == FAIL)
+ mch_exit(0);
+ 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.
+ * Returns the new entry or NULL when out of memory.
+ */
+ estack_T *
+ estack_push(etype_T type, char_u *name, long lnum)
+ {
+ estack_T *entry;
+
+ // If memory allocation fails then we'll pop more than we push, eventually
+ // at the top level it will be OK again.
+ if (ga_grow(&exestack, 1) == OK)
+ {
+ 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;
+ }
+ return NULL;
+ }
+
+ /*
+ * Add a user function to the execution stack.
+ */
+ void
+ estack_push_ufunc(etype_T type, ufunc_T *ufunc, long lnum)
+ {
+ estack_T *entry = estack_push(type,
+ 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_u *
+ estack_sfile(void)
+ {
+ int len;
+ int idx;
+ estack_T *entry;
+ char *res;
+ int done;
+
+ entry = ((estack_T *)exestack.ga_data) + exestack.ga_len - 1;
+ if (entry->es_name == NULL)
+ return NULL;
+ if (entry->es_info.ufunc == NULL)
+ return vim_strsave(entry->es_name);
+
+ // For a function we compose the call stack, as it was done in the past:
+ // "function One[123]..Two[456]..Three"
+ len = STRLEN(entry->es_name) + 10;
+ 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;
+ }
+
+ res = (char *)alloc(len);
+ if (res != NULL)
+ {
+ STRCPY(res, "function ");
+ while (idx < exestack.ga_len - 1)
+ {
+ done = STRLEN(res);
+ entry = ((estack_T *)exestack.ga_data) + idx;
+ vim_snprintf(res + done, len - done, "%s[%ld]..",
+ 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 (char_u *)res;
+ }
+
+ /*
* ":runtime [what] {name}"
*/
void
***************
*** 947,954 ****
int is_vimrc) // DOSO_ value
{
struct source_cookie cookie;
- char_u *save_sourcing_name;
- linenr_T save_sourcing_lnum;
char_u *p;
char_u *fname_exp;
char_u *firstline = NULL;
--- 1063,1068 ----
***************
*** 1039,1049 ****
if (p_verbose > 0)
{
verbose_enter();
! if (sourcing_name == NULL)
smsg(_("could not source \"%s\""), fname);
else
smsg(_("line %ld: could not source \"%s\""),
! sourcing_lnum, fname);
verbose_leave();
}
goto theend;
--- 1153,1163 ----
if (p_verbose > 0)
{
verbose_enter();
! if (SOURCING_NAME == NULL)
smsg(_("could not source \"%s\""), fname);
else
smsg(_("line %ld: could not source \"%s\""),
! SOURCING_LNUM, fname);
verbose_leave();
}
goto theend;
***************
*** 1055,1065 ****
if (p_verbose > 1)
{
verbose_enter();
! if (sourcing_name == NULL)
smsg(_("sourcing \"%s\""), fname);
else
! smsg(_("line %ld: sourcing \"%s\""),
! sourcing_lnum, fname);
verbose_leave();
}
if (is_vimrc == DOSO_VIMRC)
--- 1169,1178 ----
if (p_verbose > 1)
{
verbose_enter();
! if (SOURCING_NAME == NULL)
smsg(_("sourcing \"%s\""), fname);
else
! smsg(_("line %ld: sourcing \"%s\""), SOURCING_LNUM, fname);
verbose_leave();
}
if (is_vimrc == DOSO_VIMRC)
***************
*** 1090,1099 ****
#endif

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

#ifdef STARTUPTIME
if (time_fd != NULL)
--- 1203,1209 ----
#endif

// Keep the sourcing name/lnum, for recursive calls.
! estack_push(ETYPE_SCRIPT, fname_exp, 0);

#ifdef STARTUPTIME
if (time_fd != NULL)
***************
*** 1233,1246 ****

if (got_int)
emsg(_(e_interr));
! sourcing_name = save_sourcing_name;
! sourcing_lnum = save_sourcing_lnum;
if (p_verbose > 1)
{
verbose_enter();
smsg(_("finished sourcing %s"), fname);
! if (sourcing_name != NULL)
! smsg(_("continuing in %s"), sourcing_name);
verbose_leave();
}
#ifdef STARTUPTIME
--- 1343,1355 ----

if (got_int)
emsg(_(e_interr));
! estack_pop();
if (p_verbose > 1)
{
verbose_enter();
smsg(_("finished sourcing %s"), fname);
! if (SOURCING_NAME != NULL)
! smsg(_("continuing in %s"), SOURCING_NAME);
verbose_leave();
}
#ifdef STARTUPTIME
***************
*** 1381,1387 ****
{
return fgetline == getsourceline
? ((struct source_cookie *)cookie)->sourcing_lnum
! : sourcing_lnum;
}

static char_u *
--- 1490,1496 ----
{
return fgetline == getsourceline
? ((struct source_cookie *)cookie)->sourcing_lnum
! : SOURCING_LNUM;
}

static char_u *
***************
*** 1507,1513 ****
// If breakpoints have been added/deleted need to check for it.
if (sp->dbg_tick < debug_tick)
{
! sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
sp->dbg_tick = debug_tick;
}
# ifdef FEAT_PROFILE
--- 1616,1622 ----
// If breakpoints have been added/deleted need to check for it.
if (sp->dbg_tick < debug_tick)
{
! sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, SOURCING_LNUM);
sp->dbg_tick = debug_tick;
}
# ifdef FEAT_PROFILE
***************
*** 1517,1523 ****
#endif

// Set the current sourcing line number.
! sourcing_lnum = sp->sourcing_lnum + 1;

// Get current line. If there is a read-ahead line, use it, otherwise get
// one now.
--- 1626,1632 ----
#endif

// Set the current sourcing line number.
! SOURCING_LNUM = sp->sourcing_lnum + 1;

// Get current line. If there is a read-ahead line, use it, otherwise get
// one now.
***************
*** 1602,1612 ****

#ifdef FEAT_EVAL
// Did we encounter a breakpoint?
! if (sp->breakpoint != 0 && sp->breakpoint <= sourcing_lnum)
{
! dbg_breakpoint(sp->fname, sourcing_lnum);
// Find next breakpoint.
! sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, sourcing_lnum);
sp->dbg_tick = debug_tick;
}
#endif
--- 1711,1721 ----

#ifdef FEAT_EVAL
// Did we encounter a breakpoint?
! if (sp->breakpoint != 0 && sp->breakpoint <= SOURCING_LNUM)
{
! dbg_breakpoint(sp->fname, SOURCING_LNUM);
// Find next breakpoint.
! sp->breakpoint = dbg_find_breakpoint(TRUE, sp->fname, SOURCING_LNUM);
sp->dbg_tick = debug_tick;
}
#endif
*** ../vim-8.2.0055/src/option.c 2019-12-05 20:11:19.000000000 +0100
--- src/option.c 2019-12-29 16:41:30.196427514 +0100
***************
*** 2435,2441 ****
int indir = (int)options[opt_idx].indir;
sctx_T new_script_ctx = script_ctx;

! new_script_ctx.sc_lnum += sourcing_lnum;

// Remember where the option was set. For local options need to do that
// in the buffer or window structure.
--- 2435,2441 ----
int indir = (int)options[opt_idx].indir;
sctx_T new_script_ctx = script_ctx;

! new_script_ctx.sc_lnum += SOURCING_LNUM;

// Remember where the option was set. For local options need to do that
// in the buffer or window structure.
*** ../vim-8.2.0055/src/profiler.c 2019-09-18 22:00:33.000000000 +0200
--- src/profiler.c 2019-12-29 16:42:33.308158473 +0100
***************
*** 602,611 ****
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;
// Skip continuation lines.
while (fp->uf_tml_idx > 0 && FUNCLINE(fp, fp->uf_tml_idx) == NULL)
--fp->uf_tml_idx;
--- 602,611 ----
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;
// Skip continuation lines.
while (fp->uf_tml_idx > 0 && FUNCLINE(fp, fp->uf_tml_idx) == NULL)
--fp->uf_tml_idx;
***************
*** 906,918 ****
if (current_sctx.sc_sid <= 0 || current_sctx.sc_sid > script_items.ga_len)
return;
si = &SCRIPT_ITEM(current_sctx.sc_sid);
! 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,
! (int)(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)
{
--- 906,918 ----
if (current_sctx.sc_sid <= 0 || current_sctx.sc_sid > script_items.ga_len)
return;
si = &SCRIPT_ITEM(current_sctx.sc_sid);
! 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,
! (int)(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)
{
*** ../vim-8.2.0055/src/spellfile.c 2019-12-05 21:20:39.000000000 +0100
--- src/spellfile.c 2019-12-29 16:33:07.918397631 +0100
***************
*** 349,356 ****
int i;
int n;
int len;
- char_u *save_sourcing_name = sourcing_name;
- linenr_T save_sourcing_lnum = sourcing_lnum;
slang_T *lp = NULL;
int c = 0;
int res;
--- 349,354 ----
***************
*** 393,400 ****
lp = old_lp;

// Set sourcing_name, so that error messages mention the file name.
! sourcing_name = fname;
! sourcing_lnum = 0;

/*
* <HEADER>: <fileID>
--- 391,397 ----
lp = old_lp;

// Set sourcing_name, so that error messages mention the file name.
! estack_push(ETYPE_SPELL, fname, 0);

/*
* <HEADER>: <fileID>
***************
*** 581,588 ****
endOK:
if (fd != NULL)
fclose(fd);
! sourcing_name = save_sourcing_name;
! sourcing_lnum = save_sourcing_lnum;

return lp;
}
--- 578,584 ----
endOK:
if (fd != NULL)
fclose(fd);
! estack_pop();

return lp;
}
*** ../vim-8.2.0055/src/term.c 2019-12-07 17:34:32.000000000 +0100
--- src/term.c 2019-12-29 16:34:24.690127317 +0100
***************
*** 2277,2283 ****
}
#endif

! if (sourcing_name == NULL)
{
#ifdef HAVE_TGETENT
if (error_msg != NULL)
--- 2277,2283 ----
}
#endif

! if (SOURCING_NAME == NULL)
{
#ifdef HAVE_TGETENT
if (error_msg != NULL)
*** ../vim-8.2.0055/src/testing.c 2019-12-23 22:59:14.264820697 +0100
--- src/testing.c 2019-12-29 20:31:46.756611485 +0100
***************
*** 21,42 ****
static void
prepare_assert_error(garray_T *gap)
{
! char buf[NUMBUFLEN];

ga_init2(gap, 1, 100);
! if (sourcing_name != NULL)
{
! ga_concat(gap, sourcing_name);
! if (sourcing_lnum > 0)
ga_concat(gap, (char_u *)" ");
}
! if (sourcing_lnum > 0)
{
! sprintf(buf, "line %ld", (long)sourcing_lnum);
ga_concat(gap, (char_u *)buf);
}
! if (sourcing_name != NULL || sourcing_lnum > 0)
ga_concat(gap, (char_u *)": ");
}

/*
--- 21,44 ----
static void
prepare_assert_error(garray_T *gap)
{
! char buf[NUMBUFLEN];
! char_u *sname = estack_sfile();

ga_init2(gap, 1, 100);
! if (sname != NULL)
{
! ga_concat(gap, sname);
! if (SOURCING_LNUM > 0)
ga_concat(gap, (char_u *)" ");
}
! if (SOURCING_LNUM > 0)
{
! sprintf(buf, "line %ld", (long)SOURCING_LNUM);
ga_concat(gap, (char_u *)buf);
}
! if (sname != NULL || SOURCING_LNUM > 0)
ga_concat(gap, (char_u *)": ");
+ vim_free(sname);
}

/*
*** ../vim-8.2.0055/src/usercmd.c 2019-12-29 13:56:28.692861883 +0100
--- src/usercmd.c 2019-12-29 16:43:13.271990339 +0100
***************
*** 191,197 ****
{
xp->xp_arg = uc->uc_compl_arg;
xp->xp_script_ctx = uc->uc_script_ctx;
! xp->xp_script_ctx.sc_lnum += sourcing_lnum;
}
# endif
// Do not search for further abbreviations
--- 191,197 ----
{
xp->xp_arg = uc->uc_compl_arg;
xp->xp_script_ctx = uc->uc_script_ctx;
! xp->xp_script_ctx.sc_lnum += SOURCING_LNUM;
}
# endif
// Do not search for further abbreviations
***************
*** 956,962 ****
cmd->uc_compl = compl;
#ifdef FEAT_EVAL
cmd->uc_script_ctx = current_sctx;
! cmd->uc_script_ctx.sc_lnum += sourcing_lnum;
cmd->uc_compl_arg = compl_arg;
#endif
cmd->uc_addr_type = addr_type;
--- 956,962 ----
cmd->uc_compl = compl;
#ifdef FEAT_EVAL
cmd->uc_script_ctx = current_sctx;
! cmd->uc_script_ctx.sc_lnum += SOURCING_LNUM;
cmd->uc_compl_arg = compl_arg;
#endif
cmd->uc_addr_type = addr_type;
*** ../vim-8.2.0055/src/userfunc.c 2019-12-25 15:03:56.526592324 +0100
--- src/userfunc.c 2019-12-29 19:44:28.321252384 +0100
***************
*** 226,231 ****
--- 226,247 ----
return OK;
}

+ 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 = alloc(STRLEN(name) + 3);
+ if (fp->uf_name_exp != NULL)
+ {
+ 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}.
***************
*** 309,315 ****
vim_strncpy(p + 7, s, e - s);

fp->uf_refcount = 1;
! STRCPY(fp->uf_name, name);
hash_add(&func_hashtab, UF2HIKEY(fp));
fp->uf_args = newargs;
ga_init(&fp->uf_def_args);
--- 325,331 ----
vim_strncpy(p + 7, s, e - s);

fp->uf_refcount = 1;
! set_ufunc_name(fp, name);
hash_add(&func_hashtab, UF2HIKEY(fp));
fp->uf_args = newargs;
ga_init(&fp->uf_def_args);
***************
*** 333,339 ****
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;

pt->pt_func = fp;
pt->pt_refcount = 1;
--- 349,355 ----
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;

pt->pt_func = fp;
pt->pt_refcount = 1;
***************
*** 759,766 ****
linenr_T lastline, // last line of range
dict_T *selfdict) // Dictionary for "self"
{
- char_u *save_sourcing_name;
- linenr_T save_sourcing_lnum;
sctx_T save_current_sctx;
int using_sandbox = FALSE;
funccall_T *fc;
--- 775,780 ----
***************
*** 774,780 ****
int islambda = FALSE;
char_u numbuf[NUMBUFLEN];
char_u *name;
- size_t len;
#ifdef FEAT_PROFILE
proftime_T wait_start;
proftime_T call_start;
--- 788,793 ----
***************
*** 948,956 ****

// Don't redraw while executing the function.
++RedrawingDisabled;
- save_sourcing_name = sourcing_name;
- save_sourcing_lnum = sourcing_lnum;
- sourcing_lnum = 1;

if (fp->uf_flags & FC_SANDBOX)
{
--- 961,966 ----
***************
*** 958,1022 ****
++sandbox;
}

! // need space for function name + ("function " + 3) or "[number]"
! len = (save_sourcing_name == NULL ? 0 : STRLEN(save_sourcing_name))
! + STRLEN(fp->uf_name) + 20;
! sourcing_name = alloc(len);
! if (sourcing_name != NULL)
! {
! if (save_sourcing_name != NULL
! && STRNCMP(save_sourcing_name, "function ", 9) == 0)
! sprintf((char *)sourcing_name, "%s[%d]..",
! save_sourcing_name, (int)save_sourcing_lnum);
! else
! STRCPY(sourcing_name, "function ");
! cat_func_name(sourcing_name + STRLEN(sourcing_name), fp);
!
! if (p_verbose >= 12)
! {
! ++no_wait_return;
! verbose_enter_scroll();
!
! smsg(_("calling %s"), sourcing_name);
! if (p_verbose >= 14)
! {
! char_u buf[MSG_BUF_LEN];
! char_u numbuf2[NUMBUFLEN];
! char_u *tofree;
! char_u *s;

! msg_puts("(");
! for (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;
! s = tv2string(&argvars[i], &tofree, numbuf2, 0);
! --emsg_off;
! if (s != NULL)
{
! if (vim_strsize(s) > MSG_BUF_CLEN)
! {
! trunc_string(s, buf, MSG_BUF_CLEN, MSG_BUF_LEN);
! s = buf;
! }
! msg_puts((char *)s);
! vim_free(tofree);
}
}
}
- msg_puts(")");
}
! msg_puts("\n"); // don't overwrite this either
!
! verbose_leave_scroll();
! --no_wait_return;
}
}
#ifdef FEAT_PROFILE
if (do_profiling == PROF_YES)
--- 968,1018 ----
++sandbox;
}

! estack_push_ufunc(ETYPE_UFUNC, fp, 1);
! if (p_verbose >= 12)
! {
! ++no_wait_return;
! verbose_enter_scroll();
!
! smsg(_("calling %s"), SOURCING_NAME);
! if (p_verbose >= 14)
! {
! char_u buf[MSG_BUF_LEN];
! char_u numbuf2[NUMBUFLEN];
! char_u *tofree;
! char_u *s;

! msg_puts("(");
! for (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;
! s = tv2string(&argvars[i], &tofree, numbuf2, 0);
! --emsg_off;
! if (s != NULL)
{
! if (vim_strsize(s) > MSG_BUF_CLEN)
{
! trunc_string(s, buf, MSG_BUF_CLEN, MSG_BUF_LEN);
! s = buf;
}
+ msg_puts((char *)s);
+ vim_free(tofree);
}
}
}
! msg_puts(")");
}
+ msg_puts("\n"); // don't overwrite this either
+
+ verbose_leave_scroll();
+ --no_wait_return;
}
#ifdef FEAT_PROFILE
if (do_profiling == PROF_YES)
***************
*** 1085,1093 ****
verbose_enter_scroll();

if (aborting())
! smsg(_("%s aborted"), sourcing_name);
else if (fc->rettv->v_type == VAR_NUMBER)
! smsg(_("%s returning #%ld"), sourcing_name,
(long)fc->rettv->vval.v_number);
else
{
--- 1081,1089 ----
verbose_enter_scroll();

if (aborting())
! smsg(_("%s aborted"), SOURCING_NAME);
else if (fc->rettv->v_type == VAR_NUMBER)
! smsg(_("%s returning #%ld"), SOURCING_NAME,
(long)fc->rettv->vval.v_number);
else
{
***************
*** 1109,1115 ****
trunc_string(s, buf, MSG_BUF_CLEN, MSG_BUF_LEN);
s = buf;
}
! smsg(_("%s returning %s"), sourcing_name, s);
vim_free(tofree);
}
}
--- 1105,1111 ----
trunc_string(s, buf, MSG_BUF_CLEN, MSG_BUF_LEN);
s = buf;
}
! smsg(_("%s returning %s"), SOURCING_NAME, s);
vim_free(tofree);
}
}
***************
*** 1119,1127 ****
--no_wait_return;
}

! vim_free(sourcing_name);
! sourcing_name = save_sourcing_name;
! sourcing_lnum = save_sourcing_lnum;
current_sctx = save_current_sctx;
#ifdef FEAT_PROFILE
if (do_profiling == PROF_YES)
--- 1115,1121 ----
--no_wait_return;
}

! estack_pop();
current_sctx = save_current_sctx;
#ifdef FEAT_PROFILE
if (do_profiling == PROF_YES)
***************
*** 1130,1141 ****
if (using_sandbox)
--sandbox;

! if (p_verbose >= 12 && sourcing_name != NULL)
{
++no_wait_return;
verbose_enter_scroll();

! smsg(_("continuing in %s"), sourcing_name);
msg_puts("\n"); // don't overwrite this either

verbose_leave_scroll();
--- 1124,1135 ----
if (using_sandbox)
--sandbox;

! if (p_verbose >= 12 && SOURCING_NAME != NULL)
{
++no_wait_return;
verbose_enter_scroll();

! smsg(_("continuing in %s"), SOURCING_NAME);
msg_puts("\n"); // don't overwrite this either

verbose_leave_scroll();
***************
*** 1204,1216 ****
ga_clear_strings(&(fp->uf_args));
ga_clear_strings(&(fp->uf_def_args));
ga_clear_strings(&(fp->uf_lines));
#ifdef FEAT_PROFILE
! vim_free(fp->uf_tml_count);
! fp->uf_tml_count = NULL;
! vim_free(fp->uf_tml_total);
! fp->uf_tml_total = NULL;
! vim_free(fp->uf_tml_self);
! fp->uf_tml_self = NULL;
#endif
}

--- 1198,1208 ----
ga_clear_strings(&(fp->uf_args));
ga_clear_strings(&(fp->uf_def_args));
ga_clear_strings(&(fp->uf_lines));
+ VIM_CLEAR(fp->uf_name_exp);
#ifdef FEAT_PROFILE
! VIM_CLEAR(fp->uf_tml_count);
! VIM_CLEAR(fp->uf_tml_total);
! VIM_CLEAR(fp->uf_tml_self);
#endif
}

***************
*** 1736,1746 ****
if (indent)
msg_puts(" ");
msg_puts("function ");
! if (fp->uf_name[0] == K_SPECIAL)
! {
! msg_puts_attr("<SNR>", HL_ATTR(HLF_8));
! msg_puts((char *)fp->uf_name + 3);
! }
else
msg_puts((char *)fp->uf_name);
msg_putchar('(');
--- 1728,1735 ----
if (indent)
msg_puts(" ");
msg_puts("function ");
! if (fp->uf_name_exp != NULL)
! msg_puts((char *)fp->uf_name_exp);
else
msg_puts((char *)fp->uf_name);
msg_putchar('(');
***************
*** 2308,2314 ****
}

// Save the starting line number.
! sourcing_lnum_top = sourcing_lnum;

indent = 2;
nesting = 0;
--- 2297,2303 ----
}

// Save the starting line number.
! sourcing_lnum_top = SOURCING_LNUM;

indent = 2;
nesting = 0;
***************
*** 2351,2360 ****
goto erret;
}

! // 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;
else
sourcing_lnum_off = 0;

--- 2340,2349 ----
goto erret;
}

! // 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;
else
sourcing_lnum_off = 0;

***************
*** 2631,2646 ****

// Check that the autoload name matches the script name.
j = FAIL;
! if (sourcing_name != NULL)
{
scriptname = autoload_name(name);
if (scriptname != NULL)
{
p = vim_strchr(scriptname, '/');
plen = (int)STRLEN(p);
! slen = (int)STRLEN(sourcing_name);
if (slen > plen && fnamecmp(p,
! sourcing_name + slen - plen) == 0)
j = OK;
vim_free(scriptname);
}
--- 2620,2635 ----

// Check that the autoload name matches the script name.
j = FAIL;
! if (SOURCING_NAME != NULL)
{
scriptname = autoload_name(name);
if (scriptname != NULL)
{
p = vim_strchr(scriptname, '/');
plen = (int)STRLEN(p);
! slen = (int)STRLEN(SOURCING_NAME);
if (slen > plen && fnamecmp(p,
! SOURCING_NAME + slen - plen) == 0)
j = OK;
vim_free(scriptname);
}
***************
*** 2685,2691 ****
}

// insert the new function in the function list
! STRCPY(fp->uf_name, name);
if (overwrite)
{
hi = hash_find(&func_hashtab, name);
--- 2674,2680 ----
}

// insert the new function in the function list
! set_ufunc_name(fp, name);
if (overwrite)
{
hi = hash_find(&func_hashtab, name);
***************
*** 3353,3359 ****
if (fcp->dbg_tick != debug_tick)
{
fcp->breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name,
! sourcing_lnum);
fcp->dbg_tick = debug_tick;
}
#ifdef FEAT_PROFILE
--- 3342,3348 ----
if (fcp->dbg_tick != debug_tick)
{
fcp->breakpoint = dbg_find_breakpoint(FALSE, fp->uf_name,
! SOURCING_LNUM);
fcp->dbg_tick = debug_tick;
}
#ifdef FEAT_PROFILE
***************
*** 3376,3382 ****
else
{
retval = vim_strsave(((char_u **)(gap->ga_data))[fcp->linenr++]);
! sourcing_lnum = fcp->linenr;
#ifdef FEAT_PROFILE
if (do_profiling == PROF_YES)
func_line_start(cookie);
--- 3365,3371 ----
else
{
retval = vim_strsave(((char_u **)(gap->ga_data))[fcp->linenr++]);
! SOURCING_LNUM = fcp->linenr;
#ifdef FEAT_PROFILE
if (do_profiling == PROF_YES)
func_line_start(cookie);
***************
*** 3385,3396 ****
}

// Did we encounter a breakpoint?
! 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->dbg_tick = debug_tick;
}

--- 3374,3385 ----
}

// Did we encounter a breakpoint?
! 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->dbg_tick = debug_tick;
}

*** ../vim-8.2.0055/src/kword_test.c 2019-12-04 21:41:40.000000000 +0100
--- src/kword_test.c 2019-12-29 16:50:21.846266344 +0100
***************
*** 76,81 ****
--- 76,82 ----
int
main(void)
{
+ estack_init();
test_isword_funcs_utf8();
return 0;
}
*** ../vim-8.2.0055/src/testdir/test_debugger.vim 2019-08-07 22:51:41.000000000 +0200
--- src/testdir/test_debugger.vim 2019-12-29 21:00:41.864006715 +0100
***************
*** 14,20 ****
" Verify the expected output
let lnum = 20 - len(a:1)
for l in a:1
! call WaitForAssert({-> assert_equal(l, term_getline(a:buf, lnum))})
let lnum += 1
endfor
endif
--- 14,20 ----
" Verify the expected output
let lnum = 20 - len(a:1)
for l in a:1
! call WaitForAssert({-> assert_equal(l, term_getline(a:buf, lnum))}, 200)
let lnum += 1
endfor
endif
*** ../vim-8.2.0055/src/version.c 2019-12-29 15:19:00.470760367 +0100
--- src/version.c 2019-12-29 22:58:51.211858220 +0100
***************
*** 744,745 ****
--- 744,747 ----
{ /* Add new patch number below this line */
+ /**/
+ 56,
/**/

--
ARTHUR: Shut up! Will you shut up!
DENNIS: Ah, now we see the violence inherent in the system.
ARTHUR: Shut up!
DENNIS: Oh! Come and see the violence inherent in the system!
HELP! HELP! I'm being repressed!
The Quest for the Holy Grail (Monty Python)

/// Bram Moolenaar -- Br...@Moolenaar.net -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language -- http://www.Zimbu.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///

Bram Moolenaar

unread,
Dec 29, 2019, 6:16:57 PM12/29/19
to vim...@googlegroups.com

I wrote:

> Patch 8.2.0056
> 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.
> Files: src/structs.h, src/globals.h, src/autocmd.c, src/buffer.c
> src/debugger.c, src/ex_docmd.c, src/ex_eval.c, src/highlight.c,
> src/main.c, src/map.c, src/message.c, src/proto/scriptfile.pro,
> src/scriptfile.c, src/option.c, src/profiler.c, src/spellfile.c,
> src/term.c, src/testing.c, src/usercmd.c, src/userfunc.c,
> src/kword_test.c, src/testdir/test_debugger.vim

This drastically changes how Vim keeps track of what is executing.
I fixed all that tests could find, but there might be other places that
change unexpectedly. Let me know if you spot something.

Later I'll make some intentional changes to show more of the execution
stack. E.g. it should now be possible to see a sequence of a function
sourcing a file that calls a function, etc.

--
ARTHUR: What?
BLACK KNIGHT: None shall pass.
ARTHUR: I have no quarrel with you, good Sir knight, but I must cross
this bridge.
BLACK KNIGHT: Then you shall die.
Reply all
Reply to author
Forward
0 new messages