aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/nvim/api/private/helpers.c8
-rw-r--r--src/nvim/buffer.c8
-rw-r--r--src/nvim/buffer_defs.h30
-rw-r--r--src/nvim/eval.c66
-rw-r--r--src/nvim/eval/typval.h13
-rw-r--r--src/nvim/ex_cmds2.c54
-rw-r--r--src/nvim/ex_cmds_defs.h4
-rw-r--r--src/nvim/ex_docmd.c55
-rw-r--r--src/nvim/ex_getln.c11
-rw-r--r--src/nvim/fileio.c29
-rw-r--r--src/nvim/getchar.c13
-rw-r--r--src/nvim/globals.h8
-rw-r--r--src/nvim/keymap.c8
-rw-r--r--src/nvim/macros.h1
-rw-r--r--src/nvim/main.c23
-rw-r--r--src/nvim/menu.c4
-rw-r--r--src/nvim/option.c64
-rw-r--r--src/nvim/option_defs.h2
-rw-r--r--src/nvim/syntax.c19
-rw-r--r--src/nvim/testdir/test_alot.vim1
-rw-r--r--src/nvim/testdir/test_expand_func.vim66
-rw-r--r--src/nvim/testdir/test_maparg.vim19
22 files changed, 321 insertions, 185 deletions
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index fb3a73ad4a..2056cb07e3 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -391,8 +391,10 @@ void set_option_to(uint64_t channel_id, void *to, int type,
stringval = (char *)value.data.string.data;
}
- const scid_T save_current_SID = current_SID;
- current_SID = channel_id == LUA_INTERNAL_CALL ? SID_LUA : SID_API_CLIENT;
+ const sctx_T save_current_sctx = current_sctx;
+ current_sctx.sc_sid =
+ channel_id == LUA_INTERNAL_CALL ? SID_LUA : SID_API_CLIENT;
+ current_sctx.sc_lnum = 0;
current_channel_id = channel_id;
const int opt_flags = (type == SREQ_WIN && !(flags & SOPT_GLOBAL))
@@ -401,7 +403,7 @@ void set_option_to(uint64_t channel_id, void *to, int type,
set_option_value_for(name.data, numval, stringval,
opt_flags, type, to, err);
- current_SID = save_current_SID;
+ current_sctx = save_current_sctx;
}
#define TYPVAL_ENCODE_ALLOW_SPECIALS false
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index 382b4c45c1..f15205349b 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -5066,7 +5066,6 @@ chk_modeline(
int retval = OK;
char_u *save_sourcing_name;
linenr_T save_sourcing_lnum;
- scid_T save_SID;
prev = -1;
for (s = ml_get(lnum); *s != NUL; s++) {
@@ -5154,15 +5153,16 @@ chk_modeline(
if (*s != NUL) { // skip over an empty "::"
const int secure_save = secure;
- save_SID = current_SID;
- current_SID = SID_MODELINE;
+ const sctx_T save_current_sctx = current_sctx;
+ current_sctx.sc_sid = SID_MODELINE;
+ current_sctx.sc_lnum = 0;
// Make sure no risky things are executed as a side effect.
secure = 1;
retval = do_set(s, OPT_MODELINE | OPT_LOCAL | flags);
secure = secure_save;
- current_SID = save_SID;
+ current_sctx = save_current_sctx;
if (retval == FAIL) { // stop if error found
break;
}
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index 5e700940b0..117e3f42fe 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -255,8 +255,8 @@ typedef struct {
long wo_winbl;
# define w_p_winbl w_onebuf_opt.wo_winbl // 'winblend'
- LastSet wo_scriptID[WV_COUNT]; // SIDs for window-local options
-# define w_p_scriptID w_onebuf_opt.wo_scriptID
+ LastSet wo_script_ctx[WV_COUNT]; // SCTXs for window-local options
+# define w_p_script_ctx w_onebuf_opt.wo_script_ctx
} winopt_T;
/*
@@ -344,17 +344,17 @@ typedef struct {
*/
typedef struct mapblock mapblock_T;
struct mapblock {
- mapblock_T *m_next; /* next mapblock in list */
- char_u *m_keys; /* mapped from, lhs */
- char_u *m_str; /* mapped to, rhs */
- char_u *m_orig_str; /* rhs as entered by the user */
- int m_keylen; /* strlen(m_keys) */
- int m_mode; /* valid mode */
- int m_noremap; /* if non-zero no re-mapping for m_str */
- char m_silent; /* <silent> used, don't echo commands */
- char m_nowait; /* <nowait> used */
- char m_expr; /* <expr> used, m_str is an expression */
- scid_T m_script_ID; /* ID of script where map was defined */
+ mapblock_T *m_next; // next mapblock in list
+ char_u *m_keys; // mapped from, lhs
+ char_u *m_str; // mapped to, rhs
+ char_u *m_orig_str; // rhs as entered by the user
+ int m_keylen; // strlen(m_keys)
+ int m_mode; // valid mode
+ int m_noremap; // if non-zero no re-mapping for m_str
+ char m_silent; // <silent> used, don't echo commands
+ char m_nowait; // <nowait> used
+ char m_expr; // <expr> used, m_str is an expression
+ sctx_T m_script_ctx; // SCTX where map was defined
};
/*
@@ -622,9 +622,9 @@ struct file_buffer {
* They are here because their value depends on the type of file
* or contents of the file being edited.
*/
- bool b_p_initialized; /* set when options initialized */
+ bool b_p_initialized; // set when options initialized
- LastSet b_p_scriptID[BV_COUNT]; // SIDs for buffer-local options
+ LastSet b_p_script_ctx[BV_COUNT]; // SCTXs for buffer-local options
int b_p_ai; ///< 'autoindent'
int b_p_ai_nopaste; ///< b_p_ai saved for paste mode
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index a50474a55a..0625a63e21 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -1815,13 +1815,11 @@ static void list_vim_vars(int *first)
list_hashtable_vars(&vimvarht, "v:", false, first);
}
-/*
- * List script-local variables, if there is a script.
- */
+// List script-local variables, if there is a script.
static void list_script_vars(int *first)
{
- if (current_SID > 0 && current_SID <= ga_scripts.ga_len) {
- list_hashtable_vars(&SCRIPT_VARS(current_SID), "s:", false, first);
+ if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= ga_scripts.ga_len) {
+ list_hashtable_vars(&SCRIPT_VARS(current_sctx.sc_sid), "s:", false, first);
}
}
@@ -5981,7 +5979,8 @@ static int get_lambda_tv(char_u **arg, typval_T *rettv, bool 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;
@@ -6329,11 +6328,11 @@ static char_u *fname_trans_sid(const char_u *const name,
fname_buf[2] = (int)KE_SNR;
int i = 3;
if (eval_fname_sid((const char *)name)) { // "<SID>" or "s:"
- if (current_SID <= 0) {
+ if (current_sctx.sc_sid <= 0) {
*error = ERROR_SCRIPT;
} else {
snprintf((char *)fname_buf + 3, FLEN_FIXED + 1, "%" PRId64 "_",
- (int64_t)current_SID);
+ (int64_t)current_sctx.sc_sid);
i = (int)STRLEN(fname_buf);
}
}
@@ -9433,7 +9432,7 @@ static void common_function(typval_T *argvars, typval_T *rettv,
// would also work, but some plugins depend on the name being
// printable text.
snprintf(sid_buf, sizeof(sid_buf), "<SNR>%" PRId64 "_",
- (int64_t)current_SID);
+ (int64_t)current_sctx.sc_sid);
name = xmalloc(STRLEN(sid_buf) + STRLEN(s + off) + 1);
STRCPY(name, sid_buf);
STRCAT(name, s + off);
@@ -12874,7 +12873,8 @@ void mapblock_fill_dict(dict_T *const dict,
tv_dict_add_nr(dict, S_LEN("noremap"), noremap_value);
tv_dict_add_nr(dict, S_LEN("expr"), mp->m_expr ? 1 : 0);
tv_dict_add_nr(dict, S_LEN("silent"), mp->m_silent ? 1 : 0);
- tv_dict_add_nr(dict, S_LEN("sid"), (varnumber_T)mp->m_script_ID);
+ tv_dict_add_nr(dict, S_LEN("sid"), (varnumber_T)mp->m_script_ctx.sc_sid);
+ tv_dict_add_nr(dict, S_LEN("lnum"), (varnumber_T)mp->m_script_ctx.sc_lnum);
tv_dict_add_nr(dict, S_LEN("buffer"), (varnumber_T)buffer_value);
tv_dict_add_nr(dict, S_LEN("nowait"), mp->m_nowait ? 1 : 0);
tv_dict_add_allocated_str(dict, S_LEN("mode"), mapmode);
@@ -14549,7 +14549,7 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, FunPtr fptr)
ADD(args, vim_to_object(tv));
}
- scid_T save_current_SID;
+ sctx_T save_current_sctx;
uint8_t *save_sourcing_name, *save_autocmd_fname, *save_autocmd_match;
linenr_T save_sourcing_lnum;
int save_autocmd_bufnr;
@@ -14558,7 +14558,7 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (l_provider_call_nesting) {
// If this is called from a provider function, restore the scope
// information of the caller.
- save_current_SID = current_SID;
+ save_current_sctx = current_sctx;
save_sourcing_name = sourcing_name;
save_sourcing_lnum = sourcing_lnum;
save_autocmd_fname = autocmd_fname;
@@ -14566,7 +14566,7 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, FunPtr fptr)
save_autocmd_bufnr = autocmd_bufnr;
save_funccalp = save_funccal();
- current_SID = provider_caller_scope.SID;
+ current_sctx = provider_caller_scope.script_ctx;
sourcing_name = provider_caller_scope.sourcing_name;
sourcing_lnum = provider_caller_scope.sourcing_lnum;
autocmd_fname = provider_caller_scope.autocmd_fname;
@@ -14584,7 +14584,7 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, FunPtr fptr)
Object result = rpc_send_call(chan_id, method, args, &err);
if (l_provider_call_nesting) {
- current_SID = save_current_SID;
+ current_sctx = save_current_sctx;
sourcing_name = save_sourcing_name;
sourcing_lnum = save_sourcing_lnum;
autocmd_fname = save_autocmd_fname;
@@ -20119,7 +20119,7 @@ static dictitem_T *find_var_in_ht(hashtab_T *const ht,
if (varname_len == 0) {
// Must be something like "s:", otherwise "ht" would be NULL.
switch (htname) {
- case 's': return (dictitem_T *)&SCRIPT_SV(current_SID)->sv_var;
+ case 's': return (dictitem_T *)&SCRIPT_SV(current_sctx.sc_sid)->sv_var;
case 'g': return (dictitem_T *)&globvars_var;
case 'v': return (dictitem_T *)&vimvars_var;
case 'b': return (dictitem_T *)&curbuf->b_bufvar;
@@ -20256,8 +20256,9 @@ static hashtab_T *find_var_ht_dict(const char *name, const size_t name_len,
} else if (*name == 'l' && current_funccal != NULL) { // local variable
*d = &get_funccal()->l_vars;
} else if (*name == 's' // script variable
- && current_SID > 0 && current_SID <= ga_scripts.ga_len) {
- *d = &SCRIPT_SV(current_SID)->sv_dict;
+ && current_sctx.sc_sid > 0
+ && current_sctx.sc_sid <= ga_scripts.ga_len) {
+ *d = &SCRIPT_SV(current_sctx.sc_sid)->sv_dict;
}
end:
@@ -21628,7 +21629,8 @@ void ex_function(exarg_T *eap)
}
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:
@@ -21815,12 +21817,12 @@ trans_function_name(
if ((lv.ll_exp_name != NULL && eval_fname_sid(lv.ll_exp_name))
|| eval_fname_sid((const char *)(*pp))) {
// It's "s:" or "<SID>".
- if (current_SID <= 0) {
+ if (current_sctx.sc_sid <= 0) {
EMSG(_(e_usingsid));
goto theend;
}
sid_buf_len = snprintf(sid_buf, sizeof(sid_buf),
- "%" PRIdSCID "_", current_SID);
+ "%" PRIdSCID "_", current_sctx.sc_sid);
lead += sid_buf_len;
}
} else if (!(flags & TFN_INT)
@@ -21937,8 +21939,9 @@ static void list_func_head(ufunc_T *fp, int indent, bool force)
msg_puts(" closure");
}
msg_clr_eos();
- if (p_verbose > 0)
- last_set_msg(fp->uf_script_ID);
+ if (p_verbose > 0) {
+ last_set_msg(fp->uf_script_ctx);
+ }
}
/// Find a function by name, return pointer to it in ufuncs.
@@ -22628,7 +22631,6 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars,
{
char_u *save_sourcing_name;
linenr_T save_sourcing_lnum;
- scid_T save_current_SID;
bool using_sandbox = false;
funccall_T *fc;
int save_did_emsg;
@@ -22882,8 +22884,8 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars,
script_prof_save(&wait_start);
}
- save_current_SID = current_SID;
- current_SID = fp->uf_script_ID;
+ const sctx_T save_current_sctx = current_sctx;
+ current_sctx = fp->uf_script_ctx;
save_did_emsg = did_emsg;
did_emsg = FALSE;
@@ -22957,7 +22959,7 @@ void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars,
xfree(sourcing_name);
sourcing_name = save_sourcing_name;
sourcing_lnum = save_sourcing_lnum;
- current_SID = save_current_SID;
+ current_sctx = save_current_sctx;
if (do_profiling_yes) {
script_prof_restore(&wait_start);
}
@@ -23577,10 +23579,10 @@ int store_session_globals(FILE *fd)
* Display script name where an item was last set.
* Should only be invoked when 'verbose' is non-zero.
*/
-void last_set_msg(scid_T scriptID)
+void last_set_msg(sctx_T script_ctx)
{
const LastSet last_set = (LastSet){
- .script_id = scriptID,
+ .script_ctx = script_ctx,
.channel_id = 0,
};
option_last_set_msg(last_set);
@@ -23591,12 +23593,16 @@ void last_set_msg(scid_T scriptID)
/// Should only be invoked when 'verbose' is non-zero.
void option_last_set_msg(LastSet last_set)
{
- if (last_set.script_id != 0) {
+ if (last_set.script_ctx.sc_sid != 0) {
bool should_free;
char_u *p = get_scriptname(last_set, &should_free);
verbose_enter();
MSG_PUTS(_("\n\tLast set from "));
MSG_PUTS(p);
+ if (last_set.script_ctx.sc_lnum > 0) {
+ MSG_PUTS(_(" line "));
+ msg_outnum((long)last_set.script_ctx.sc_lnum);
+ }
if (should_free) {
xfree(p);
}
@@ -24042,7 +24048,7 @@ typval_T eval_call_provider(char *provider, char *method, list_T *arguments)
// Save caller scope information
struct caller_scope saved_provider_caller_scope = provider_caller_scope;
provider_caller_scope = (struct caller_scope) {
- .SID = current_SID,
+ .script_ctx = current_sctx,
.sourcing_name = sourcing_name,
.sourcing_lnum = sourcing_lnum,
.autocmd_fname = autocmd_fname,
diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h
index 5c0f872b38..c40585443e 100644
--- a/src/nvim/eval/typval.h
+++ b/src/nvim/eval/typval.h
@@ -248,6 +248,17 @@ typedef int scid_T;
/// Format argument for scid_T
#define PRIdSCID "d"
+// 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;
+
// Structure to hold info for a function that is currently being executed.
typedef struct funccall_S funccall_T;
@@ -275,7 +286,7 @@ struct ufunc {
proftime_T uf_tml_wait; ///< start wait time for current line
int uf_tml_idx; ///< index of line being timed; -1 if none
int uf_tml_execed; ///< line being timed was executed
- 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
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index 691ad74100..96f758805b 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -1080,8 +1080,8 @@ void script_prof_save(
{
scriptitem_T *si;
- if (current_SID > 0 && current_SID <= script_items.ga_len) {
- si = &SCRIPT_ITEM(current_SID);
+ if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= script_items.ga_len) {
+ si = &SCRIPT_ITEM(current_sctx.sc_sid);
if (si->sn_prof_on && si->sn_pr_nest++ == 0) {
si->sn_pr_child = profile_start();
}
@@ -1094,8 +1094,8 @@ void script_prof_restore(proftime_T *tm)
{
scriptitem_T *si;
- if (current_SID > 0 && current_SID <= script_items.ga_len) {
- si = &SCRIPT_ITEM(current_SID);
+ if (current_sctx.sc_sid > 0 && current_sctx.sc_sid <= script_items.ga_len) {
+ si = &SCRIPT_ITEM(current_sctx.sc_sid);
if (si->sn_prof_on && --si->sn_pr_nest == 0) {
si->sn_pr_child = profile_end(si->sn_pr_child);
// don't count wait time
@@ -1192,8 +1192,8 @@ static void script_dump_profile(FILE *fd)
/// profiled.
bool 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;
}
@@ -3033,7 +3033,6 @@ int do_source(char_u *fname, int check_other, int is_vimrc)
char_u *fname_exp;
char_u *firstline = NULL;
int retval = FAIL;
- scid_T save_current_SID;
static scid_T last_current_SID = 0;
void *save_funccalp;
int save_debug_break_level = debug_break_level;
@@ -3161,12 +3160,14 @@ int do_source(char_u *fname, int check_other, int is_vimrc)
// Check if this script was sourced before to finds its SID.
// If it's new, generate a new SID.
- save_current_SID = current_SID;
+ const sctx_T save_current_sctx = current_sctx;
+ current_sctx.sc_lnum = 0;
FileID file_id;
bool file_id_ok = os_fileid((char *)fname_exp, &file_id);
assert(script_items.ga_len >= 0);
- for (current_SID = script_items.ga_len; current_SID > 0; current_SID--) {
- si = &SCRIPT_ITEM(current_SID);
+ for (current_sctx.sc_sid = script_items.ga_len; current_sctx.sc_sid > 0;
+ current_sctx.sc_sid--) {
+ si = &SCRIPT_ITEM(current_sctx.sc_sid);
// Compare dev/ino when possible, it catches symbolic links.
// Also compare file names, the inode may change when the file was edited.
bool file_id_equal = file_id_ok && si->file_id_valid
@@ -3176,15 +3177,15 @@ int do_source(char_u *fname, int check_other, int is_vimrc)
break;
}
}
- if (current_SID == 0) {
- current_SID = ++last_current_SID;
- ga_grow(&script_items, (int)(current_SID - script_items.ga_len));
- while (script_items.ga_len < current_SID) {
+ if (current_sctx.sc_sid == 0) {
+ current_sctx.sc_sid = ++last_current_SID;
+ ga_grow(&script_items, (int)(current_sctx.sc_sid - script_items.ga_len));
+ while (script_items.ga_len < current_sctx.sc_sid) {
script_items.ga_len++;
SCRIPT_ITEM(script_items.ga_len).sn_name = NULL;
SCRIPT_ITEM(script_items.ga_len).sn_prof_on = false;
}
- si = &SCRIPT_ITEM(current_SID);
+ si = &SCRIPT_ITEM(current_sctx.sc_sid);
si->sn_name = fname_exp;
fname_exp = vim_strsave(si->sn_name); // used for autocmd
if (file_id_ok) {
@@ -3195,7 +3196,7 @@ int do_source(char_u *fname, int check_other, int is_vimrc)
}
// Allocate the local script variables to use for this script.
- new_script_vars(current_SID);
+ new_script_vars(current_sctx.sc_sid);
}
if (l_do_profiling == PROF_YES) {
@@ -3236,7 +3237,7 @@ int do_source(char_u *fname, int check_other, int is_vimrc)
if (l_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) {
si->sn_pr_start = profile_end(si->sn_pr_start);
si->sn_pr_start = profile_sub_wait(wait_start, si->sn_pr_start);
@@ -3277,7 +3278,7 @@ int do_source(char_u *fname, int check_other, int is_vimrc)
debug_break_level++;
}
- current_SID = save_current_SID;
+ current_sctx = save_current_sctx;
restore_funccal(save_funccalp);
if (l_do_profiling == PROF_YES) {
prof_child_exit(&wait_start); // leaving a child now
@@ -3338,7 +3339,7 @@ char_u *get_scriptname(LastSet last_set, bool *should_free)
{
*should_free = false;
- switch (last_set.script_id) {
+ switch (last_set.script_ctx.sc_sid) {
case SID_MODELINE:
return (char_u *)_("modeline");
case SID_CMDARG:
@@ -3358,7 +3359,8 @@ char_u *get_scriptname(LastSet last_set, bool *should_free)
return IObuff;
default:
*should_free = true;
- return home_replace_save(NULL, SCRIPT_ITEM(last_set.script_id).sn_name);
+ return home_replace_save(NULL,
+ SCRIPT_ITEM(last_set.script_ctx.sc_sid).sn_name);
}
}
@@ -3585,10 +3587,10 @@ void 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
// here isn't counted.
@@ -3616,10 +3618,10 @@ void 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;
}
@@ -3631,10 +3633,10 @@ void 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) {
if (si->sn_prl_execed) {
diff --git a/src/nvim/ex_cmds_defs.h b/src/nvim/ex_cmds_defs.h
index bc7e1e9b59..42ba1060e9 100644
--- a/src/nvim/ex_cmds_defs.h
+++ b/src/nvim/ex_cmds_defs.h
@@ -143,9 +143,9 @@ struct exarg {
struct expand {
int xp_context; // type of expansion
char_u *xp_pattern; // start of item to expand
- size_t xp_pattern_len; // bytes in xp_pattern before cursor
+ size_t xp_pattern_len; // bytes in xp_pattern before cursor
char_u *xp_arg; // completion function
- int xp_scriptID; // SID for completion function
+ sctx_T xp_script_ctx; // SCTX for completion function
int xp_backslash; // one of the XP_BS_ values
#ifndef BACKSLASH_IN_FILENAME
int xp_shell; // TRUE for a shell command, more
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 85ec4efd3a..b1f80d791e 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -84,14 +84,14 @@ static int ex_pressedreturn = FALSE;
static int did_lcd;
typedef struct ucmd {
- char_u *uc_name; /* The command name */
- uint32_t uc_argt; /* The argument type */
- char_u *uc_rep; /* The command's replacement string */
- long uc_def; /* The default value for a range/count */
- int uc_compl; /* completion type */
- int uc_addr_type; /* The command's address type */
- scid_T uc_scriptID; /* SID where the command was defined */
- char_u *uc_compl_arg; /* completion argument if any */
+ char_u *uc_name; // The command name
+ uint32_t uc_argt; // The argument type
+ char_u *uc_rep; // The command's replacement string
+ long uc_def; // The default value for a range/count
+ int uc_compl; // completion type
+ int uc_addr_type; // The command's address type
+ sctx_T uc_script_ctx; // SCTX where the command was defined
+ char_u *uc_compl_arg; // completion argument if any
} ucmd_T;
#define UC_BUFFER 1 /* -buffer: local to current buffer */
@@ -2564,7 +2564,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;
}
/* Do not search for further abbreviations
* if this is an exact match. */
@@ -4879,7 +4880,8 @@ static int uc_add_command(char_u *name, size_t name_len, char_u *rep,
cmd->uc_argt = argt;
cmd->uc_def = def;
cmd->uc_compl = compl;
- cmd->uc_scriptID = current_SID;
+ cmd->uc_script_ctx = current_sctx;
+ cmd->uc_script_ctx.sc_lnum += sourcing_lnum;
cmd->uc_compl_arg = compl_arg;
cmd->uc_addr_type = addr_type;
@@ -5070,9 +5072,10 @@ static void uc_list(char_u *name, size_t name_len)
IObuff[len] = '\0';
msg_outtrans(IObuff);
- msg_outtrans_special(cmd->uc_rep, FALSE);
- if (p_verbose > 0)
- last_set_msg(cmd->uc_scriptID);
+ msg_outtrans_special(cmd->uc_rep, false);
+ if (p_verbose > 0) {
+ last_set_msg(cmd->uc_script_ctx);
+ }
ui_flush();
os_breakcheck();
if (got_int)
@@ -5716,7 +5719,7 @@ static void do_ucmd(exarg_T *eap)
size_t split_len = 0;
char_u *split_buf = NULL;
ucmd_T *cmd;
- scid_T save_current_SID = current_SID;
+ const sctx_T save_current_sctx = current_sctx;
if (eap->cmdidx == CMD_USER)
cmd = USER_CMD(eap->useridx);
@@ -5797,10 +5800,10 @@ static void do_ucmd(exarg_T *eap)
buf = xmalloc(totlen + 1);
}
- current_SID = cmd->uc_scriptID;
+ current_sctx.sc_sid = cmd->uc_script_ctx.sc_sid;
(void)do_cmdline(buf, eap->getline, eap->cookie,
- DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_KEYTYPED);
- current_SID = save_current_SID;
+ DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_KEYTYPED);
+ current_sctx = save_current_sctx;
xfree(buf);
xfree(split_buf);
}
@@ -8538,6 +8541,8 @@ ssize_t find_cmdline_var(const char_u *src, size_t *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)
};
for (size_t i = 0; i < ARRAY_SIZE(spec_str); ++i) {
@@ -8764,7 +8769,8 @@ eval_vars (
return NULL;
}
break;
- case SPEC_SLNUM: /* line in file for ":so" command */
+
+ case SPEC_SLNUM: // line in file for ":so" command
if (sourcing_name == NULL || sourcing_lnum == 0) {
*errormsg = (char_u *)_("E842: no line number to use for \"<slnum>\"");
return NULL;
@@ -8772,6 +8778,17 @@ eval_vars (
snprintf(strbuf, sizeof(strbuf), "%" PRIdLINENR, sourcing_lnum);
result = (char_u *)strbuf;
break;
+
+ 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;
+ }
+ snprintf((char *)strbuf, sizeof(strbuf), "%" PRIdLINENR,
+ current_sctx.sc_lnum + sourcing_lnum);
+ result = (char_u *)strbuf;
+ break;
+
default:
// should not happen
*errormsg = (char_u *)"";
@@ -10193,7 +10210,7 @@ Dictionary commands_array(buf_T *buf)
PUT(d, "name", STRING_OBJ(cstr_to_string((char *)cmd->uc_name)));
PUT(d, "definition", STRING_OBJ(cstr_to_string((char *)cmd->uc_rep)));
- PUT(d, "script_id", INTEGER_OBJ(cmd->uc_scriptID));
+ PUT(d, "script_id", INTEGER_OBJ(cmd->uc_script_ctx.sc_sid));
PUT(d, "bang", BOOLEAN_OBJ(!!(cmd->uc_argt & BANG)));
PUT(d, "bar", BOOLEAN_OBJ(!!(cmd->uc_argt & TRLBAR)));
PUT(d, "register", BOOLEAN_OBJ(!!(cmd->uc_argt & REGSTR)));
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index f00367d9ca..6b4092b5b4 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -1909,7 +1909,7 @@ static int command_line_changed(CommandLineState *s)
redrawcmdline();
s->did_incsearch = true;
} else if (s->firstc == ':'
- && current_SID == 0 // only if interactive
+ && current_sctx.sc_sid == 0 // only if interactive
&& *p_icm != NUL // 'inccommand' is set
&& curbuf->b_p_ma // buffer is modifiable
&& cmdline_star == 0 // not typing a password
@@ -5072,7 +5072,7 @@ static void * call_user_expand_func(user_expand_func_T user_expand_func,
char_u keep = 0;
typval_T args[4];
char_u *pat = NULL;
- int save_current_SID = current_SID;
+ const sctx_T save_current_sctx = current_sctx;
struct cmdline_info save_ccline;
if (xp->xp_arg == NULL || xp->xp_arg[0] == '\0' || xp->xp_line == NULL)
@@ -5098,14 +5098,15 @@ static void * call_user_expand_func(user_expand_func_T user_expand_func,
save_ccline = ccline;
ccline.cmdbuff = NULL;
ccline.cmdprompt = NULL;
- current_SID = xp->xp_scriptID;
+ current_sctx = xp->xp_script_ctx;
void *const ret = user_expand_func(xp->xp_arg, 3, args);
ccline = save_ccline;
- current_SID = save_current_SID;
- if (ccline.cmdbuff != NULL)
+ current_sctx = save_current_sctx;
+ if (ccline.cmdbuff != NULL) {
ccline.cmdbuff[ccline.cmdlen] = keep;
+ }
xfree(pat);
return ret;
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index 8b19257d3d..517325a2cd 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -103,7 +103,7 @@ typedef struct AutoCmd {
bool once; // "One shot": removed after execution
char nested; // If autocommands nest here
char last; // last command in list
- scid_T scriptID; // script ID where defined
+ sctx_T script_ctx; // script context where defined
struct AutoCmd *next; // Next AutoCmd in list
} AutoCmd;
@@ -5422,20 +5422,25 @@ static void show_autocmd(AutoPat *ap, event_T event)
if (ac->cmd == NULL) { /* skip removed commands */
continue;
}
- if (msg_col >= 14)
+ if (msg_col >= 14) {
msg_putchar('\n');
+ }
msg_col = 14;
- if (got_int)
+ if (got_int) {
return;
+ }
msg_outtrans(ac->cmd);
- if (p_verbose > 0)
- last_set_msg(ac->scriptID);
- if (got_int)
+ if (p_verbose > 0) {
+ last_set_msg(ac->script_ctx);
+ }
+ if (got_int) {
return;
+ }
if (ac->next != NULL) {
msg_putchar('\n');
- if (got_int)
+ if (got_int) {
return;
+ }
}
}
}
@@ -6241,7 +6246,8 @@ static int do_autocmd_event(event_T event, char_u *pat, bool once, int nested,
prev_ac = &ac->next;
ac = xmalloc(sizeof(AutoCmd));
ac->cmd = vim_strsave(cmd);
- ac->scriptID = current_SID;
+ ac->script_ctx = current_sctx;
+ ac->script_ctx.sc_lnum += sourcing_lnum;
ac->next = NULL;
*prev_ac = ac;
ac->once = once;
@@ -6675,7 +6681,6 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io,
static int nesting = 0;
AutoPatCmd patcmd;
AutoPat *ap;
- scid_T save_current_SID;
void *save_funccalp;
char_u *save_cmdarg;
long save_cmdbang;
@@ -6860,7 +6865,7 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io,
save_sourcing_lnum = sourcing_lnum;
sourcing_lnum = 0; /* no line number here */
- save_current_SID = current_SID;
+ const sctx_T save_current_sctx = current_sctx;
if (do_profiling == PROF_YES)
prof_child_enter(&wait_time); /* doesn't count for the caller itself */
@@ -6954,7 +6959,7 @@ static bool apply_autocmds_group(event_T event, char_u *fname, char_u *fname_io,
autocmd_fname = save_autocmd_fname;
autocmd_bufnr = save_autocmd_bufnr;
autocmd_match = save_autocmd_match;
- current_SID = save_current_SID;
+ current_sctx = save_current_sctx;
restore_funccal(save_funccalp);
if (do_profiling == PROF_YES)
prof_child_exit(&wait_time);
@@ -7147,7 +7152,7 @@ char_u *getnextac(int c, void *cookie, int indent)
au_del_cmd(ac);
}
autocmd_nested = ac->nested;
- current_SID = ac->scriptID;
+ current_sctx = ac->script_ctx;
if (ac->last) {
acp->nextcmd = NULL;
} else {
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c
index 0ef0c852a4..318b36860e 100644
--- a/src/nvim/getchar.c
+++ b/src/nvim/getchar.c
@@ -2957,7 +2957,8 @@ int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev,
mp->m_silent = args->silent;
mp->m_mode = mode;
mp->m_expr = args->expr;
- mp->m_script_ID = current_SID;
+ mp->m_script_ctx = current_sctx;
+ mp->m_script_ctx.sc_lnum += sourcing_lnum;
did_it = true;
}
}
@@ -3032,7 +3033,8 @@ int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev,
mp->m_silent = args->silent;
mp->m_mode = mode;
mp->m_expr = args->expr;
- mp->m_script_ID = current_SID;
+ mp->m_script_ctx = current_sctx;
+ mp->m_script_ctx.sc_lnum += sourcing_lnum;
// add the new entry in front of the abbrlist or maphash[] list
if (is_abbrev) {
@@ -3375,9 +3377,10 @@ showmap (
msg_outtrans_special(s, FALSE);
xfree(s);
}
- if (p_verbose > 0)
- last_set_msg(mp->m_script_ID);
- ui_flush(); /* show one line at a time */
+ if (p_verbose > 0) {
+ last_set_msg(mp->m_script_ctx);
+ }
+ ui_flush(); // show one line at a time
}
/// Check if a map exists that has given string in the rhs
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index 9a7b5425bf..3eae415719 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -332,8 +332,8 @@ EXTERN int garbage_collect_at_exit INIT(= false);
#define SID_LUA -7 // for Lua scripts/chunks
#define SID_API_CLIENT -8 // for API clients
-// 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 });
// ID of the current channel making a client API call
EXTERN uint64_t current_channel_id INIT(= 0);
@@ -342,8 +342,8 @@ EXTERN bool did_source_packages INIT(= false);
// Scope information for the code that indirectly triggered the current
// provider function call
EXTERN struct caller_scope {
- scid_T SID;
- uint8_t *sourcing_name, *autocmd_fname, *autocmd_match;
+ sctx_T script_ctx;
+ uint8_t *sourcing_name, *autocmd_fname, *autocmd_match;
linenr_T sourcing_lnum;
int autocmd_bufnr;
void *funccalp;
diff --git a/src/nvim/keymap.c b/src/nvim/keymap.c
index eab65f2625..b8b9c945b9 100644
--- a/src/nvim/keymap.c
+++ b/src/nvim/keymap.c
@@ -824,7 +824,8 @@ char_u *replace_termcodes(const char_u *from, const size_t from_len,
// Allocate space for the translation. Worst case a single character is
// replaced by 6 bytes (shifted special key), plus a NUL at the end.
- result = xmalloc(from_len * 6 + 1);
+ const size_t buf_len = from_len * 6 + 1;
+ result = xmalloc(buf_len);
src = from;
@@ -849,14 +850,15 @@ char_u *replace_termcodes(const char_u *from, const size_t from_len,
// Replace <SID> by K_SNR <script-nr> _.
// (room: 5 * 6 = 30 bytes; needed: 3 + <nr> + 1 <= 14)
if (end - src >= 4 && STRNICMP(src, "<SID>", 5) == 0) {
- if (current_SID <= 0) {
+ if (current_sctx.sc_sid <= 0) {
EMSG(_(e_usingsid));
} else {
src += 5;
result[dlen++] = K_SPECIAL;
result[dlen++] = (int)KS_EXTRA;
result[dlen++] = (int)KE_SNR;
- sprintf((char *)result + dlen, "%" PRId64, (int64_t)current_SID);
+ snprintf((char *)result + dlen, buf_len - dlen, "%" PRId64,
+ (int64_t)current_sctx.sc_sid);
dlen += STRLEN(result + dlen);
result[dlen++] = '_';
continue;
diff --git a/src/nvim/macros.h b/src/nvim/macros.h
index 760f690e87..d11507fa6a 100644
--- a/src/nvim/macros.h
+++ b/src/nvim/macros.h
@@ -9,6 +9,7 @@
#else
# ifndef INIT
# define INIT(...) __VA_ARGS__
+# define COMMA ,
# endif
#endif
diff --git a/src/nvim/main.c b/src/nvim/main.c
index e7c45b1a7b..9ea856a0c4 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -1638,11 +1638,12 @@ static void exe_pre_commands(mparm_T *parmp)
if (cnt > 0) {
curwin->w_cursor.lnum = 0; /* just in case.. */
sourcing_name = (char_u *)_("pre-vimrc command line");
- current_SID = SID_CMDARG;
- for (i = 0; i < cnt; ++i)
+ current_sctx.sc_sid = SID_CMDARG;
+ for (i = 0; i < cnt; i++) {
do_cmdline_cmd(cmds[i]);
+ }
sourcing_name = NULL;
- current_SID = 0;
+ current_sctx.sc_sid = 0;
TIME_MSG("--cmd commands");
}
}
@@ -1663,16 +1664,17 @@ static void exe_commands(mparm_T *parmp)
if (parmp->tagname == NULL && curwin->w_cursor.lnum <= 1)
curwin->w_cursor.lnum = 0;
sourcing_name = (char_u *)"command line";
- current_SID = SID_CARG;
- for (i = 0; i < parmp->n_commands; ++i) {
+ current_sctx.sc_sid = SID_CARG;
+ for (i = 0; i < parmp->n_commands; i++) {
do_cmdline_cmd(parmp->commands[i]);
if (parmp->cmds_tofree[i])
xfree(parmp->commands[i]);
}
sourcing_name = NULL;
- current_SID = 0;
- if (curwin->w_cursor.lnum == 0)
+ current_sctx.sc_sid = 0;
+ if (curwin->w_cursor.lnum == 0) {
curwin->w_cursor.lnum = 1;
+ }
if (!exmode_active)
msg_scroll = FALSE;
@@ -1858,12 +1860,13 @@ static int execute_env(char *env)
linenr_T save_sourcing_lnum = sourcing_lnum;
sourcing_name = (char_u *)env;
sourcing_lnum = 0;
- scid_T save_sid = current_SID;
- current_SID = SID_ENV;
+ const sctx_T save_current_sctx = current_sctx;
+ current_sctx.sc_sid = SID_ENV;
+ current_sctx.sc_lnum = 0;
do_cmdline_cmd((char *)initstr);
sourcing_name = save_sourcing_name;
sourcing_lnum = save_sourcing_lnum;
- current_SID = save_sid;
+ current_sctx = save_current_sctx;
return OK;
}
return FAIL;
diff --git a/src/nvim/menu.c b/src/nvim/menu.c
index 368faf7d0b..181efbf3b0 100644
--- a/src/nvim/menu.c
+++ b/src/nvim/menu.c
@@ -1370,7 +1370,7 @@ void ex_emenu(exarg_T *eap)
/* Found the menu, so execute.
* Use the Insert mode entry when returning to Insert mode. */
- if (((State & INSERT) || restart_edit) && !current_SID) {
+ if (((State & INSERT) || restart_edit) && !current_sctx.sc_sid) {
mode = (char_u *)"Insert";
idx = MENU_INDEX_INSERT;
} else if (State & CMDLINE) {
@@ -1431,7 +1431,7 @@ void ex_emenu(exarg_T *eap)
if (menu->strings[idx] != NULL) {
// When executing a script or function execute the commands right now.
// Otherwise put them in the typeahead buffer.
- if (current_SID != 0) {
+ if (current_sctx.sc_sid != 0) {
exec_normal_cmd(menu->strings[idx], menu->noremap[idx],
menu->silent[idx]);
} else {
diff --git a/src/nvim/option.c b/src/nvim/option.c
index ed9128dbbf..07d3561990 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -200,7 +200,7 @@ typedef struct vimoption {
// local option: indirect option index
char_u *def_val[2]; // default values for variable (vi and vim)
LastSet last_set; // script in which the option was last set
-# define SCRIPTID_INIT , 0
+# define SCTX_INIT , { 0, 0 }
} vimoption_T;
#define VI_DEFAULT 0 // def_val[VI_DEFAULT] is Vi default value
@@ -896,7 +896,7 @@ set_option_default(
*flagsp = *flagsp & ~P_INSECURE;
}
- set_option_scriptID_idx(opt_idx, opt_flags, current_SID);
+ set_option_sctx_idx(opt_idx, opt_flags, current_sctx);
}
/*
@@ -1384,10 +1384,10 @@ int do_set(
if (varp == options[opt_idx].var) {
option_last_set_msg(options[opt_idx].last_set);
} else if ((int)options[opt_idx].indir & PV_WIN) {
- option_last_set_msg(curwin->w_p_scriptID[
+ option_last_set_msg(curwin->w_p_script_ctx[
(int)options[opt_idx].indir & PV_MASK]);
} else if ((int)options[opt_idx].indir & PV_BUF) {
- option_last_set_msg(curbuf->b_p_scriptID[
+ option_last_set_msg(curbuf->b_p_script_ctx[
(int)options[opt_idx].indir & PV_MASK]);
}
}
@@ -2359,13 +2359,12 @@ static void redraw_titles(void)
static int shada_idx = -1;
-/*
- * Set a string option to a new value (without checking the effect).
- * The string is copied into allocated memory.
- * if ("opt_idx" == -1) "name" is used, otherwise "opt_idx" is used.
- * When "set_sid" is zero set the scriptID to current_SID. When "set_sid" is
- * SID_NONE don't set the scriptID. Otherwise set the scriptID to "set_sid".
- */
+// Set a string option to a new value (without checking the effect).
+// The string is copied into allocated memory.
+// if ("opt_idx" == -1) "name" is used, otherwise "opt_idx" is used.
+// When "set_sid" is zero set the scriptID to current_sctx.sc_sid. When
+// "set_sid" is SID_NONE don't set the scriptID. Otherwise set the scriptID to
+// "set_sid".
void
set_string_option_direct(
char_u *name,
@@ -2417,9 +2416,17 @@ set_string_option_direct(
free_string_option(*varp);
*varp = empty_option;
}
- if (set_sid != SID_NONE)
- set_option_scriptID_idx(idx, opt_flags,
- set_sid == 0 ? current_SID : set_sid);
+ if (set_sid != SID_NONE) {
+ sctx_T script_ctx;
+
+ if (set_sid == 0) {
+ script_ctx = current_sctx;
+ } else {
+ script_ctx.sc_sid = set_sid;
+ script_ctx.sc_lnum = 0;
+ }
+ set_option_sctx_idx(idx, opt_flags, script_ctx);
+ }
}
}
@@ -3296,12 +3303,10 @@ ambw_end:
}
} else {
// Remember where the option was set.
- set_option_scriptID_idx(opt_idx, opt_flags, current_SID);
- /*
- * Free string options that are in allocated memory.
- * Use "free_oldval", because recursiveness may change the flags under
- * our fingers (esp. init_highlight()).
- */
+ set_option_sctx_idx(opt_idx, opt_flags, current_sctx);
+ // Free string options that are in allocated memory.
+ // Use "free_oldval", because recursiveness may change the flags under
+ // our fingers (esp. init_highlight()).
if (free_oldval) {
free_string_option(oldval);
}
@@ -3786,15 +3791,14 @@ static bool parse_winhl_opt(win_T *wp)
return true;
}
-/*
- * Set the scriptID for an option, taking care of setting the buffer- or
- * window-local value.
- */
-static void set_option_scriptID_idx(int opt_idx, int opt_flags, int id)
+// Set the script_ctx for an option, taking care of setting the buffer- or
+// window-local value.
+static void set_option_sctx_idx(int opt_idx, int opt_flags, sctx_T script_ctx)
{
int both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0;
int indir = (int)options[opt_idx].indir;
- const LastSet last_set = { id, current_channel_id };
+ const LastSet last_set = { .script_ctx =
+ { script_ctx.sc_sid, sourcing_lnum }, current_channel_id };
// Remember where the option was set. For local options need to do that
// in the buffer or window structure.
@@ -3803,9 +3807,9 @@ static void set_option_scriptID_idx(int opt_idx, int opt_flags, int id)
}
if (both || (opt_flags & OPT_LOCAL)) {
if (indir & PV_BUF) {
- curbuf->b_p_scriptID[indir & PV_MASK] = last_set;
+ curbuf->b_p_script_ctx[indir & PV_MASK] = last_set;
} else if (indir & PV_WIN) {
- curwin->w_p_scriptID[indir & PV_MASK] = last_set;
+ curwin->w_p_script_ctx[indir & PV_MASK] = last_set;
}
}
}
@@ -3832,7 +3836,7 @@ static char *set_bool_option(const int opt_idx, char_u *const varp,
*(int *)varp = value; // set the new value
// Remember where the option was set.
- set_option_scriptID_idx(opt_idx, opt_flags, current_SID);
+ set_option_sctx_idx(opt_idx, opt_flags, current_sctx);
// May set global value for local option.
@@ -4310,7 +4314,7 @@ static char *set_num_option(int opt_idx, char_u *varp, long value,
*pp = value;
// Remember where the option was set.
- set_option_scriptID_idx(opt_idx, opt_flags, current_SID);
+ set_option_sctx_idx(opt_idx, opt_flags, current_sctx);
// For these options we want to fix some invalid values.
if (pp == &p_window) {
diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h
index f9cddf5550..3aa2f47907 100644
--- a/src/nvim/option_defs.h
+++ b/src/nvim/option_defs.h
@@ -837,7 +837,7 @@ enum {
/// Stores an identifier of a script or channel that last set an option.
typedef struct {
- scid_T script_id; /// Script ID or one of SID_* special values.
+ sctx_T script_ctx; /// script context where the option was last set
uint64_t channel_id; /// Only used when script_id is SID_API_CLIENT.
} LastSet;
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index 4b9e84745a..f7de5f00d0 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -60,7 +60,7 @@ struct hl_group {
int sg_attr; ///< Screen attr @see ATTR_ENTRY
int sg_link; ///< link to this highlight group ID
int sg_set; ///< combination of flags in \ref SG_SET
- 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
// for terminal UIs
int sg_cterm; ///< "cterm=" highlighting attr
///< (combination of \ref HlAttrFlags)
@@ -6565,13 +6565,15 @@ void do_highlight(const char *line, const bool forceit, const bool init)
EMSG(_("E414: group has settings, highlight link ignored"));
}
} else if (HL_TABLE()[from_id - 1].sg_link != to_id
- || HL_TABLE()[from_id - 1].sg_scriptID != current_SID
+ || HL_TABLE()[from_id - 1].sg_script_ctx.sc_sid
+ != current_sctx.sc_sid
|| HL_TABLE()[from_id - 1].sg_cleared) {
if (!init) {
HL_TABLE()[from_id - 1].sg_set |= SG_LINK;
}
HL_TABLE()[from_id - 1].sg_link = to_id;
- 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;
HL_TABLE()[from_id - 1].sg_cleared = false;
redraw_all_later(SOME_VALID);
@@ -6950,7 +6952,8 @@ void do_highlight(const char *line, const bool forceit, const bool init)
} else {
set_hl_attr(idx);
}
- 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;
}
xfree(key);
xfree(arg);
@@ -7034,7 +7037,8 @@ static void 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;
}
}
@@ -7084,8 +7088,9 @@ static void highlight_list_one(const int id)
if (!didh)
highlight_list_arg(id, didh, LIST_STRING, 0, (char_u *)"cleared", "");
- if (p_verbose > 0)
- last_set_msg(sgp->sg_scriptID);
+ if (p_verbose > 0) {
+ last_set_msg(sgp->sg_script_ctx);
+ }
}
/// Outputs a highlight when doing ":hi MyHighlight"
diff --git a/src/nvim/testdir/test_alot.vim b/src/nvim/testdir/test_alot.vim
index 30e29bd05d..6bf2e8329c 100644
--- a/src/nvim/testdir/test_alot.vim
+++ b/src/nvim/testdir/test_alot.vim
@@ -11,6 +11,7 @@ source test_ex_equal.vim
source test_ex_undo.vim
source test_ex_z.vim
source test_execute_func.vim
+source test_expand_func.vim
source test_expr.vim
source test_feedkeys.vim
source test_filter_cmd.vim
diff --git a/src/nvim/testdir/test_expand_func.vim b/src/nvim/testdir/test_expand_func.vim
new file mode 100644
index 0000000000..fb29c3eb7a
--- /dev/null
+++ b/src/nvim/testdir/test_expand_func.vim
@@ -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
diff --git a/src/nvim/testdir/test_maparg.vim b/src/nvim/testdir/test_maparg.vim
index 6324e39eec..0b941d51ec 100644
--- a/src/nvim/testdir/test_maparg.vim
+++ b/src/nvim/testdir/test_maparg.vim
@@ -10,23 +10,30 @@ 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))
+ let lnum = expand('<sflnum>')
tmap baz foo
call assert_equal({'silent': 0, 'noremap': 0, 'lhs': 'baz', 'mode': 't',
- \ 'nowait': 0, 'expr': 0, 'sid': sid, 'rhs': 'foo', 'buffer': 0},
+ \ 'nowait': 0, 'expr': 0, 'sid': sid, 'lnum': lnum + 1, 'rhs': 'foo',
+ \ 'buffer': 0},
\ maparg('baz', 't', 0, 1))
map abc x<char-114>x