fix(api): make nil value in nvim_set_option_value clear local value (#16710)

For special options such as 'undolevels' and 'scrolloff', this sets the
local value to the special "unset" value (e.g. -12345 for 'undolevels').
This commit is contained in:
Gregory Anders 2021-12-21 14:20:34 -07:00 committed by GitHub
parent 1b04da52b3
commit 33cd1ba00a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 66 additions and 5 deletions

View File

@ -696,7 +696,17 @@ Object nvim_get_option_value(String name, Dict(option) *opts, Error *err)
rv = INTEGER_OBJ(numval);
break;
case 2:
rv = BOOLEAN_OBJ(!!numval);
switch (numval) {
case 0:
case 1:
rv = BOOLEAN_OBJ(numval);
break;
default:
// Boolean options that return something other than 0 or 1 should return nil. Currently this
// only applies to 'autoread' which uses -1 as a local value to indicate "unset"
rv = NIL;
break;
}
break;
default:
api_set_error(err, kErrorTypeValidation, "unknown option '%s'", name.data);
@ -749,7 +759,7 @@ void nvim_set_option_value(String name, Object value, Dict(option) *opts, Error
stringval = value.data.string.data;
break;
case kObjectTypeNil:
// Do nothing
scope |= OPT_CLEAR;
break;
default:
api_set_error(err, kErrorTypeValidation, "invalid value for option");

View File

@ -5059,6 +5059,9 @@ int get_option_value_strict(char *name, int64_t *numval, char **stringval, int o
/// @param[in] number New value for the number or boolean option.
/// @param[in] string New value for string option.
/// @param[in] opt_flags Flags: OPT_LOCAL, OPT_GLOBAL, or 0 (both).
/// If OPT_CLEAR is set, the value of the option
/// is cleared (the exact semantics of this depend
/// on the option).
///
/// @return NULL on success, error message on error.
char *set_option_value(const char *const name, const long number, const char *const string,
@ -5084,7 +5087,7 @@ char *set_option_value(const char *const name, const long number, const char *co
}
if (flags & P_STRING) {
const char *s = string;
if (s == NULL) {
if (s == NULL || opt_flags & OPT_CLEAR) {
s = "";
}
return set_string_option(opt_idx, s, opt_flags);
@ -5106,10 +5109,23 @@ char *set_option_value(const char *const name, const long number, const char *co
return NULL; // do nothing as we hit an error
}
}
long numval = number;
if (opt_flags & OPT_CLEAR) {
if ((int *)varp == &curbuf->b_p_ar) {
numval = -1;
} else if ((long *)varp == &curbuf->b_p_ul) {
numval = NO_LOCAL_UNDOLEVEL;
} else if ((long *)varp == &curwin->w_p_so || (long *)varp == &curwin->w_p_siso) {
numval = -1;
} else {
char *s = NULL;
(void)get_option_value(name, &numval, (char_u **)&s, OPT_GLOBAL);
}
}
if (flags & P_NUM) {
return set_num_option(opt_idx, varp, number, NULL, 0, opt_flags);
return set_num_option(opt_idx, varp, numval, NULL, 0, opt_flags);
} else {
return set_bool_option(opt_idx, varp, (int)number, opt_flags);
return set_bool_option(opt_idx, varp, (int)numval, opt_flags);
}
}
}

View File

@ -22,6 +22,7 @@ typedef enum {
OPT_ONECOLUMN = 64, ///< list options one per line
OPT_NO_REDRAW = 128, ///< ignore redraw flags on option
OPT_SKIPRTP = 256, ///< "skiprtp" in 'sessionoptions'
OPT_CLEAR = 512, ///< Clear local value of an option.
} OptionFlags;
#ifdef INCLUDE_GENERATED_DECLARATIONS

View File

@ -974,6 +974,40 @@ describe('API', function()
eq('hello', nvim('get_option_value', 'makeprg', {}))
eq('', nvim('get_option_value', 'makeprg', {scope = 'local'}))
end)
it('clears the local value of an option with nil', function()
-- Set global value
nvim('set_option_value', 'shiftwidth', 42, {})
eq(42, nvim('get_option_value', 'shiftwidth', {}))
-- Set local value
nvim('set_option_value', 'shiftwidth', 8, {scope = 'local'})
eq(8, nvim('get_option_value', 'shiftwidth', {}))
eq(8, nvim('get_option_value', 'shiftwidth', {scope = 'local'}))
eq(42, nvim('get_option_value', 'shiftwidth', {scope = 'global'}))
-- Clear value without scope
nvim('set_option_value', 'shiftwidth', NIL, {})
eq(42, nvim('get_option_value', 'shiftwidth', {}))
eq(42, nvim('get_option_value', 'shiftwidth', {scope = 'local'}))
-- Clear value with explicit scope
nvim('set_option_value', 'shiftwidth', 8, {scope = 'local'})
nvim('set_option_value', 'shiftwidth', NIL, {scope = 'local'})
eq(42, nvim('get_option_value', 'shiftwidth', {}))
eq(42, nvim('get_option_value', 'shiftwidth', {scope = 'local'}))
-- Now try with options with a special "local is unset" value (e.g. 'undolevels')
nvim('set_option_value', 'undolevels', 1000, {})
eq(1000, nvim('get_option_value', 'undolevels', {scope = 'local'}))
nvim('set_option_value', 'undolevels', NIL, {scope = 'local'})
eq(-123456, nvim('get_option_value', 'undolevels', {scope = 'local'}))
nvim('set_option_value', 'autoread', true, {})
eq(true, nvim('get_option_value', 'autoread', {scope = 'local'}))
nvim('set_option_value', 'autoread', NIL, {scope = 'local'})
eq(NIL, nvim('get_option_value', 'autoread', {scope = 'local'}))
end)
end)
describe('nvim_{get,set}_current_buf, nvim_list_bufs', function()