diff options
author | zeertzjq <zeertzjq@outlook.com> | 2025-02-25 09:17:51 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-02-25 01:17:51 +0000 |
commit | 095c0876c2010d6160df37cf057f2d0ad2c4501f (patch) | |
tree | a1ad1fbecda4626835bb415a3d4ee80f56c4362a /src | |
parent | 614c9322d50052c76fb3e6e1be7536a972ff0902 (diff) | |
download | rneovim-095c0876c2010d6160df37cf057f2d0ad2c4501f.tar.gz rneovim-095c0876c2010d6160df37cf057f2d0ad2c4501f.tar.bz2 rneovim-095c0876c2010d6160df37cf057f2d0ad2c4501f.zip |
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
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/api/private/helpers.c | 24 | ||||
-rw-r--r-- | src/nvim/api/private/helpers.h | 8 | ||||
-rw-r--r-- | src/nvim/buffer_defs.h | 4 | ||||
-rw-r--r-- | src/nvim/eval.c | 28 | ||||
-rw-r--r-- | src/nvim/eval/typval_defs.h | 7 | ||||
-rw-r--r-- | src/nvim/file_search.c | 2 | ||||
-rw-r--r-- | src/nvim/fold.c | 2 | ||||
-rw-r--r-- | src/nvim/globals.h | 4 | ||||
-rw-r--r-- | src/nvim/indent.c | 2 | ||||
-rw-r--r-- | src/nvim/option.c | 42 | ||||
-rw-r--r-- | src/nvim/option_defs.h | 2 | ||||
-rw-r--r-- | src/nvim/profile.c | 6 | ||||
-rw-r--r-- | src/nvim/runtime.c | 18 | ||||
-rw-r--r-- | src/nvim/textformat.c | 2 | ||||
-rw-r--r-- | src/nvim/window.c | 4 |
15 files changed, 50 insertions, 105 deletions
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index a1af26e56f..cf82d907a3 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -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. /// -/// @param channel_id api clients id. Used to determine if it's a internal -/// call or a rpc call. -/// @return returns previous value of current_sctx. To be used -/// to be used for restoring sctx to previous state. +/// @param channel_id api client id to determine if it's a internal or RPC call. +/// +/// @return previous value of current_sctx. To be used later for restoring sctx. sctx_T api_set_sctx(uint64_t channel_id) { sctx_T old_current_sctx = current_sctx; if (channel_id != VIML_INTERNAL_CALL) { - current_sctx.sc_sid = - channel_id == LUA_INTERNAL_CALL ? SID_LUA : SID_API_CLIENT; + current_sctx.sc_sid = channel_id == LUA_INTERNAL_CALL ? SID_LUA : SID_API_CLIENT; current_sctx.sc_lnum = 0; + current_sctx.sc_chan = channel_id; } return old_current_sctx; } diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h index 5cf1ca4d34..d51f99e5ac 100644 --- a/src/nvim/api/private/helpers.h +++ b/src/nvim/api/private/helpers.h @@ -186,13 +186,7 @@ typedef struct { #define WITH_SCRIPT_CONTEXT(channel_id, code) \ do { \ - const sctx_T save_current_sctx = current_sctx; \ - 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; \ + const sctx_T save_current_sctx = api_set_sctx(channel_id); \ code; \ - current_channel_id = save_channel_id; \ current_sctx = save_current_sctx; \ } while (0); diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 28029d0249..6d42b5d9ad 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -208,7 +208,7 @@ typedef struct { OptInt wo_winbl; #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 } winopt_T; @@ -510,7 +510,7 @@ struct file_buffer { // or contents of the file being edited. 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_nopaste; ///< b_p_ai saved for paste mode diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 5b91f1248f..18f83bfb6b 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -1368,7 +1368,7 @@ int eval_foldexpr(win_T *wp, int *cp) const bool use_sandbox = was_set_insecurely(wp, kOptFoldexpr, OPT_LOCAL); 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++; 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 // 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. - const LastSet last_set = (LastSet){ - .script_ctx = current_sctx, - .channel_id = LUA_INTERNAL_CALL, - }; bool should_free; // should_free is ignored as script_ctx will be resolved to a fname // 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); } } @@ -8043,31 +8039,19 @@ void var_set_global(const char *const name, typval_T vartv) /// Should only be invoked when 'verbose' is non-zero. void last_set_msg(sctx_T script_ctx) { - const LastSet last_set = (LastSet){ - .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) { + if (script_ctx.sc_sid == 0) { return; } bool should_free; - char *p = get_scriptname(last_set, &should_free); + char *p = get_scriptname(script_ctx, &should_free); verbose_enter(); msg_puts(_("\n\tLast set from ")); msg_puts(p); - if (last_set.script_ctx.sc_lnum > 0) { + if (script_ctx.sc_lnum > 0) { msg_puts(_(line_msg)); - msg_outnum(last_set.script_ctx.sc_lnum); + msg_outnum(script_ctx.sc_lnum); } if (should_free) { xfree(p); diff --git a/src/nvim/eval/typval_defs.h b/src/nvim/eval/typval_defs.h index 90b0d4e4a9..ddc2b154a4 100644 --- a/src/nvim/eval/typval_defs.h +++ b/src/nvim/eval/typval_defs.h @@ -286,14 +286,9 @@ typedef struct { scid_T sc_sid; ///< script ID int sc_seq; ///< sourcing sequence number linenr_T sc_lnum; ///< line number + uint64_t sc_chan; ///< Only used when sc_sid is SID_API_CLIENT. } 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 { VAR_SHORT_LEN = 20, }; ///< Short variable name length enum { FIXVAR_CNT = 12, }; ///< Number of fixed variables used for arguments diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c index 8ca0676a0f..b0029e7761 100644 --- a/src/nvim/file_search.c +++ b/src/nvim/file_search.c @@ -1747,7 +1747,7 @@ static char *eval_includeexpr(const char *const ptr, const size_t len) { const sctx_T save_sctx = current_sctx; 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, was_set_insecurely(curwin, kOptIncludeexpr, OPT_LOCAL), diff --git a/src/nvim/fold.c b/src/nvim/fold.c index 45cc327444..41b5ce9a32 100644 --- a/src/nvim/fold.c +++ b/src/nvim/fold.c @@ -1731,7 +1731,7 @@ char *get_foldtext(win_T *wp, linenr_T lnum, linenr_T lnume, foldinfo_T foldinfo curwin = wp; 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 diff --git a/src/nvim/globals.h b/src/nvim/globals.h index ea349352a8..e0bbba3d68 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -298,9 +298,7 @@ EXTERN bool garbage_collect_at_exit INIT( = false); #define SID_STR (-10) // for sourcing a string with no script item // Script CTX being sourced or was sourced to define the current function. -EXTERN sctx_T current_sctx INIT( = { 0, 0, 0 }); -// ID of the current channel making a client API call -EXTERN uint64_t current_channel_id INIT( = 0); +EXTERN sctx_T current_sctx INIT( = { 0, 0, 0, 0 }); /// Last channel that invoked 'nvim_input` or got FocusGained. EXTERN uint64_t current_ui INIT( = 0); diff --git a/src/nvim/indent.c b/src/nvim/indent.c index 170346ec0d..0d06199bde 100644 --- a/src/nvim/indent.c +++ b/src/nvim/indent.c @@ -1181,7 +1181,7 @@ int get_expr_indent(void) sandbox++; } 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 // evaluating it. diff --git a/src/nvim/option.c b/src/nvim/option.c index f92ec349da..e5efdb9924 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -1286,11 +1286,11 @@ static void do_one_set_option(int opt_flags, char **argp, bool *did_show, char * if (p_verbose > 0) { // Mention where the option was last set. 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)) { - 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)) { - 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) { 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 @@ -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; nlua_set_sctx(&script_ctx); - LastSet last_set = { - .script_ctx = script_ctx, - .channel_id = current_channel_id, - }; // Modeline already has the line number set. 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 // in the buffer or window structure. 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 (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))) { - 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) { // 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; } -#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. /// 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)); - LastSet last_set = { .channel_id = 0 }; + sctx_T script_ctx = { .sc_sid = 0 }; if (opt_flags == OPT_GLOBAL) { - last_set = opt->last_set; + script_ctx = opt->script_ctx; } else { // Scope is either OPT_LOCAL or a fallback mode was requested. 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)) { - 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) { - last_set = opt->last_set; + if (opt_flags != OPT_LOCAL && script_ctx.sc_sid == 0) { + script_ctx = opt->script_ctx; } } - PUT_C(dict, "last_set_sid", INTEGER_OBJ(last_set.script_ctx.sc_sid)); - PUT_C(dict, "last_set_linenr", INTEGER_OBJ(last_set.script_ctx.sc_lnum)); - PUT_C(dict, "last_set_chan", INTEGER_OBJ((int64_t)last_set.channel_id)); + PUT_C(dict, "last_set_sid", INTEGER_OBJ(script_ctx.sc_sid)); + PUT_C(dict, "last_set_linenr", INTEGER_OBJ(script_ctx.sc_lnum)); + 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, "default", optval_as_object(opt->def_val)); diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index 7dd4bd2bc7..ec227aa301 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -191,5 +191,5 @@ typedef struct { opt_expand_cb_T opt_expand_cb; 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; diff --git a/src/nvim/profile.c b/src/nvim/profile.c index 65d341cac3..627f06c9ce 100644 --- a/src/nvim/profile.c +++ b/src/nvim/profile.c @@ -616,11 +616,7 @@ static void func_dump_profile(FILE *fd) } if (fp->uf_script_ctx.sc_sid != 0) { bool should_free; - const LastSet last_set = (LastSet){ - .script_ctx = fp->uf_script_ctx, - .channel_id = 0, - }; - char *p = get_scriptname(last_set, &should_free); + char *p = get_scriptname(fp->uf_script_ctx, &should_free); fprintf(fd, " Defined: %s:%" PRIdLINENR "\n", p, fp->uf_script_ctx.sc_lnum); if (should_free) { diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c index cdedf86977..de58c81441 100644 --- a/src/nvim/runtime.c +++ b/src/nvim/runtime.c @@ -270,17 +270,13 @@ list_T *stacktrace_create(void) ufunc_T *const fp = entry->es_info.ufunc; const sctx_T sctx = fp->uf_script_ctx; bool filepath_alloced = false; - char *filepath = sctx.sc_sid > 0 - ? get_scriptname((LastSet){ .script_ctx = sctx }, - &filepath_alloced) : ""; + char *filepath = sctx.sc_sid > 0 ? get_scriptname(sctx, &filepath_alloced) : ""; lnum += sctx.sc_lnum; stacktrace_push_item(l, fp, NULL, lnum, filepath, filepath_alloced); } else if (entry->es_type == ETYPE_AUCMD) { const sctx_T sctx = entry->es_info.aucmd->script_ctx; bool filepath_alloced = false; - char *filepath = sctx.sc_sid > 0 - ? get_scriptname((LastSet){ .script_ctx = sctx }, - &filepath_alloced) : ""; + char *filepath = sctx.sc_sid > 0 ? get_scriptname(sctx, &filepath_alloced) : ""; lnum += sctx.sc_lnum; 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". /// 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; - switch (last_set.script_ctx.sc_sid) { + switch (script_ctx.sc_sid) { case SID_MODELINE: return _("modeline"); case SID_CMDARG: @@ -2446,15 +2442,15 @@ char *get_scriptname(LastSet last_set, bool *should_free) case SID_LUA: return _("Lua (run Nvim with -V1 for more details)"); 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; case SID_STR: return _("anonymous :source"); 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) { snprintf(IObuff, IOSIZE, _("anonymous :source (script id %d)"), - last_set.script_ctx.sc_sid); + script_ctx.sc_sid); return IObuff; } diff --git a/src/nvim/textformat.c b/src/nvim/textformat.c index ffa273c0ad..b40dbd7bc2 100644 --- a/src/nvim/textformat.c +++ b/src/nvim/textformat.c @@ -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. 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. if (use_sandbox) { diff --git a/src/nvim/window.c b/src/nvim/window.c index 1fa31f10b1..e8a357a708 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -6714,8 +6714,8 @@ void win_comp_scroll(win_T *wp) if (wp->w_p_scr != old_w_p_scr) { // Used by "verbose set scroll". - wp->w_p_script_ctx[kWinOptScroll].script_ctx.sc_sid = SID_WINLAYOUT; - wp->w_p_script_ctx[kWinOptScroll].script_ctx.sc_lnum = 0; + wp->w_p_script_ctx[kWinOptScroll].sc_sid = SID_WINLAYOUT; + wp->w_p_script_ctx[kWinOptScroll].sc_lnum = 0; } } |