mirror of
https://github.com/neovim/neovim.git
synced 2025-09-06 19:38:20 +00:00
fix(api): don't override Vimscript SID (#32610)
Problem: When calling an API from Vimscript to set an option, mapping, etc., :verbose shows that it's set from an API client. Solution: Don't override current_sctx.sc_sid when calling an API from Vimscript. Also fix the inverse case where API channel id is not set when calling an API from RPC. Move channel id into sctx_T to make saving and restoring easier. Related #8329
This commit is contained in:
@@ -1049,32 +1049,18 @@ const char *get_default_stl_hl(win_T *wp, bool use_winbar, int stc_hl_id)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int find_sid(uint64_t channel_id)
|
|
||||||
{
|
|
||||||
switch (channel_id) {
|
|
||||||
case VIML_INTERNAL_CALL:
|
|
||||||
// TODO(autocmd): Figure out what this should be
|
|
||||||
// return SID_API_CLIENT;
|
|
||||||
case LUA_INTERNAL_CALL:
|
|
||||||
return SID_LUA;
|
|
||||||
default:
|
|
||||||
return SID_API_CLIENT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets sctx for API calls.
|
/// Sets sctx for API calls.
|
||||||
///
|
///
|
||||||
/// @param channel_id api clients id. Used to determine if it's a internal
|
/// @param channel_id api client id to determine if it's a internal or RPC call.
|
||||||
/// call or a rpc call.
|
///
|
||||||
/// @return returns previous value of current_sctx. To be used
|
/// @return previous value of current_sctx. To be used later for restoring sctx.
|
||||||
/// to be used for restoring sctx to previous state.
|
|
||||||
sctx_T api_set_sctx(uint64_t channel_id)
|
sctx_T api_set_sctx(uint64_t channel_id)
|
||||||
{
|
{
|
||||||
sctx_T old_current_sctx = current_sctx;
|
sctx_T old_current_sctx = current_sctx;
|
||||||
if (channel_id != VIML_INTERNAL_CALL) {
|
if (channel_id != VIML_INTERNAL_CALL) {
|
||||||
current_sctx.sc_sid =
|
current_sctx.sc_sid = channel_id == LUA_INTERNAL_CALL ? SID_LUA : SID_API_CLIENT;
|
||||||
channel_id == LUA_INTERNAL_CALL ? SID_LUA : SID_API_CLIENT;
|
|
||||||
current_sctx.sc_lnum = 0;
|
current_sctx.sc_lnum = 0;
|
||||||
|
current_sctx.sc_chan = channel_id;
|
||||||
}
|
}
|
||||||
return old_current_sctx;
|
return old_current_sctx;
|
||||||
}
|
}
|
||||||
|
@@ -186,13 +186,7 @@ typedef struct {
|
|||||||
|
|
||||||
#define WITH_SCRIPT_CONTEXT(channel_id, code) \
|
#define WITH_SCRIPT_CONTEXT(channel_id, code) \
|
||||||
do { \
|
do { \
|
||||||
const sctx_T save_current_sctx = current_sctx; \
|
const sctx_T save_current_sctx = api_set_sctx(channel_id); \
|
||||||
const uint64_t save_channel_id = current_channel_id; \
|
|
||||||
current_sctx.sc_sid = \
|
|
||||||
(channel_id) == LUA_INTERNAL_CALL ? SID_LUA : SID_API_CLIENT; \
|
|
||||||
current_sctx.sc_lnum = 0; \
|
|
||||||
current_channel_id = channel_id; \
|
|
||||||
code; \
|
code; \
|
||||||
current_channel_id = save_channel_id; \
|
|
||||||
current_sctx = save_current_sctx; \
|
current_sctx = save_current_sctx; \
|
||||||
} while (0);
|
} while (0);
|
||||||
|
@@ -208,7 +208,7 @@ typedef struct {
|
|||||||
OptInt wo_winbl;
|
OptInt wo_winbl;
|
||||||
#define w_p_winbl w_onebuf_opt.wo_winbl // 'winblend'
|
#define w_p_winbl w_onebuf_opt.wo_winbl // 'winblend'
|
||||||
|
|
||||||
LastSet wo_script_ctx[kWinOptCount]; // SCTXs for window-local options
|
sctx_T wo_script_ctx[kWinOptCount]; // SCTXs for window-local options
|
||||||
#define w_p_script_ctx w_onebuf_opt.wo_script_ctx
|
#define w_p_script_ctx w_onebuf_opt.wo_script_ctx
|
||||||
} winopt_T;
|
} winopt_T;
|
||||||
|
|
||||||
@@ -510,7 +510,7 @@ struct file_buffer {
|
|||||||
// or contents of the file being edited.
|
// 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_script_ctx[kBufOptCount]; // SCTXs for buffer-local options
|
sctx_T b_p_script_ctx[kBufOptCount]; // SCTXs for buffer-local options
|
||||||
|
|
||||||
int b_p_ai; ///< 'autoindent'
|
int b_p_ai; ///< 'autoindent'
|
||||||
int b_p_ai_nopaste; ///< b_p_ai saved for paste mode
|
int b_p_ai_nopaste; ///< b_p_ai saved for paste mode
|
||||||
|
@@ -1368,7 +1368,7 @@ int eval_foldexpr(win_T *wp, int *cp)
|
|||||||
const bool use_sandbox = was_set_insecurely(wp, kOptFoldexpr, OPT_LOCAL);
|
const bool use_sandbox = was_set_insecurely(wp, kOptFoldexpr, OPT_LOCAL);
|
||||||
|
|
||||||
char *arg = skipwhite(wp->w_p_fde);
|
char *arg = skipwhite(wp->w_p_fde);
|
||||||
current_sctx = wp->w_p_script_ctx[kWinOptFoldexpr].script_ctx;
|
current_sctx = wp->w_p_script_ctx[kWinOptFoldexpr];
|
||||||
|
|
||||||
emsg_off++;
|
emsg_off++;
|
||||||
if (use_sandbox) {
|
if (use_sandbox) {
|
||||||
@@ -7655,14 +7655,10 @@ hashtab_T *find_var_ht_dict(const char *name, const size_t name_len, const char
|
|||||||
// for behavioral consistency. With this different anonymous exec from
|
// for behavioral consistency. With this different anonymous exec from
|
||||||
// same file can't access each others script local stuff. We need to do
|
// same file can't access each others script local stuff. We need to do
|
||||||
// this all other cases except this will act like that otherwise.
|
// this all other cases except this will act like that otherwise.
|
||||||
const LastSet last_set = (LastSet){
|
|
||||||
.script_ctx = current_sctx,
|
|
||||||
.channel_id = LUA_INTERNAL_CALL,
|
|
||||||
};
|
|
||||||
bool should_free;
|
bool should_free;
|
||||||
// should_free is ignored as script_ctx will be resolved to a fname
|
// should_free is ignored as script_ctx will be resolved to a fname
|
||||||
// and new_script_item() will consume it.
|
// and new_script_item() will consume it.
|
||||||
char *sc_name = get_scriptname(last_set, &should_free);
|
char *sc_name = get_scriptname(current_sctx, &should_free);
|
||||||
new_script_item(sc_name, ¤t_sctx.sc_sid);
|
new_script_item(sc_name, ¤t_sctx.sc_sid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8043,31 +8039,19 @@ void var_set_global(const char *const name, typval_T vartv)
|
|||||||
/// Should only be invoked when 'verbose' is non-zero.
|
/// Should only be invoked when 'verbose' is non-zero.
|
||||||
void last_set_msg(sctx_T script_ctx)
|
void last_set_msg(sctx_T script_ctx)
|
||||||
{
|
{
|
||||||
const LastSet last_set = (LastSet){
|
if (script_ctx.sc_sid == 0) {
|
||||||
.script_ctx = script_ctx,
|
|
||||||
.channel_id = 0,
|
|
||||||
};
|
|
||||||
option_last_set_msg(last_set);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Displays where an option was last set.
|
|
||||||
///
|
|
||||||
/// Should only be invoked when 'verbose' is non-zero.
|
|
||||||
void option_last_set_msg(LastSet last_set)
|
|
||||||
{
|
|
||||||
if (last_set.script_ctx.sc_sid == 0) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool should_free;
|
bool should_free;
|
||||||
char *p = get_scriptname(last_set, &should_free);
|
char *p = get_scriptname(script_ctx, &should_free);
|
||||||
|
|
||||||
verbose_enter();
|
verbose_enter();
|
||||||
msg_puts(_("\n\tLast set from "));
|
msg_puts(_("\n\tLast set from "));
|
||||||
msg_puts(p);
|
msg_puts(p);
|
||||||
if (last_set.script_ctx.sc_lnum > 0) {
|
if (script_ctx.sc_lnum > 0) {
|
||||||
msg_puts(_(line_msg));
|
msg_puts(_(line_msg));
|
||||||
msg_outnum(last_set.script_ctx.sc_lnum);
|
msg_outnum(script_ctx.sc_lnum);
|
||||||
}
|
}
|
||||||
if (should_free) {
|
if (should_free) {
|
||||||
xfree(p);
|
xfree(p);
|
||||||
|
@@ -286,14 +286,9 @@ typedef struct {
|
|||||||
scid_T sc_sid; ///< script ID
|
scid_T sc_sid; ///< script ID
|
||||||
int sc_seq; ///< sourcing sequence number
|
int sc_seq; ///< sourcing sequence number
|
||||||
linenr_T sc_lnum; ///< line number
|
linenr_T sc_lnum; ///< line number
|
||||||
|
uint64_t sc_chan; ///< Only used when sc_sid is SID_API_CLIENT.
|
||||||
} sctx_T;
|
} sctx_T;
|
||||||
|
|
||||||
/// Stores an identifier of a script or channel that last set an option.
|
|
||||||
typedef struct {
|
|
||||||
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;
|
|
||||||
|
|
||||||
enum { MAX_FUNC_ARGS = 20, }; ///< Maximum number of function arguments
|
enum { MAX_FUNC_ARGS = 20, }; ///< Maximum number of function arguments
|
||||||
enum { VAR_SHORT_LEN = 20, }; ///< Short variable name length
|
enum { VAR_SHORT_LEN = 20, }; ///< Short variable name length
|
||||||
enum { FIXVAR_CNT = 12, }; ///< Number of fixed variables used for arguments
|
enum { FIXVAR_CNT = 12, }; ///< Number of fixed variables used for arguments
|
||||||
|
@@ -1747,7 +1747,7 @@ static char *eval_includeexpr(const char *const ptr, const size_t len)
|
|||||||
{
|
{
|
||||||
const sctx_T save_sctx = current_sctx;
|
const sctx_T save_sctx = current_sctx;
|
||||||
set_vim_var_string(VV_FNAME, ptr, (ptrdiff_t)len);
|
set_vim_var_string(VV_FNAME, ptr, (ptrdiff_t)len);
|
||||||
current_sctx = curbuf->b_p_script_ctx[kBufOptIncludeexpr].script_ctx;
|
current_sctx = curbuf->b_p_script_ctx[kBufOptIncludeexpr];
|
||||||
|
|
||||||
char *res = eval_to_string_safe(curbuf->b_p_inex,
|
char *res = eval_to_string_safe(curbuf->b_p_inex,
|
||||||
was_set_insecurely(curwin, kOptIncludeexpr, OPT_LOCAL),
|
was_set_insecurely(curwin, kOptIncludeexpr, OPT_LOCAL),
|
||||||
|
@@ -1731,7 +1731,7 @@ char *get_foldtext(win_T *wp, linenr_T lnum, linenr_T lnume, foldinfo_T foldinfo
|
|||||||
|
|
||||||
curwin = wp;
|
curwin = wp;
|
||||||
curbuf = wp->w_buffer;
|
curbuf = wp->w_buffer;
|
||||||
current_sctx = wp->w_p_script_ctx[kWinOptFoldtext].script_ctx;
|
current_sctx = wp->w_p_script_ctx[kWinOptFoldtext];
|
||||||
|
|
||||||
emsg_off++; // handle exceptions, but don't display errors
|
emsg_off++; // handle exceptions, but don't display errors
|
||||||
|
|
||||||
|
@@ -298,9 +298,7 @@ EXTERN bool garbage_collect_at_exit INIT( = false);
|
|||||||
#define SID_STR (-10) // for sourcing a string with no script item
|
#define SID_STR (-10) // for sourcing a string with no script item
|
||||||
|
|
||||||
// Script CTX being sourced or was sourced to define the current function.
|
// Script CTX being sourced or was sourced to define the current function.
|
||||||
EXTERN sctx_T current_sctx INIT( = { 0, 0, 0 });
|
EXTERN sctx_T current_sctx INIT( = { 0, 0, 0, 0 });
|
||||||
// ID of the current channel making a client API call
|
|
||||||
EXTERN uint64_t current_channel_id INIT( = 0);
|
|
||||||
/// Last channel that invoked 'nvim_input` or got FocusGained.
|
/// Last channel that invoked 'nvim_input` or got FocusGained.
|
||||||
EXTERN uint64_t current_ui INIT( = 0);
|
EXTERN uint64_t current_ui INIT( = 0);
|
||||||
|
|
||||||
|
@@ -1181,7 +1181,7 @@ int get_expr_indent(void)
|
|||||||
sandbox++;
|
sandbox++;
|
||||||
}
|
}
|
||||||
textlock++;
|
textlock++;
|
||||||
current_sctx = curbuf->b_p_script_ctx[kBufOptIndentexpr].script_ctx;
|
current_sctx = curbuf->b_p_script_ctx[kBufOptIndentexpr];
|
||||||
|
|
||||||
// Need to make a copy, the 'indentexpr' option could be changed while
|
// Need to make a copy, the 'indentexpr' option could be changed while
|
||||||
// evaluating it.
|
// evaluating it.
|
||||||
|
@@ -1286,11 +1286,11 @@ static void do_one_set_option(int opt_flags, char **argp, bool *did_show, char *
|
|||||||
if (p_verbose > 0) {
|
if (p_verbose > 0) {
|
||||||
// Mention where the option was last set.
|
// Mention where the option was last set.
|
||||||
if (varp == options[opt_idx].var) {
|
if (varp == options[opt_idx].var) {
|
||||||
option_last_set_msg(options[opt_idx].last_set);
|
last_set_msg(options[opt_idx].script_ctx);
|
||||||
} else if (option_has_scope(opt_idx, kOptScopeWin)) {
|
} else if (option_has_scope(opt_idx, kOptScopeWin)) {
|
||||||
option_last_set_msg(curwin->w_p_script_ctx[option_scope_idx(opt_idx, kOptScopeWin)]);
|
last_set_msg(curwin->w_p_script_ctx[option_scope_idx(opt_idx, kOptScopeWin)]);
|
||||||
} else if (option_has_scope(opt_idx, kOptScopeBuf)) {
|
} else if (option_has_scope(opt_idx, kOptScopeBuf)) {
|
||||||
option_last_set_msg(curbuf->b_p_script_ctx[option_scope_idx(opt_idx, kOptScopeBuf)]);
|
last_set_msg(curbuf->b_p_script_ctx[option_scope_idx(opt_idx, kOptScopeBuf)]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1805,7 +1805,7 @@ bool parse_winhl_opt(const char *winhl, win_T *wp)
|
|||||||
sctx_T *get_option_sctx(OptIndex opt_idx)
|
sctx_T *get_option_sctx(OptIndex opt_idx)
|
||||||
{
|
{
|
||||||
assert(opt_idx != kOptInvalid);
|
assert(opt_idx != kOptInvalid);
|
||||||
return &options[opt_idx].last_set.script_ctx;
|
return &options[opt_idx].script_ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the script_ctx for an option, taking care of setting the buffer- or
|
/// Set the script_ctx for an option, taking care of setting the buffer- or
|
||||||
@@ -1814,29 +1814,25 @@ void set_option_sctx(OptIndex opt_idx, int opt_flags, sctx_T script_ctx)
|
|||||||
{
|
{
|
||||||
bool both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0;
|
bool both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0;
|
||||||
nlua_set_sctx(&script_ctx);
|
nlua_set_sctx(&script_ctx);
|
||||||
LastSet last_set = {
|
|
||||||
.script_ctx = script_ctx,
|
|
||||||
.channel_id = current_channel_id,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Modeline already has the line number set.
|
// Modeline already has the line number set.
|
||||||
if (!(opt_flags & OPT_MODELINE)) {
|
if (!(opt_flags & OPT_MODELINE)) {
|
||||||
last_set.script_ctx.sc_lnum += SOURCING_LNUM;
|
script_ctx.sc_lnum += SOURCING_LNUM;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remember where the option was set. For local options need to do that
|
// Remember where the option was set. For local options need to do that
|
||||||
// in the buffer or window structure.
|
// in the buffer or window structure.
|
||||||
if (both || (opt_flags & OPT_GLOBAL) || option_is_global_only(opt_idx)) {
|
if (both || (opt_flags & OPT_GLOBAL) || option_is_global_only(opt_idx)) {
|
||||||
options[opt_idx].last_set = last_set;
|
options[opt_idx].script_ctx = script_ctx;
|
||||||
}
|
}
|
||||||
if (both || (opt_flags & OPT_LOCAL)) {
|
if (both || (opt_flags & OPT_LOCAL)) {
|
||||||
if (option_has_scope(opt_idx, kOptScopeBuf)) {
|
if (option_has_scope(opt_idx, kOptScopeBuf)) {
|
||||||
curbuf->b_p_script_ctx[option_scope_idx(opt_idx, kOptScopeBuf)] = last_set;
|
curbuf->b_p_script_ctx[option_scope_idx(opt_idx, kOptScopeBuf)] = script_ctx;
|
||||||
} else if ((option_has_scope(opt_idx, kOptScopeWin))) {
|
} else if ((option_has_scope(opt_idx, kOptScopeWin))) {
|
||||||
curwin->w_p_script_ctx[option_scope_idx(opt_idx, kOptScopeWin)] = last_set;
|
curwin->w_p_script_ctx[option_scope_idx(opt_idx, kOptScopeWin)] = script_ctx;
|
||||||
if (both) {
|
if (both) {
|
||||||
// also setting the "all buffers" value
|
// also setting the "all buffers" value
|
||||||
curwin->w_allbuf_opt.wo_script_ctx[option_scope_idx(opt_idx, kOptScopeWin)] = last_set;
|
curwin->w_allbuf_opt.wo_script_ctx[option_scope_idx(opt_idx, kOptScopeWin)] = script_ctx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4987,7 +4983,7 @@ void didset_window_options(win_T *wp, bool valid_cursor)
|
|||||||
wp->w_grid_alloc.blending = wp->w_p_winbl > 0;
|
wp->w_grid_alloc.blending = wp->w_p_winbl > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define COPY_OPT_SCTX(buf, bv) buf->b_p_script_ctx[bv] = options[buf_opt_idx[bv]].last_set
|
#define COPY_OPT_SCTX(buf, bv) buf->b_p_script_ctx[bv] = options[buf_opt_idx[bv]].script_ctx
|
||||||
|
|
||||||
/// Copy global option values to local options for one buffer.
|
/// Copy global option values to local options for one buffer.
|
||||||
/// Used when creating a new buffer and sometimes when entering a buffer.
|
/// Used when creating a new buffer and sometimes when entering a buffer.
|
||||||
@@ -6349,25 +6345,25 @@ static Dict vimoption2dict(vimoption_T *opt, int opt_flags, buf_T *buf, win_T *w
|
|||||||
|
|
||||||
PUT_C(dict, "was_set", BOOLEAN_OBJ(opt->flags & kOptFlagWasSet));
|
PUT_C(dict, "was_set", BOOLEAN_OBJ(opt->flags & kOptFlagWasSet));
|
||||||
|
|
||||||
LastSet last_set = { .channel_id = 0 };
|
sctx_T script_ctx = { .sc_sid = 0 };
|
||||||
if (opt_flags == OPT_GLOBAL) {
|
if (opt_flags == OPT_GLOBAL) {
|
||||||
last_set = opt->last_set;
|
script_ctx = opt->script_ctx;
|
||||||
} else {
|
} else {
|
||||||
// Scope is either OPT_LOCAL or a fallback mode was requested.
|
// Scope is either OPT_LOCAL or a fallback mode was requested.
|
||||||
if (option_has_scope(opt_idx, kOptScopeBuf)) {
|
if (option_has_scope(opt_idx, kOptScopeBuf)) {
|
||||||
last_set = buf->b_p_script_ctx[opt->scope_idx[kOptScopeBuf]];
|
script_ctx = buf->b_p_script_ctx[opt->scope_idx[kOptScopeBuf]];
|
||||||
}
|
}
|
||||||
if (option_has_scope(opt_idx, kOptScopeWin)) {
|
if (option_has_scope(opt_idx, kOptScopeWin)) {
|
||||||
last_set = win->w_p_script_ctx[opt->scope_idx[kOptScopeWin]];
|
script_ctx = win->w_p_script_ctx[opt->scope_idx[kOptScopeWin]];
|
||||||
}
|
}
|
||||||
if (opt_flags != OPT_LOCAL && last_set.script_ctx.sc_sid == 0) {
|
if (opt_flags != OPT_LOCAL && script_ctx.sc_sid == 0) {
|
||||||
last_set = opt->last_set;
|
script_ctx = opt->script_ctx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PUT_C(dict, "last_set_sid", INTEGER_OBJ(last_set.script_ctx.sc_sid));
|
PUT_C(dict, "last_set_sid", INTEGER_OBJ(script_ctx.sc_sid));
|
||||||
PUT_C(dict, "last_set_linenr", INTEGER_OBJ(last_set.script_ctx.sc_lnum));
|
PUT_C(dict, "last_set_linenr", INTEGER_OBJ(script_ctx.sc_lnum));
|
||||||
PUT_C(dict, "last_set_chan", INTEGER_OBJ((int64_t)last_set.channel_id));
|
PUT_C(dict, "last_set_chan", INTEGER_OBJ((int64_t)script_ctx.sc_chan));
|
||||||
|
|
||||||
PUT_C(dict, "type", CSTR_AS_OBJ(optval_type_get_name(option_get_type(get_opt_idx(opt)))));
|
PUT_C(dict, "type", CSTR_AS_OBJ(optval_type_get_name(option_get_type(get_opt_idx(opt)))));
|
||||||
PUT_C(dict, "default", optval_as_object(opt->def_val));
|
PUT_C(dict, "default", optval_as_object(opt->def_val));
|
||||||
|
@@ -191,5 +191,5 @@ typedef struct {
|
|||||||
opt_expand_cb_T opt_expand_cb;
|
opt_expand_cb_T opt_expand_cb;
|
||||||
|
|
||||||
OptVal def_val; ///< default value
|
OptVal def_val; ///< default value
|
||||||
LastSet last_set; ///< script in which the option was last set
|
sctx_T script_ctx; ///< script in which the option was last set
|
||||||
} vimoption_T;
|
} vimoption_T;
|
||||||
|
@@ -616,11 +616,7 @@ static void func_dump_profile(FILE *fd)
|
|||||||
}
|
}
|
||||||
if (fp->uf_script_ctx.sc_sid != 0) {
|
if (fp->uf_script_ctx.sc_sid != 0) {
|
||||||
bool should_free;
|
bool should_free;
|
||||||
const LastSet last_set = (LastSet){
|
char *p = get_scriptname(fp->uf_script_ctx, &should_free);
|
||||||
.script_ctx = fp->uf_script_ctx,
|
|
||||||
.channel_id = 0,
|
|
||||||
};
|
|
||||||
char *p = get_scriptname(last_set, &should_free);
|
|
||||||
fprintf(fd, " Defined: %s:%" PRIdLINENR "\n",
|
fprintf(fd, " Defined: %s:%" PRIdLINENR "\n",
|
||||||
p, fp->uf_script_ctx.sc_lnum);
|
p, fp->uf_script_ctx.sc_lnum);
|
||||||
if (should_free) {
|
if (should_free) {
|
||||||
|
@@ -270,17 +270,13 @@ list_T *stacktrace_create(void)
|
|||||||
ufunc_T *const fp = entry->es_info.ufunc;
|
ufunc_T *const fp = entry->es_info.ufunc;
|
||||||
const sctx_T sctx = fp->uf_script_ctx;
|
const sctx_T sctx = fp->uf_script_ctx;
|
||||||
bool filepath_alloced = false;
|
bool filepath_alloced = false;
|
||||||
char *filepath = sctx.sc_sid > 0
|
char *filepath = sctx.sc_sid > 0 ? get_scriptname(sctx, &filepath_alloced) : "";
|
||||||
? get_scriptname((LastSet){ .script_ctx = sctx },
|
|
||||||
&filepath_alloced) : "";
|
|
||||||
lnum += sctx.sc_lnum;
|
lnum += sctx.sc_lnum;
|
||||||
stacktrace_push_item(l, fp, NULL, lnum, filepath, filepath_alloced);
|
stacktrace_push_item(l, fp, NULL, lnum, filepath, filepath_alloced);
|
||||||
} else if (entry->es_type == ETYPE_AUCMD) {
|
} else if (entry->es_type == ETYPE_AUCMD) {
|
||||||
const sctx_T sctx = entry->es_info.aucmd->script_ctx;
|
const sctx_T sctx = entry->es_info.aucmd->script_ctx;
|
||||||
bool filepath_alloced = false;
|
bool filepath_alloced = false;
|
||||||
char *filepath = sctx.sc_sid > 0
|
char *filepath = sctx.sc_sid > 0 ? get_scriptname(sctx, &filepath_alloced) : "";
|
||||||
? get_scriptname((LastSet){ .script_ctx = sctx },
|
|
||||||
&filepath_alloced) : "";
|
|
||||||
lnum += sctx.sc_lnum;
|
lnum += sctx.sc_lnum;
|
||||||
stacktrace_push_item(l, NULL, entry->es_name, lnum, filepath, filepath_alloced);
|
stacktrace_push_item(l, NULL, entry->es_name, lnum, filepath, filepath_alloced);
|
||||||
}
|
}
|
||||||
@@ -2426,11 +2422,11 @@ void scriptnames_slash_adjust(void)
|
|||||||
|
|
||||||
/// Get a pointer to a script name. Used for ":verbose set".
|
/// Get a pointer to a script name. Used for ":verbose set".
|
||||||
/// Message appended to "Last set from "
|
/// Message appended to "Last set from "
|
||||||
char *get_scriptname(LastSet last_set, bool *should_free)
|
char *get_scriptname(sctx_T script_ctx, bool *should_free)
|
||||||
{
|
{
|
||||||
*should_free = false;
|
*should_free = false;
|
||||||
|
|
||||||
switch (last_set.script_ctx.sc_sid) {
|
switch (script_ctx.sc_sid) {
|
||||||
case SID_MODELINE:
|
case SID_MODELINE:
|
||||||
return _("modeline");
|
return _("modeline");
|
||||||
case SID_CMDARG:
|
case SID_CMDARG:
|
||||||
@@ -2446,15 +2442,15 @@ char *get_scriptname(LastSet last_set, bool *should_free)
|
|||||||
case SID_LUA:
|
case SID_LUA:
|
||||||
return _("Lua (run Nvim with -V1 for more details)");
|
return _("Lua (run Nvim with -V1 for more details)");
|
||||||
case SID_API_CLIENT:
|
case SID_API_CLIENT:
|
||||||
snprintf(IObuff, IOSIZE, _("API client (channel id %" PRIu64 ")"), last_set.channel_id);
|
snprintf(IObuff, IOSIZE, _("API client (channel id %" PRIu64 ")"), script_ctx.sc_chan);
|
||||||
return IObuff;
|
return IObuff;
|
||||||
case SID_STR:
|
case SID_STR:
|
||||||
return _("anonymous :source");
|
return _("anonymous :source");
|
||||||
default: {
|
default: {
|
||||||
char *const sname = SCRIPT_ITEM(last_set.script_ctx.sc_sid)->sn_name;
|
char *const sname = SCRIPT_ITEM(script_ctx.sc_sid)->sn_name;
|
||||||
if (sname == NULL) {
|
if (sname == NULL) {
|
||||||
snprintf(IObuff, IOSIZE, _("anonymous :source (script id %d)"),
|
snprintf(IObuff, IOSIZE, _("anonymous :source (script id %d)"),
|
||||||
last_set.script_ctx.sc_sid);
|
script_ctx.sc_sid);
|
||||||
return IObuff;
|
return IObuff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -865,7 +865,7 @@ int fex_format(linenr_T lnum, long count, int c)
|
|||||||
|
|
||||||
// Make a copy, the option could be changed while calling it.
|
// Make a copy, the option could be changed while calling it.
|
||||||
char *fex = xstrdup(curbuf->b_p_fex);
|
char *fex = xstrdup(curbuf->b_p_fex);
|
||||||
current_sctx = curbuf->b_p_script_ctx[kBufOptFormatexpr].script_ctx;
|
current_sctx = curbuf->b_p_script_ctx[kBufOptFormatexpr];
|
||||||
|
|
||||||
// Evaluate the function.
|
// Evaluate the function.
|
||||||
if (use_sandbox) {
|
if (use_sandbox) {
|
||||||
|
@@ -6714,8 +6714,8 @@ void win_comp_scroll(win_T *wp)
|
|||||||
|
|
||||||
if (wp->w_p_scr != old_w_p_scr) {
|
if (wp->w_p_scr != old_w_p_scr) {
|
||||||
// Used by "verbose set scroll".
|
// Used by "verbose set scroll".
|
||||||
wp->w_p_script_ctx[kWinOptScroll].script_ctx.sc_sid = SID_WINLAYOUT;
|
wp->w_p_script_ctx[kWinOptScroll].sc_sid = SID_WINLAYOUT;
|
||||||
wp->w_p_script_ctx[kWinOptScroll].script_ctx.sc_lnum = 0;
|
wp->w_p_script_ctx[kWinOptScroll].sc_lnum = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -6,17 +6,18 @@ local eq = t.eq
|
|||||||
local exec = n.exec
|
local exec = n.exec
|
||||||
local exec_capture = n.exec_capture
|
local exec_capture = n.exec_capture
|
||||||
local write_file = t.write_file
|
local write_file = t.write_file
|
||||||
local call_viml_function = n.api.nvim_call_function
|
local api = n.api
|
||||||
|
local fn = n.fn
|
||||||
|
|
||||||
local function last_set_tests(cmd)
|
local function last_set_lua_tests(cmd)
|
||||||
local script_location, script_file
|
local script_location, script_file
|
||||||
-- All test cases below use the same nvim instance.
|
-- All test cases below use the same Nvim instance.
|
||||||
setup(function()
|
setup(function()
|
||||||
clear { args = { '-V1' } }
|
clear({ args = { '-V1' } })
|
||||||
script_file = 'test_verbose.lua'
|
script_file = 'test_verbose.lua'
|
||||||
local current_dir = call_viml_function('getcwd', {})
|
local current_dir = fn.getcwd()
|
||||||
current_dir = call_viml_function('fnamemodify', { current_dir, ':~' })
|
current_dir = fn.fnamemodify(current_dir, ':~')
|
||||||
script_location = table.concat { current_dir, n.get_pathsep(), script_file }
|
script_location = table.concat({ current_dir, n.get_pathsep(), script_file })
|
||||||
|
|
||||||
write_file(
|
write_file(
|
||||||
script_file,
|
script_file,
|
||||||
@@ -66,7 +67,7 @@ let &tw = s:return80()\
|
|||||||
os.remove(script_file)
|
os.remove(script_file)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('"Last set" for option set by Lua', function()
|
it('"Last set" for option set by nvim_set_option_value', function()
|
||||||
local result = exec_capture(':verbose set hlsearch?')
|
local result = exec_capture(':verbose set hlsearch?')
|
||||||
eq(
|
eq(
|
||||||
string.format(
|
string.format(
|
||||||
@@ -105,7 +106,7 @@ nohlsearch
|
|||||||
)
|
)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('"Last set" for mapping set by Lua', function()
|
it('"Last set" for mapping set by nvim_set_keymap', function()
|
||||||
local result = exec_capture(':verbose map <leader>key1')
|
local result = exec_capture(':verbose map <leader>key1')
|
||||||
eq(
|
eq(
|
||||||
string.format(
|
string.format(
|
||||||
@@ -220,7 +221,7 @@ TestHL2 xxx guibg=Green
|
|||||||
)
|
)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('"Last set" for function', function()
|
it('"Last set" for function defined by nvim_exec2', function()
|
||||||
local result = exec_capture(':verbose function Close_Window')
|
local result = exec_capture(':verbose function Close_Window')
|
||||||
eq(
|
eq(
|
||||||
string.format(
|
string.format(
|
||||||
@@ -235,7 +236,7 @@ TestHL2 xxx guibg=Green
|
|||||||
)
|
)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('"Last set" works with anonymous sid', function()
|
it('"Last set" works with anonymous sid from nvim_exec2', function()
|
||||||
local result = exec_capture(':verbose set tw?')
|
local result = exec_capture(':verbose set tw?')
|
||||||
eq(
|
eq(
|
||||||
string.format(
|
string.format(
|
||||||
@@ -250,11 +251,11 @@ TestHL2 xxx guibg=Green
|
|||||||
end
|
end
|
||||||
|
|
||||||
describe('lua :verbose when using :source', function()
|
describe('lua :verbose when using :source', function()
|
||||||
last_set_tests('source')
|
last_set_lua_tests('source')
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe('lua :verbose when using :luafile', function()
|
describe('lua :verbose when using :luafile', function()
|
||||||
last_set_tests('luafile')
|
last_set_lua_tests('luafile')
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe('lua verbose:', function()
|
describe('lua verbose:', function()
|
||||||
@@ -286,3 +287,176 @@ nohlsearch
|
|||||||
)
|
)
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
describe(':verbose when using API from Vimscript', function()
|
||||||
|
local script_location, script_file
|
||||||
|
-- All test cases below use the same Nvim instance.
|
||||||
|
setup(function()
|
||||||
|
clear()
|
||||||
|
script_file = 'test_verbose.vim'
|
||||||
|
local current_dir = fn.getcwd()
|
||||||
|
current_dir = fn.fnamemodify(current_dir, ':~')
|
||||||
|
script_location = table.concat({ current_dir, n.get_pathsep(), script_file })
|
||||||
|
|
||||||
|
write_file(
|
||||||
|
script_file,
|
||||||
|
[[
|
||||||
|
call nvim_set_option_value('hlsearch', v:false, {})
|
||||||
|
call nvim_set_keymap('n', '<leader>key1', ':echo "test"<cr>', #{noremap: v:true})
|
||||||
|
|
||||||
|
call nvim_create_augroup('test_group', {})
|
||||||
|
call nvim_create_autocmd('FileType', #{
|
||||||
|
\ group: 'test_group',
|
||||||
|
\ pattern: 'cpp',
|
||||||
|
\ command: 'setl cindent',
|
||||||
|
\ })
|
||||||
|
|
||||||
|
call nvim_set_hl(0, 'TestHL2', #{bg: 'Green'})
|
||||||
|
call nvim_create_user_command("TestCommand", ":echo 'Hello'", {})
|
||||||
|
]]
|
||||||
|
)
|
||||||
|
exec('source ' .. script_file)
|
||||||
|
end)
|
||||||
|
|
||||||
|
teardown(function()
|
||||||
|
os.remove(script_file)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('"Last set" for option set by nvim_set_option_value', function()
|
||||||
|
local result = exec_capture(':verbose set hlsearch?')
|
||||||
|
eq(
|
||||||
|
string.format(
|
||||||
|
[[
|
||||||
|
nohlsearch
|
||||||
|
Last set from %s line 1]],
|
||||||
|
script_location
|
||||||
|
),
|
||||||
|
result
|
||||||
|
)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('"Last set" for mapping set by nvim_set_keymap', function()
|
||||||
|
local result = exec_capture(':verbose map <leader>key1')
|
||||||
|
eq(
|
||||||
|
string.format(
|
||||||
|
[[
|
||||||
|
|
||||||
|
n \key1 * :echo "test"<CR>
|
||||||
|
Last set from %s line 2]],
|
||||||
|
script_location
|
||||||
|
),
|
||||||
|
result
|
||||||
|
)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('"Last set" for autocmd set by nvim_create_autocmd', function()
|
||||||
|
local result = exec_capture(':verbose autocmd test_group Filetype cpp')
|
||||||
|
eq(
|
||||||
|
string.format(
|
||||||
|
[[
|
||||||
|
--- Autocommands ---
|
||||||
|
test_group FileType
|
||||||
|
cpp setl cindent
|
||||||
|
Last set from %s line 5]],
|
||||||
|
script_location
|
||||||
|
),
|
||||||
|
result
|
||||||
|
)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('"Last set" for highlight group set by nvim_set_hl', function()
|
||||||
|
local result = exec_capture(':verbose highlight TestHL2')
|
||||||
|
eq(
|
||||||
|
string.format(
|
||||||
|
[[
|
||||||
|
TestHL2 xxx guibg=Green
|
||||||
|
Last set from %s line 11]],
|
||||||
|
script_location
|
||||||
|
),
|
||||||
|
result
|
||||||
|
)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('"Last set" for command defined by nvim_create_user_command', function()
|
||||||
|
local result = exec_capture(':verbose command TestCommand')
|
||||||
|
eq(
|
||||||
|
string.format(
|
||||||
|
[[
|
||||||
|
Name Args Address Complete Definition
|
||||||
|
TestCommand 0 :echo 'Hello'
|
||||||
|
Last set from %s line 12]],
|
||||||
|
script_location
|
||||||
|
),
|
||||||
|
result
|
||||||
|
)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
describe(':verbose when using API from RPC', function()
|
||||||
|
-- All test cases below use the same Nvim instance.
|
||||||
|
setup(clear)
|
||||||
|
|
||||||
|
it('"Last set" for option set by nvim_set_option_value', function()
|
||||||
|
api.nvim_set_option_value('hlsearch', false, {})
|
||||||
|
local result = exec_capture(':verbose set hlsearch?')
|
||||||
|
eq(
|
||||||
|
[[
|
||||||
|
nohlsearch
|
||||||
|
Last set from API client (channel id 1)]],
|
||||||
|
result
|
||||||
|
)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('"Last set" for mapping set by nvim_set_keymap', function()
|
||||||
|
api.nvim_set_keymap('n', '<leader>key1', ':echo "test"<cr>', { noremap = true })
|
||||||
|
local result = exec_capture(':verbose map <leader>key1')
|
||||||
|
eq(
|
||||||
|
[[
|
||||||
|
|
||||||
|
n \key1 * :echo "test"<CR>
|
||||||
|
Last set from API client (channel id 1)]],
|
||||||
|
result
|
||||||
|
)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('"Last set" for autocmd set by nvim_create_autocmd', function()
|
||||||
|
api.nvim_create_augroup('test_group', {})
|
||||||
|
api.nvim_create_autocmd('FileType', {
|
||||||
|
group = 'test_group',
|
||||||
|
pattern = 'cpp',
|
||||||
|
command = 'setl cindent',
|
||||||
|
})
|
||||||
|
local result = exec_capture(':verbose autocmd test_group Filetype cpp')
|
||||||
|
eq(
|
||||||
|
[[
|
||||||
|
--- Autocommands ---
|
||||||
|
test_group FileType
|
||||||
|
cpp setl cindent
|
||||||
|
Last set from API client (channel id 1)]],
|
||||||
|
result
|
||||||
|
)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('"Last set" for highlight group set by nvim_set_hl', function()
|
||||||
|
api.nvim_set_hl(0, 'TestHL2', { bg = 'Green' })
|
||||||
|
local result = exec_capture(':verbose highlight TestHL2')
|
||||||
|
eq(
|
||||||
|
[[
|
||||||
|
TestHL2 xxx guibg=Green
|
||||||
|
Last set from API client (channel id 1)]],
|
||||||
|
result
|
||||||
|
)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('"Last set" for command defined by nvim_create_user_command', function()
|
||||||
|
api.nvim_create_user_command('TestCommand', ":echo 'Hello'", {})
|
||||||
|
local result = exec_capture(':verbose command TestCommand')
|
||||||
|
eq(
|
||||||
|
[[
|
||||||
|
Name Args Address Complete Definition
|
||||||
|
TestCommand 0 :echo 'Hello'
|
||||||
|
Last set from API client (channel id 1)]],
|
||||||
|
result
|
||||||
|
)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
Reference in New Issue
Block a user