diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/api/private/helpers.c | 8 | ||||
-rw-r--r-- | src/nvim/buffer.c | 8 | ||||
-rw-r--r-- | src/nvim/buffer_defs.h | 30 | ||||
-rw-r--r-- | src/nvim/eval.c | 66 | ||||
-rw-r--r-- | src/nvim/eval/typval.h | 13 | ||||
-rw-r--r-- | src/nvim/ex_cmds2.c | 54 | ||||
-rw-r--r-- | src/nvim/ex_cmds_defs.h | 4 | ||||
-rw-r--r-- | src/nvim/ex_docmd.c | 55 | ||||
-rw-r--r-- | src/nvim/ex_getln.c | 11 | ||||
-rw-r--r-- | src/nvim/fileio.c | 29 | ||||
-rw-r--r-- | src/nvim/getchar.c | 13 | ||||
-rw-r--r-- | src/nvim/globals.h | 8 | ||||
-rw-r--r-- | src/nvim/keymap.c | 8 | ||||
-rw-r--r-- | src/nvim/macros.h | 1 | ||||
-rw-r--r-- | src/nvim/main.c | 23 | ||||
-rw-r--r-- | src/nvim/menu.c | 4 | ||||
-rw-r--r-- | src/nvim/option.c | 64 | ||||
-rw-r--r-- | src/nvim/option_defs.h | 2 | ||||
-rw-r--r-- | src/nvim/syntax.c | 19 | ||||
-rw-r--r-- | src/nvim/testdir/test_alot.vim | 1 | ||||
-rw-r--r-- | src/nvim/testdir/test_expand_func.vim | 66 | ||||
-rw-r--r-- | src/nvim/testdir/test_maparg.vim | 19 |
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 |