Merge #8329 'API: Make nvim_set_option() update `:verbose set …`'

This commit is contained in:
Justin M. Keyes 2018-05-11 10:08:09 +02:00
commit 273d2cd5d5
11 changed files with 134 additions and 70 deletions

View File

@ -581,7 +581,8 @@ Object nvim_buf_get_option(Buffer buffer, String name, Error *err)
/// @param name Option name
/// @param value Option value
/// @param[out] err Error details, if any
void nvim_buf_set_option(Buffer buffer, String name, Object value, Error *err)
void nvim_buf_set_option(uint64_t channel_id, Buffer buffer,
String name, Object value, Error *err)
FUNC_API_SINCE(1)
{
buf_T *buf = find_buffer_by_handle(buffer, err);
@ -590,7 +591,7 @@ void nvim_buf_set_option(Buffer buffer, String name, Object value, Error *err)
return;
}
set_option_to(buf, SREQ_BUF, name, value, err);
set_option_to(channel_id, buf, SREQ_BUF, name, value, err);
}
/// Gets the buffer number

View File

@ -324,7 +324,8 @@ Object get_option_from(void *from, int type, String name, Error *err)
/// @param type One of `SREQ_GLOBAL`, `SREQ_WIN` or `SREQ_BUF`
/// @param name The option name
/// @param[out] err Details of an error that may have occurred
void set_option_to(void *to, int type, String name, Object value, Error *err)
void set_option_to(uint64_t channel_id, void *to, int type,
String name, Object value, Error *err)
{
if (name.size == 0) {
api_set_error(err, kErrorTypeValidation, "Empty option name");
@ -361,7 +362,8 @@ void set_option_to(void *to, int type, String name, Object value, Error *err)
}
}
int opt_flags = (type == SREQ_GLOBAL) ? OPT_GLOBAL : OPT_LOCAL;
int numval = 0;
char *stringval = NULL;
if (flags & SOPT_BOOL) {
if (value.type != kObjectTypeBoolean) {
@ -372,8 +374,7 @@ void set_option_to(void *to, int type, String name, Object value, Error *err)
return;
}
bool val = value.data.boolean;
set_option_value_for(name.data, val, NULL, opt_flags, type, to, err);
numval = value.data.boolean;
} else if (flags & SOPT_NUM) {
if (value.type != kObjectTypeInteger) {
api_set_error(err,
@ -391,8 +392,7 @@ void set_option_to(void *to, int type, String name, Object value, Error *err)
return;
}
int val = (int) value.data.integer;
set_option_value_for(name.data, val, NULL, opt_flags, type, to, err);
numval = (int)value.data.integer;
} else {
if (value.type != kObjectTypeString) {
api_set_error(err,
@ -402,9 +402,18 @@ void set_option_to(void *to, int type, String name, Object value, Error *err)
return;
}
set_option_value_for(name.data, 0, value.data.string.data,
opt_flags, type, to, err);
stringval = (char *)value.data.string.data;
}
const scid_T save_current_SID = current_SID;
current_SID = channel_id == LUA_INTERNAL_CALL ? SID_LUA : SID_API_CLIENT;
current_channel_id = channel_id;
const int opt_flags = (type == SREQ_GLOBAL) ? OPT_GLOBAL : OPT_LOCAL;
set_option_value_for(name.data, numval, stringval,
opt_flags, type, to, err);
current_SID = save_current_SID;
}
#define TYPVAL_ENCODE_ALLOW_SPECIALS false

View File

@ -683,10 +683,10 @@ Object nvim_get_option(String name, Error *err)
/// @param name Option name
/// @param value New option value
/// @param[out] err Error details, if any
void nvim_set_option(String name, Object value, Error *err)
void nvim_set_option(uint64_t channel_id, String name, Object value, Error *err)
FUNC_API_SINCE(1)
{
set_option_to(NULL, SREQ_GLOBAL, name, value, err);
set_option_to(channel_id, NULL, SREQ_GLOBAL, name, value, err);
}
/// Writes a message to the Vim output buffer. Does not append "\n", the

View File

@ -309,7 +309,8 @@ Object nvim_win_get_option(Window window, String name, Error *err)
/// @param name Option name
/// @param value Option value
/// @param[out] err Error details, if any
void nvim_win_set_option(Window window, String name, Object value, Error *err)
void nvim_win_set_option(uint64_t channel_id, Window window,
String name, Object value, Error *err)
FUNC_API_SINCE(1)
{
win_T *win = find_window_by_handle(window, err);
@ -318,7 +319,7 @@ void nvim_win_set_option(Window window, String name, Object value, Error *err)
return;
}
set_option_to(win, SREQ_WIN, name, value, err);
set_option_to(channel_id, win, SREQ_WIN, name, value, err);
}
/// Gets the window position in display cells. First position is zero.

