mirror of
				https://github.com/neovim/neovim.git
				synced 2025-11-04 09:44:31 +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