patch 8.1.0362: cannot get the script line number when executing a function

Problem:    Cannot get the script line number when executing a function.
Solution:   Store the line number besides the script ID. (Ozaki Kiichi,
            closes #3362)  Also display the line number with ":verbose set".
This commit is contained in:
Bram Moolenaar
2018-09-10 21:05:02 +02:00
parent 6b0b83f768
commit f29c1c6aa3
24 changed files with 716 additions and 562 deletions

View File

@@ -832,11 +832,12 @@ it, no matter how many backslashes.
\\# \#
Also see |`=|.
*:<cword>* *:<cWORD>* *:<cfile>* *<cfile>*
*:<sfile>* *<sfile>* *:<afile>* *<afile>*
*:<abuf>* *<abuf>* *:<amatch>* *<amatch>*
*:<cexpr>* *<cexpr>*
*<slnum>* *E495* *E496* *E497* *E499* *E500*
*:<cword>* *<cword>* *:<cWORD>* *<cWORD>*
*:<cexpr>* *<cexpr>* *:<cfile>* *<cfile>*
*:<afile>* *<afile>* *:<abuf>* *<abuf>*
*:<amatch>* *<amatch>*
*:<sfile>* *<sfile>* *:<slnum>* *<slnum>*
*:<sflnum>* *<sflnum>* *E499* *E500*
Note: these are typed literally, they are not special keys!
<cword> is replaced with the word under the cursor (like |star|)
<cWORD> is replaced with the WORD under the cursor (see |WORD|)
@@ -849,15 +850,16 @@ Note: these are typed literally, they are not special keys!
|gf| uses)
<afile> When executing autocommands, is replaced with the file name
of the buffer being manipulated, or the file for a read or
write.
write. *E495*
<abuf> When executing autocommands, is replaced with the currently
effective buffer number (for ":r file" and ":so file" it is
the current buffer, the file being read/sourced is not in a
buffer).
buffer). *E496*
<amatch> When executing autocommands, is replaced with the match for
which this autocommand was executed. It differs from
<afile> only when the file name isn't used to match with
(for FileType, Syntax and SpellFileMissing events).
which this autocommand was executed. *E497*
It differs from <afile> only when the file name isn't used
to match with (for FileType, Syntax and SpellFileMissing
events).
<sfile> When executing a ":source" command, is replaced with the
file name of the sourced file. *E498*
When executing a function, is replaced with:
@@ -870,6 +872,9 @@ Note: these are typed literally, they are not special keys!
line number. *E842*
When executing a function it's the line number relative to
the start of the function.
<sflnum> When executing a script, is replaced with the line number.
It differs from <slnum> in that <sflnum> is replaced with
the script line number in any situation. *E961*
*filename-modifiers*
*:_%:* *::8* *::p* *::.* *::~* *::h* *::t* *::r* *::e* *::s* *::gs* *::S*

View File

@@ -3798,7 +3798,10 @@ expand({expr} [, {nosuf} [, {list}]]) *expand()*
<abuf> autocmd buffer number (as a String!)
<amatch> autocmd matched name
<sfile> sourced script file or function name
<slnum> sourced script file line number
<slnum> sourced script line number or function
line number
<sflnum> script file line number, also when in
a function
<cword> word under the cursor
<cWORD> WORD under the cursor
<client> the {clientid} of the last received
@@ -5931,6 +5934,7 @@ maparg({name} [, {mode} [, {abbr} [, {dict}]]]) *maparg()*
(|mapmode-ic|)
"sid" The script local ID, used for <sid> mappings
(|<SID>|).
"lnum" The line number in "sid", zero if unknown.
"nowait" Do not wait for other, longer mappings.
(|:map-<nowait>|).

View File

@@ -2,7 +2,8 @@
# Common Makefile, defines the list of tests to run.
#
# Individual tests, including the ones part of test_alot
# Individual tests, including the ones part of test_alot.
# Please keep sorted up to test_alot.
NEW_TESTS = \
test_arglist \
test_arabic \
@@ -52,6 +53,7 @@ NEW_TESTS = \
test_exists_autocmd \
test_expand \
test_expand_dllpath \
test_expand_func \
test_expr \
test_expr_utf8 \
test_farsi \

View File

@@ -5412,7 +5412,7 @@ chk_modeline(
char_u *save_sourcing_name;
linenr_T save_sourcing_lnum;
#ifdef FEAT_EVAL
scid_T save_SID;
sctx_T save_current_sctx;
#endif
prev = -1;
@@ -5497,12 +5497,13 @@ chk_modeline(
if (*s != NUL) /* skip over an empty "::" */
{
#ifdef FEAT_EVAL
save_SID = current_SID;
current_SID = SID_MODELINE;
save_current_sctx = current_sctx;
current_sctx.sc_sid = SID_MODELINE;
current_sctx.sc_lnum = 0;
#endif
retval = do_set(s, OPT_MODELINE | OPT_LOCAL | flags);
#ifdef FEAT_EVAL
current_SID = save_SID;
current_sctx = save_current_sctx;
#endif
if (retval == FAIL) /* stop if error found */
break;

View File

@@ -1495,8 +1495,8 @@ list_vim_vars(int *first)
static void
list_script_vars(int *first)
{
if (current_SID > 0 && current_SID <= ga_scripts.ga_len)
list_hashtable_vars(&SCRIPT_VARS(current_SID),
if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= ga_scripts.ga_len)
list_hashtable_vars(&SCRIPT_VARS(current_sctx.sc_sid),
(char_u *)"s:", FALSE, first);
}
@@ -7202,7 +7202,7 @@ find_var_in_ht(
/* Must be something like "s:", otherwise "ht" would be NULL. */
switch (htname)
{
case 's': return &SCRIPT_SV(current_SID)->sv_var;
case 's': return &SCRIPT_SV(current_sctx.sc_sid)->sv_var;
case 'g': return &globvars_var;
case 'v': return &vimvars_var;
case 'b': return &curbuf->b_bufvar;
@@ -7286,8 +7286,8 @@ find_var_ht(char_u *name, char_u **varname)
if (*name == 'l') /* l: local function variable */
return get_funccal_local_ht();
if (*name == 's' /* script variable */
&& current_SID > 0 && current_SID <= ga_scripts.ga_len)
return &SCRIPT_VARS(current_SID);
&& current_sctx.sc_sid > 0 && current_sctx.sc_sid <= ga_scripts.ga_len)
return &SCRIPT_VARS(current_sctx.sc_sid);
return NULL;
}
@@ -8729,20 +8729,25 @@ store_session_globals(FILE *fd)
* Should only be invoked when 'verbose' is non-zero.
*/
void
last_set_msg(scid_T scriptID)
last_set_msg(sctx_T script_ctx)
{
char_u *p;
if (scriptID != 0)
if (script_ctx.sc_sid != 0)
{
p = home_replace_save(NULL, get_scriptname(scriptID));
p = home_replace_save(NULL, get_scriptname(script_ctx.sc_sid));
if (p != NULL)
{
verbose_enter();
MSG_PUTS(_("\n\tLast set from "));
MSG_PUTS(p);
vim_free(p);
if (script_ctx.sc_lnum > 0)
{
MSG_PUTS(_(" line "));
msg_outnum((long)script_ctx.sc_lnum);
}
verbose_leave();
vim_free(p);
}
}
}

View File

@@ -4061,7 +4061,7 @@ common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
* also be called from another script. Using trans_function_name()
* would also work, but some plugins depend on the name being
* printable text. */
sprintf(sid_buf, "<SNR>%ld_", (long)current_SID);
sprintf(sid_buf, "<SNR>%ld_", (long)current_sctx.sc_sid);
name = alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
if (name != NULL)
{
@@ -7618,7 +7618,8 @@ get_maparg(typval_T *argvars, typval_T *rettv, int exact)
dict_add_number(dict, "noremap", mp->m_noremap ? 1L : 0L);
dict_add_number(dict, "expr", mp->m_expr ? 1L : 0L);
dict_add_number(dict, "silent", mp->m_silent ? 1L : 0L);
dict_add_number(dict, "sid", (long)mp->m_script_ID);
dict_add_number(dict, "sid", (long)mp->m_script_ctx.sc_sid);
dict_add_number(dict, "lnum", (long)mp->m_script_ctx.sc_lnum);
dict_add_number(dict, "buffer", (long)buffer_local);
dict_add_number(dict, "nowait", mp->m_nowait ? 1L : 0L);
dict_add_string(dict, "mode", mapmode);

View File

@@ -1866,9 +1866,9 @@ script_prof_save(
{
scriptitem_T *si;
if (current_SID > 0 && current_SID <= script_items.ga_len)
if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= script_items.ga_len)
{
si = &SCRIPT_ITEM(current_SID);
si = &SCRIPT_ITEM(current_sctx.sc_sid);
if (si->sn_prof_on && si->sn_pr_nest++ == 0)
profile_start(&si->sn_pr_child);
}
@@ -1883,9 +1883,9 @@ script_prof_restore(proftime_T *tm)
{
scriptitem_T *si;
if (current_SID > 0 && current_SID <= script_items.ga_len)
if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= script_items.ga_len)
{
si = &SCRIPT_ITEM(current_SID);
si = &SCRIPT_ITEM(current_sctx.sc_sid);
if (si->sn_prof_on && --si->sn_pr_nest == 0)
{
profile_end(&si->sn_pr_child);
@@ -2003,8 +2003,8 @@ script_dump_profile(FILE *fd)
int
prof_def_func(void)
{
if (current_SID > 0)
return SCRIPT_ITEM(current_SID).sn_pr_force;
if (current_sctx.sc_sid > 0)
return SCRIPT_ITEM(current_sctx.sc_sid).sn_pr_force;
return FALSE;
}
@@ -4351,7 +4351,7 @@ do_source(
char_u *firstline = NULL;
int retval = FAIL;
#ifdef FEAT_EVAL
scid_T save_current_SID;
sctx_T save_current_sctx;
static scid_T last_current_SID = 0;
void *save_funccalp;
int save_debug_break_level = debug_break_level;
@@ -4521,13 +4521,15 @@ do_source(
* Check if this script was sourced before to finds its SID.
* If it's new, generate a new SID.
*/
save_current_SID = current_SID;
save_current_sctx = current_sctx;
current_sctx.sc_lnum = 0;
# ifdef UNIX
stat_ok = (mch_stat((char *)fname_exp, &st) >= 0);
# endif
for (current_SID = script_items.ga_len; current_SID > 0; --current_SID)
for (current_sctx.sc_sid = script_items.ga_len; current_sctx.sc_sid > 0;
--current_sctx.sc_sid)
{
si = &SCRIPT_ITEM(current_SID);
si = &SCRIPT_ITEM(current_sctx.sc_sid);
if (si->sn_name != NULL
&& (
# ifdef UNIX
@@ -4541,13 +4543,13 @@ do_source(
fnamecmp(si->sn_name, fname_exp) == 0))
break;
}
if (current_SID == 0)
if (current_sctx.sc_sid == 0)
{
current_SID = ++last_current_SID;
if (ga_grow(&script_items, (int)(current_SID - script_items.ga_len))
== FAIL)
current_sctx.sc_sid = ++last_current_SID;
if (ga_grow(&script_items,
(int)(current_sctx.sc_sid - script_items.ga_len)) == FAIL)
goto almosttheend;
while (script_items.ga_len < current_SID)
while (script_items.ga_len < current_sctx.sc_sid)
{
++script_items.ga_len;
SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
@@ -4555,7 +4557,7 @@ do_source(
SCRIPT_ITEM(script_items.ga_len).sn_prof_on = FALSE;
# endif
}
si = &SCRIPT_ITEM(current_SID);
si = &SCRIPT_ITEM(current_sctx.sc_sid);
si->sn_name = fname_exp;
fname_exp = NULL;
# ifdef UNIX
@@ -4570,7 +4572,7 @@ do_source(
# endif
/* Allocate the local script variables to use for this script. */
new_script_vars(current_SID);
new_script_vars(current_sctx.sc_sid);
}
# ifdef FEAT_PROFILE
@@ -4626,7 +4628,7 @@ do_source(
if (do_profiling == PROF_YES)
{
/* Get "si" again, "script_items" may have been reallocated. */
si = &SCRIPT_ITEM(current_SID);
si = &SCRIPT_ITEM(current_sctx.sc_sid);
if (si->sn_prof_on)
{
profile_end(&si->sn_pr_start);
@@ -4671,7 +4673,7 @@ do_source(
#ifdef FEAT_EVAL
almosttheend:
current_SID = save_current_SID;
current_sctx = save_current_sctx;
restore_funccal(save_funccalp);
# ifdef FEAT_PROFILE
if (do_profiling == PROF_YES)
@@ -5090,9 +5092,9 @@ script_line_start(void)
scriptitem_T *si;
sn_prl_T *pp;
if (current_SID <= 0 || current_SID > script_items.ga_len)
if (current_sctx.sc_sid <= 0 || current_sctx.sc_sid > script_items.ga_len)
return;
si = &SCRIPT_ITEM(current_SID);
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
@@ -5125,9 +5127,9 @@ script_line_exec(void)
{
scriptitem_T *si;
if (current_SID <= 0 || current_SID > script_items.ga_len)
if (current_sctx.sc_sid <= 0 || current_sctx.sc_sid > script_items.ga_len)
return;
si = &SCRIPT_ITEM(current_SID);
si = &SCRIPT_ITEM(current_sctx.sc_sid);
if (si->sn_prof_on && si->sn_prl_idx >= 0)
si->sn_prl_execed = TRUE;
}
@@ -5141,9 +5143,9 @@ script_line_end(void)
scriptitem_T *si;
sn_prl_T *pp;
if (current_SID <= 0 || current_SID > script_items.ga_len)
if (current_sctx.sc_sid <= 0 || current_sctx.sc_sid > script_items.ga_len)
return;
si = &SCRIPT_ITEM(current_SID);
si = &SCRIPT_ITEM(current_sctx.sc_sid);
if (si->sn_prof_on && si->sn_prl_idx >= 0
&& si->sn_prl_idx < si->sn_prl_ga.ga_len)
{

View File

@@ -29,7 +29,7 @@ typedef struct ucmd
int uc_compl; /* completion type */
int uc_addr_type; /* The command's address type */
# ifdef FEAT_EVAL
scid_T uc_scriptID; /* SID where the command was defined */
sctx_T uc_script_ctx; /* SCTX where the command was defined */
# ifdef FEAT_CMDL_COMPL
char_u *uc_compl_arg; /* completion argument if any */
# endif
@@ -3340,7 +3340,8 @@ find_ucmd(
if (xp != NULL)
{
xp->xp_arg = uc->uc_compl_arg;
xp->xp_scriptID = uc->uc_scriptID;
xp->xp_script_ctx = uc->uc_script_ctx;
xp->xp_script_ctx.sc_lnum += sourcing_lnum;
}
# endif
# endif
@@ -5920,7 +5921,8 @@ uc_add_command(
cmd->uc_def = def;
cmd->uc_compl = compl;
#ifdef FEAT_EVAL
cmd->uc_scriptID = current_SID;
cmd->uc_script_ctx = current_sctx;
cmd->uc_script_ctx.sc_lnum += sourcing_lnum;
# ifdef FEAT_CMDL_COMPL
cmd->uc_compl_arg = compl_arg;
# endif
@@ -6141,7 +6143,7 @@ uc_list(char_u *name, size_t name_len)
msg_outtrans_special(cmd->uc_rep, FALSE);
#ifdef FEAT_EVAL
if (p_verbose > 0)
last_set_msg(cmd->uc_scriptID);
last_set_msg(cmd->uc_script_ctx);
#endif
out_flush();
ui_breakcheck();
@@ -6906,7 +6908,7 @@ do_ucmd(exarg_T *eap)
char_u *split_buf = NULL;
ucmd_T *cmd;
#ifdef FEAT_EVAL
scid_T save_current_SID = current_SID;
sctx_T save_current_sctx = current_sctx;
#endif
if (eap->cmdidx == CMD_USER)
@@ -7007,12 +7009,12 @@ do_ucmd(exarg_T *eap)
}
#ifdef FEAT_EVAL
current_SID = cmd->uc_scriptID;
current_sctx.sc_sid = cmd->uc_script_ctx.sc_sid;
#endif
(void)do_cmdline(buf, eap->getline, eap->cookie,
DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_KEYTYPED);
#ifdef FEAT_EVAL
current_SID = save_current_SID;
current_sctx = save_current_sctx;
#endif
vim_free(buf);
vim_free(split_buf);
@@ -10741,9 +10743,11 @@ find_cmdline_var(char_u *src, int *usedlen)
#define SPEC_ABUF (SPEC_AFILE + 1)
"<amatch>", /* autocommand match name */
#define SPEC_AMATCH (SPEC_ABUF + 1)
"<sflnum>", /* script file line number */
#define SPEC_SFLNUM (SPEC_AMATCH + 1)
#ifdef FEAT_CLIENTSERVER
"<client>"
# define SPEC_CLIENT (SPEC_AMATCH + 1)
# define SPEC_CLIENT (SPEC_SFLNUM + 1)
#endif
};
@@ -10999,6 +11003,7 @@ eval_vars(
return NULL;
}
break;
case SPEC_SLNUM: /* line in file for ":so" command */
if (sourcing_name == NULL || sourcing_lnum == 0)
{
@@ -11008,13 +11013,28 @@ eval_vars(
sprintf((char *)strbuf, "%ld", (long)sourcing_lnum);
result = strbuf;
break;
#if defined(FEAT_CLIENTSERVER)
#ifdef FEAT_EVAL
case SPEC_SFLNUM: /* line in script file */
if (current_sctx.sc_lnum + sourcing_lnum == 0)
{
*errormsg = (char_u *)_("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
#ifdef FEAT_CLIENTSERVER
case SPEC_CLIENT: /* Source of last submitted input */
sprintf((char *)strbuf, PRINTF_HEX_LONG_U,
(long_u)clientWindow);
result = strbuf;
break;
#endif
default:
result = (char_u *)""; /* avoid gcc warning */
break;

View File

@@ -5591,7 +5591,7 @@ call_user_expand_func(
{
int keep = 0;
typval_T args[4];
int save_current_SID = current_SID;
sctx_T save_current_sctx = current_sctx;
char_u *pat = NULL;
void *ret;
struct cmdline_info save_ccline;
@@ -5621,12 +5621,12 @@ call_user_expand_func(
save_ccline = ccline;
ccline.cmdbuff = NULL;
ccline.cmdprompt = NULL;
current_SID = xp->xp_scriptID;
current_sctx = xp->xp_script_ctx;
ret = user_expand_func(xp->xp_arg, 3, args);
ccline = save_ccline;
current_SID = save_current_SID;
current_sctx = save_current_sctx;
if (ccline.cmdbuff != NULL)
ccline.cmdbuff[ccline.cmdlen] = keep;

View File

@@ -7700,7 +7700,7 @@ typedef struct AutoCmd
char nested; /* If autocommands nest here */
char last; /* last command in list */
#ifdef FEAT_EVAL
scid_T scriptID; /* script ID where defined */
sctx_T script_ctx; /* script context where defined */
#endif
struct AutoCmd *next; /* Next AutoCmd in list */
} AutoCmd;
@@ -7962,7 +7962,7 @@ show_autocmd(AutoPat *ap, event_T event)
msg_outtrans(ac->cmd);
#ifdef FEAT_EVAL
if (p_verbose > 0)
last_set_msg(ac->scriptID);
last_set_msg(ac->script_ctx);
#endif
if (got_int)
return;
@@ -8845,7 +8845,8 @@ do_autocmd_event(
return FAIL;
ac->cmd = vim_strsave(cmd);
#ifdef FEAT_EVAL
ac->scriptID = current_SID;
ac->script_ctx = current_sctx;
ac->script_ctx.sc_lnum += sourcing_lnum;
#endif
if (ac->cmd == NULL)
{
@@ -9412,7 +9413,7 @@ apply_autocmds_group(
AutoPatCmd patcmd;
AutoPat *ap;
#ifdef FEAT_EVAL
scid_T save_current_SID;
sctx_T save_current_sctx;
void *save_funccalp;
char_u *save_cmdarg;
long save_cmdbang;
@@ -9621,7 +9622,7 @@ apply_autocmds_group(
sourcing_lnum = 0; /* no line number here */
#ifdef FEAT_EVAL
save_current_SID = current_SID;
save_current_sctx = current_sctx;
# ifdef FEAT_PROFILE
if (do_profiling == PROF_YES)
@@ -9725,7 +9726,7 @@ apply_autocmds_group(
autocmd_bufnr = save_autocmd_bufnr;
autocmd_match = save_autocmd_match;
#ifdef FEAT_EVAL
current_SID = save_current_SID;
current_sctx = save_current_sctx;
restore_funccal(save_funccalp);
# ifdef FEAT_PROFILE
if (do_profiling == PROF_YES)
@@ -9949,7 +9950,7 @@ getnextac(int c UNUSED, void *cookie, int indent UNUSED)
retval = vim_strsave(ac->cmd);
autocmd_nested = ac->nested;
#ifdef FEAT_EVAL
current_SID = ac->scriptID;
current_sctx = ac->script_ctx;
#endif
if (ac->last)
acp->nextcmd = NULL;

View File

@@ -3677,7 +3677,8 @@ do_map(
mp->m_mode = mode;
#ifdef FEAT_EVAL
mp->m_expr = expr;
mp->m_script_ID = current_SID;
mp->m_script_ctx = current_sctx;
mp->m_script_ctx.sc_lnum += sourcing_lnum;
#endif
did_it = TRUE;
}
@@ -3783,7 +3784,8 @@ do_map(
mp->m_mode = mode;
#ifdef FEAT_EVAL
mp->m_expr = expr;
mp->m_script_ID = current_SID;
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 */
@@ -4097,7 +4099,7 @@ showmap(
}
#ifdef FEAT_EVAL
if (p_verbose > 0)
last_set_msg(mp->m_script_ID);
last_set_msg(mp->m_script_ctx);
#endif
out_flush(); /* show one line at a time */
}

View File

@@ -325,8 +325,8 @@ EXTERN int may_garbage_collect INIT(= FALSE);
EXTERN int want_garbage_collect INIT(= FALSE);
EXTERN int garbage_collect_at_exit INIT(= FALSE);
/* ID of script being sourced or was sourced to define the current function. */
EXTERN scid_T current_SID INIT(= 0);
// Script CTX being sourced or was sourced to define the current function.
EXTERN sctx_T current_sctx INIT(= {0 COMMA 0});
#endif
EXTERN int did_source_packages INIT(= FALSE);

View File

@@ -2912,13 +2912,13 @@ exe_pre_commands(mparm_T *parmp)
curwin->w_cursor.lnum = 0; /* just in case.. */
sourcing_name = (char_u *)_("pre-vimrc command line");
# ifdef FEAT_EVAL
current_SID = SID_CMDARG;
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_SID = 0;
current_sctx.sc_sid = 0;
# endif
TIME_MSG("--cmd commands");
}
@@ -2942,7 +2942,7 @@ exe_commands(mparm_T *parmp)
curwin->w_cursor.lnum = 0;
sourcing_name = (char_u *)"command line";
#ifdef FEAT_EVAL
current_SID = SID_CARG;
current_sctx.sc_sid = SID_CARG;
#endif
for (i = 0; i < parmp->n_commands; ++i)
{
@@ -2952,7 +2952,7 @@ exe_commands(mparm_T *parmp)
}
sourcing_name = NULL;
#ifdef FEAT_EVAL
current_SID = 0;
current_sctx.sc_sid = 0;
#endif
if (curwin->w_cursor.lnum == 0)
curwin->w_cursor.lnum = 1;
@@ -3159,7 +3159,7 @@ process_env(
char_u *save_sourcing_name;
linenr_T save_sourcing_lnum;
#ifdef FEAT_EVAL
scid_T save_sid;
sctx_T save_current_sctx;
#endif
if ((initstr = mch_getenv(env)) != NULL && *initstr != NUL)
@@ -3171,14 +3171,15 @@ process_env(
sourcing_name = env;
sourcing_lnum = 0;
#ifdef FEAT_EVAL
save_sid = current_SID;
current_SID = SID_ENV;
save_current_sctx = current_sctx;
current_sctx.sc_sid = SID_ENV;
current_sctx.sc_lnum = 0;
#endif
do_cmdline_cmd(initstr);
sourcing_name = save_sourcing_name;
sourcing_lnum = save_sourcing_lnum;
#ifdef FEAT_EVAL
current_SID = save_sid;
current_sctx = save_current_sctx;
#endif
return OK;
}

View File

@@ -2259,7 +2259,7 @@ execute_menu(exarg_T *eap, vimmenu_T *menu)
/* Use the Insert mode entry when returning to Insert mode. */
if (restart_edit
#ifdef FEAT_EVAL
&& !current_SID
&& !current_sctx.sc_sid
#endif
)
{
@@ -2333,7 +2333,7 @@ execute_menu(exarg_T *eap, vimmenu_T *menu)
* Otherwise put them in the typeahead buffer. */
if (eap == NULL
#ifdef FEAT_EVAL
|| current_SID != 0
|| current_sctx.sc_sid != 0
#endif
)
{

File diff suppressed because it is too large Load Diff

View File

@@ -119,7 +119,7 @@ int script_autoload(char_u *name, int reload);
int read_viminfo_varlist(vir_T *virp, int writing);
void write_viminfo_varlist(FILE *fp);
int store_session_globals(FILE *fd);
void last_set_msg(scid_T scriptID);
void last_set_msg(sctx_T script_ctx);
void reset_v_option_vars(void);
void prepare_assert_error(garray_T *gap);
void assert_error(garray_T *gap);

View File

@@ -74,6 +74,19 @@ typedef struct terminal_S term_T;
typedef struct VimMenu vimmenu_T;
#endif
/*
* SCript ConteXt (SCTX): identifies a script script line.
* When sourcing a script "sc_lnum" is zero, "sourcing_lnum" is the current
* line number. When executing a user function "sc_lnum" is the line where the
* function was defined, "sourcing_lnum" is the line number inside the
* function. When stored with a function, mapping, option, etc. "sc_lnum" is
* the line number in the script "sc_sid".
*/
typedef struct {
scid_T sc_sid; // script ID
linenr_T sc_lnum; // line number
} sctx_T;
/*
* Reference to a buffer that stores the value of buf_free_count.
* bufref_valid() only needs to check "buf" when the count differs.
@@ -278,8 +291,8 @@ typedef struct
#endif
#ifdef FEAT_EVAL
int wo_scriptID[WV_COUNT]; /* SIDs for window-local options */
# define w_p_scriptID w_onebuf_opt.wo_scriptID
sctx_T wo_script_ctx[WV_COUNT]; /* SCTXs for window-local options */
# define w_p_script_ctx w_onebuf_opt.wo_script_ctx
#endif
} winopt_T;
@@ -541,7 +554,7 @@ typedef struct expand
int xp_pattern_len; /* bytes in xp_pattern before cursor */
#if defined(FEAT_USR_CMDS) && defined(FEAT_EVAL) && defined(FEAT_CMDL_COMPL)
char_u *xp_arg; /* completion function */
int xp_scriptID; /* SID for completion function */
sctx_T xp_script_ctx; /* SCTX for completion function */
#endif
int xp_backslash; /* one of the XP_BS_ values */
#ifndef BACKSLASH_IN_FILENAME
@@ -1071,7 +1084,7 @@ struct mapblock
char m_nowait; /* <nowait> used */
#ifdef FEAT_EVAL
char m_expr; /* <expr> used, m_str is an expression */
scid_T m_script_ID; /* ID of script where map was defined */
sctx_T m_script_ctx; /* SCTX where map was defined */
#endif
};
@@ -1361,7 +1374,7 @@ typedef struct
int uf_tml_idx; /* index of line being timed; -1 if none */
int uf_tml_execed; /* line being timed was executed */
#endif
scid_T uf_script_ID; /* ID of script where function was defined,
sctx_T uf_script_ctx; /* SCTX where function was defined,
used for s: variables */
int uf_refcount; /* reference count, see func_name_refcount() */
funccall_T *uf_scoped; /* l: local variables for closure */
@@ -2123,7 +2136,7 @@ struct file_buffer
int b_p_initialized; /* set when options initialized */
#ifdef FEAT_EVAL
int b_p_scriptID[BV_COUNT]; /* SIDs for buffer-local options */
sctx_T b_p_script_ctx[BV_COUNT]; /* SCTXs for buffer-local options */
#endif
int b_p_ai; /* 'autoindent' */

View File

@@ -58,7 +58,7 @@ struct hl_group
int sg_link; /* link to this highlight group ID */
int sg_set; /* combination of SG_* flags */
#ifdef FEAT_EVAL
scid_T sg_scriptID; /* script in which the group was last set */
sctx_T sg_script_ctx; /* script in which the group was last set */
#endif
};
@@ -7507,7 +7507,8 @@ do_highlight(
}
else if (HL_TABLE()[from_id - 1].sg_link != to_id
#ifdef FEAT_EVAL
|| HL_TABLE()[from_id - 1].sg_scriptID != current_SID
|| HL_TABLE()[from_id - 1].sg_script_ctx.sc_sid
!= current_sctx.sc_sid
#endif
|| HL_TABLE()[from_id - 1].sg_cleared)
{
@@ -7515,7 +7516,8 @@ do_highlight(
HL_TABLE()[from_id - 1].sg_set |= SG_LINK;
HL_TABLE()[from_id - 1].sg_link = to_id;
#ifdef FEAT_EVAL
HL_TABLE()[from_id - 1].sg_scriptID = current_SID;
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);
@@ -8277,7 +8279,8 @@ do_highlight(
else
set_hl_attr(idx);
#ifdef FEAT_EVAL
HL_TABLE()[idx].sg_scriptID = current_SID;
HL_TABLE()[idx].sg_script_ctx = current_sctx;
HL_TABLE()[idx].sg_script_ctx.sc_lnum += sourcing_lnum;
#endif
}
@@ -8404,7 +8407,10 @@ highlight_clear(int idx)
/* Clear the script ID only when there is no link, since that is not
* cleared. */
if (HL_TABLE()[idx].sg_link == 0)
HL_TABLE()[idx].sg_scriptID = 0;
{
HL_TABLE()[idx].sg_script_ctx.sc_sid = 0;
HL_TABLE()[idx].sg_script_ctx.sc_lnum = 0;
}
#endif
}
@@ -9272,7 +9278,7 @@ highlight_list_one(int id)
highlight_list_arg(id, didh, LIST_STRING, 0, (char_u *)"cleared", "");
#ifdef FEAT_EVAL
if (p_verbose > 0)
last_set_msg(sgp->sg_scriptID);
last_set_msg(sgp->sg_script_ctx);
#endif
}

View File

@@ -6128,7 +6128,7 @@ replace_termcodes(
*/
if (STRNICMP(src, "<SID>", 5) == 0)
{
if (current_SID <= 0)
if (current_sctx.sc_sid <= 0)
EMSG(_(e_usingsid));
else
{
@@ -6136,7 +6136,8 @@ replace_termcodes(
result[dlen++] = K_SPECIAL;
result[dlen++] = (int)KS_EXTRA;
result[dlen++] = (int)KE_SNR;
sprintf((char *)result + dlen, "%ld", (long)current_SID);
sprintf((char *)result + dlen, "%ld",
(long)current_sctx.sc_sid);
dlen += (int)STRLEN(result + dlen);
result[dlen++] = '_';
continue;

View File

@@ -14,6 +14,7 @@ source test_ex_z.vim
source test_execute_func.vim
source test_expand.vim
source test_expand_dllpath.vim
source test_expand_func.vim
source test_expr.vim
source test_feedkeys.vim
source test_file_perm.vim

View File

@@ -0,0 +1,66 @@
" Tests for expand()
let s:sfile = expand('<sfile>')
let s:slnum = str2nr(expand('<slnum>'))
let s:sflnum = str2nr(expand('<sflnum>'))
func s:expand_sfile()
return expand('<sfile>')
endfunc
func s:expand_slnum()
return str2nr(expand('<slnum>'))
endfunc
func s:expand_sflnum()
return str2nr(expand('<sflnum>'))
endfunc
func Test_expand_sfile()
call assert_match('test_expand_func\.vim$', s:sfile)
call assert_match('^function .*\.\.Test_expand_sfile$', expand('<sfile>'))
" Call in script-local function
call assert_match('^function .*\.\.Test_expand_sfile\[5\]\.\.<SNR>\d\+_expand_sfile$', s:expand_sfile())
" Call in command
command Sfile echo expand('<sfile>')
call assert_match('^function .*\.\.Test_expand_sfile$', trim(execute('Sfile')))
delcommand Sfile
endfunc
func Test_expand_slnum()
call assert_equal(4, s:slnum)
call assert_equal(2, str2nr(expand('<slnum>')))
" Line-continuation
call assert_equal(
\ 5,
\ str2nr(expand('<slnum>')))
" Call in script-local function
call assert_equal(1, s:expand_slnum())
" Call in command
command Slnum echo expand('<slnum>')
call assert_equal(14, str2nr(trim(execute('Slnum'))))
delcommand Slnum
endfunc
func Test_expand_sflnum()
call assert_equal(5, s:sflnum)
call assert_equal(52, str2nr(expand('<sflnum>')))
" Line-continuation
call assert_equal(
\ 55,
\ str2nr(expand('<sflnum>')))
" Call in script-local function
call assert_equal(16, s:expand_sflnum())
" Call in command
command Flnum echo expand('<sflnum>')
call assert_equal(64, str2nr(trim(execute('Flnum'))))
delcommand Flnum
endfunc

View File

@@ -13,19 +13,24 @@ function Test_maparg()
set cpo-=<
set encoding=utf8
" Test maparg() with a string result
let sid = s:SID()
let lnum = expand('<sflnum>')
map foo<C-V> is<F4>foo
vnoremap <script> <buffer> <expr> <silent> bar isbar
let sid = s:SID()
call assert_equal("is<F4>foo", maparg('foo<C-V>'))
call assert_equal({'silent': 0, 'noremap': 0, 'lhs': 'foo<C-V>',
\ 'mode': ' ', 'nowait': 0, 'expr': 0, 'sid': sid, 'rhs': 'is<F4>foo',
\ 'buffer': 0}, maparg('foo<C-V>', '', 0, 1))
\ 'mode': ' ', 'nowait': 0, 'expr': 0, 'sid': sid, 'lnum': lnum + 1,
\ 'rhs': 'is<F4>foo', 'buffer': 0},
\ maparg('foo<C-V>', '', 0, 1))
call assert_equal({'silent': 1, 'noremap': 1, 'lhs': 'bar', 'mode': 'v',
\ 'nowait': 0, 'expr': 1, 'sid': sid, 'rhs': 'isbar', 'buffer': 1},
\ 'nowait': 0, 'expr': 1, 'sid': sid, 'lnum': lnum + 2,
\ 'rhs': 'isbar', 'buffer': 1},
\ maparg('bar', '', 0, 1))
let lnum = expand('<sflnum>')
map <buffer> <nowait> foo bar
call assert_equal({'silent': 0, 'noremap': 0, 'lhs': 'foo', 'mode': ' ',
\ 'nowait': 1, 'expr': 0, 'sid': sid, 'rhs': 'bar', 'buffer': 1},
\ 'nowait': 1, 'expr': 0, 'sid': sid, 'lnum': lnum + 1, 'rhs': 'bar',
\ 'buffer': 1},
\ maparg('foo', '', 0, 1))
map abc x<char-114>x

View File

@@ -302,7 +302,8 @@ get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate)
fp->uf_varargs = TRUE;
fp->uf_flags = flags;
fp->uf_calls = 0;
fp->uf_script_ID = current_SID;
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;
@@ -505,11 +506,11 @@ fname_trans_sid(char_u *name, char_u *fname_buf, char_u **tofree, int *error)
i = 3;
if (eval_fname_sid(name)) /* "<SID>" or "s:" */
{
if (current_SID <= 0)
if (current_sctx.sc_sid <= 0)
*error = ERROR_SCRIPT;
else
{
sprintf((char *)fname_buf + 3, "%ld_", (long)current_SID);
sprintf((char *)fname_buf + 3, "%ld_", (long)current_sctx.sc_sid);
i = (int)STRLEN(fname_buf);
}
}
@@ -690,7 +691,7 @@ call_user_func(
{
char_u *save_sourcing_name;
linenr_T save_sourcing_lnum;
scid_T save_current_SID;
sctx_T save_current_sctx;
int using_sandbox = FALSE;
funccall_T *fc;
int save_did_emsg;
@@ -944,8 +945,8 @@ call_user_func(
}
#endif
save_current_SID = current_SID;
current_SID = fp->uf_script_ID;
save_current_sctx = current_sctx;
current_sctx = fp->uf_script_ctx;
save_did_emsg = did_emsg;
did_emsg = FALSE;
@@ -1026,7 +1027,7 @@ call_user_func(
vim_free(sourcing_name);
sourcing_name = save_sourcing_name;
sourcing_lnum = save_sourcing_lnum;
current_SID = save_current_SID;
current_sctx = save_current_sctx;
#ifdef FEAT_PROFILE
if (do_profiling == PROF_YES)
script_prof_restore(&wait_start);
@@ -1574,7 +1575,7 @@ list_func_head(ufunc_T *fp, int indent)
MSG_PUTS(" closure");
msg_clr_eos();
if (p_verbose > 0)
last_set_msg(fp->uf_script_ID);
last_set_msg(fp->uf_script_ctx);
}
/*
@@ -1757,12 +1758,12 @@ trans_function_name(
|| eval_fname_sid(*pp))
{
/* It's "s:" or "<SID>" */
if (current_SID <= 0)
if (current_sctx.sc_sid <= 0)
{
EMSG(_(e_usingsid));
goto theend;
}
sprintf((char *)sid_buf, "%ld_", (long)current_SID);
sprintf((char *)sid_buf, "%ld_", (long)current_sctx.sc_sid);
lead += (int)STRLEN(sid_buf);
}
}
@@ -2454,7 +2455,8 @@ ex_function(exarg_T *eap)
flags |= FC_SANDBOX;
fp->uf_flags = flags;
fp->uf_calls = 0;
fp->uf_script_ID = current_SID;
fp->uf_script_ctx = current_sctx;
fp->uf_script_ctx.sc_lnum += sourcing_lnum - newlines.ga_len - 1;
goto ret_free;
erret:

View File

@@ -794,6 +794,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
362,
/**/
361,
/**/