View File

@ -237,7 +237,7 @@ typedef struct {
char_u *wo_winhl;
# define w_p_winhl w_onebuf_opt.wo_winhl // 'winhighlight'
int wo_scriptID[WV_COUNT]; /* SIDs for window-local options */
LastSet wo_scriptID[WV_COUNT]; // SIDs for window-local options
# define w_p_scriptID w_onebuf_opt.wo_scriptID
} winopt_T;
@ -590,7 +590,7 @@ struct file_buffer {
*/
bool b_p_initialized; /* set when options initialized */
int b_p_scriptID[BV_COUNT]; /* SIDs for buffer-local options */
LastSet b_p_scriptID[BV_COUNT]; // SIDs for buffer-local options
int b_p_ai; ///< 'autoindent'
int b_p_ai_nopaste; ///< b_p_ai saved for paste mode

View File

@ -22066,12 +22066,27 @@ int store_session_globals(FILE *fd)
*/
void last_set_msg(scid_T scriptID)
{
if (scriptID != 0) {
char_u *p = home_replace_save(NULL, get_scriptname(scriptID));
const LastSet last_set = (LastSet){
.script_id = scriptID,
.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_id != 0) {
bool should_free;
char_u *p = get_scriptname(last_set, &should_free);
verbose_enter();
MSG_PUTS(_("\n\tLast set from "));
MSG_PUTS(p);
xfree(p);
if (should_free) {
xfree(p);
}
verbose_leave();
}
}

View File

@ -3055,24 +3055,32 @@ void scriptnames_slash_adjust(void)
# endif
/// Get a pointer to a script name. Used for ":verbose set".
char_u *get_scriptname(scid_T id)
char_u *get_scriptname(LastSet last_set, bool *should_free)
{
if (id == SID_MODELINE) {
return (char_u *)_("modeline");
*should_free = false;
switch (last_set.script_id) {
case SID_MODELINE:
return (char_u *)_("modeline");
case SID_CMDARG:
return (char_u *)_("--cmd argument");
case SID_CARG:
return (char_u *)_("-c argument");
case SID_ENV:
return (char_u *)_("environment variable");
case SID_ERROR:
return (char_u *)_("error handler");
case SID_LUA:
return (char_u *)_("Lua");
case SID_API_CLIENT:
vim_snprintf((char *)IObuff, IOSIZE,
_("API client (channel id %" PRIu64 ")"),
last_set.channel_id);
return IObuff;
default:
*should_free = true;
return home_replace_save(NULL, SCRIPT_ITEM(last_set.script_id).sn_name);
}
if (id == SID_CMDARG) {
return (char_u *)_("--cmd argument");
}
if (id == SID_CARG) {
return (char_u *)_("-c argument");
}
if (id == SID_ENV) {
return (char_u *)_("environment variable");
}
if (id == SID_ERROR) {
return (char_u *)_("error handler");
}
return SCRIPT_ITEM(id).sn_name;
}
# if defined(EXITFREE)

View File

@ -390,16 +390,20 @@ EXTERN int may_garbage_collect INIT(= FALSE);
EXTERN int want_garbage_collect INIT(= FALSE);
EXTERN int garbage_collect_at_exit INIT(= FALSE);
/* Special values for current_SID. */
#define SID_MODELINE -1 /* when using a modeline */
#define SID_CMDARG -2 /* for "--cmd" argument */
#define SID_CARG -3 /* for "-c" argument */
#define SID_ENV -4 /* for sourcing environment variable */
#define SID_ERROR -5 /* option was reset because of an error */
#define SID_NONE -6 /* don't set scriptID */
// Special values for current_SID.
#define SID_MODELINE -1 // when using a modeline
#define SID_CMDARG -2 // for "--cmd" argument
#define SID_CARG -3 // for "-c" argument
#define SID_ENV -4 // for sourcing environment variable
#define SID_ERROR -5 // option was reset because of an error
#define SID_NONE -6 // don't set scriptID
#define SID_LUA -7 // for Lua scripts/chunks
#define SID_API_CLIENT -8 // for API clients
/* ID of script being sourced or was sourced to define the current function. */
// ID of script being sourced or was sourced to define the current function.
EXTERN scid_T current_SID INIT(= 0);
// ID of the current channel making a client API call
EXTERN uint64_t current_channel_id INIT(= 0);
EXTERN bool did_source_packages INIT(= false);

View File

@ -187,16 +187,16 @@ static long p_tw_nopaste;
static long p_wm_nopaste;
typedef struct vimoption {
char *fullname; /* full option name */
char *shortname; /* permissible abbreviation */
uint32_t flags; /* see below */
char_u *var; /* global option: pointer to variable;
* window-local option: VAR_WIN;
* buffer-local option: global value */
idopt_T indir; /* global option: PV_NONE;
* local option: indirect option index */
char_u *def_val[2]; /* default values for variable (vi and vim) */
scid_T scriptID; /* script in which the option was last set */
char *fullname; // full option name
char *shortname; // permissible abbreviation
uint32_t flags; // see below
char_u *var; // global option: pointer to variable;
// window-local option: VAR_WIN;
// buffer-local option: global value
idopt_T indir; // global option: PV_NONE;
// local option: indirect option index
char_u *def_val[2]; // default values for variable (vi and vim)
LastSet last_set; // script in which the option was last set
# define SCRIPTID_INIT , 0
} vimoption_T;
@ -1345,15 +1345,16 @@ do_set (
if (opt_idx >= 0) {
showoneopt(&options[opt_idx], opt_flags);
if (p_verbose > 0) {
/* Mention where the option was last set. */
if (varp == options[opt_idx].var)
last_set_msg(options[opt_idx].scriptID);
else if ((int)options[opt_idx].indir & PV_WIN)
last_set_msg(curwin->w_p_scriptID[
(int)options[opt_idx].indir & PV_MASK]);
else if ((int)options[opt_idx].indir & PV_BUF)
last_set_msg(curbuf->b_p_scriptID[
(int)options[opt_idx].indir & PV_MASK]);
// Mention where the option was last set.
if (varp == options[opt_idx].var) {
option_last_set_msg(options[opt_idx].last_set);
} else if ((int)options[opt_idx].indir & PV_WIN) {
option_last_set_msg(curwin->w_p_scriptID[
(int)options[opt_idx].indir & PV_MASK]);
} else if ((int)options[opt_idx].indir & PV_BUF) {
option_last_set_msg(curbuf->b_p_scriptID[
(int)options[opt_idx].indir & PV_MASK]);
}
}
} else {
errmsg = (char_u *)N_("E846: Key code not set");
@ -3642,16 +3643,19 @@ static void set_option_scriptID_idx(int opt_idx, int opt_flags, int id)
{
int both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0;
int indir = (int)options[opt_idx].indir;
const LastSet last_set = { id, current_channel_id };
/* 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) || (indir & (PV_BUF|PV_WIN)) == 0)
options[opt_idx].scriptID = id;
// 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) || (indir & (PV_BUF|PV_WIN)) == 0) {
options[opt_idx].last_set = last_set;
}
if (both || (opt_flags & OPT_LOCAL)) {
if (indir & PV_BUF)
curbuf->b_p_scriptID[indir & PV_MASK] = id;
else if (indir & PV_WIN)
curwin->w_p_scriptID[indir & PV_MASK] = id;
if (indir & PV_BUF) {
curbuf->b_p_scriptID[indir & PV_MASK] = last_set;
} else if (indir & PV_WIN) {
curwin->w_p_scriptID[indir & PV_MASK] = last_set;
}
}
}

View File

@ -3,6 +3,7 @@
#include "nvim/types.h"
#include "nvim/macros.h" // For EXTERN
#include "eval/typval.h" // For scid_T
// option_defs.h: definition of global variables for settable options
@ -819,4 +820,10 @@ enum {
#define SB_MAX 100000 // Maximum 'scrollback' value.
/// Stores an identifier of a script or channel that last set an option.
typedef struct {
scid_T script_id; /// Script ID or one of SID_* special values.
uint64_t channel_id; /// Only used when script_id is SID_API_CLIENT.
} LastSet;
#endif // NVIM_OPTION_DEFS_H

View File

@ -382,6 +382,21 @@ describe('api', function()
eq(false, status)
ok(err:match('Invalid option name') ~= nil)
end)
it('updates where the option was last set from', function()
nvim('set_option', 'equalalways', false)
local status, rv = pcall(nvim, 'command_output',
'verbose set equalalways?')
eq(true, status)
ok(nil ~= string.find(rv, 'noequalalways\n'..
'\tLast set from API client %(channel id %d+%)'))
nvim('execute_lua', 'vim.api.nvim_set_option("equalalways", true)', {})
status, rv = pcall(nvim, 'command_output',
'verbose set equalalways?')
eq(true, status)
eq(' equalalways\n\tLast set from Lua', rv)
end)
end)
describe('nvim_{get,set}_current_buf, nvim_list_bufs', function()