refactor(options)!: use OptVal for option defaults #26691

Problem: We use `void *` for option default values, which is confusing and can cause problems with type-correctness. It also doesn't accomodate for multitype options. On top of that, it also leads to default boolean option values not behaving correctly on big endian systems.

Solution: Use `OptVal` for option default values.

BREAKING CHANGE:
- `:set {option}<` removes the local value for all global-local options instead of just string global-local options.
- `:setlocal {option}<` copies the global value to the local value for number and boolean global-local options instead of removing the local value.
This commit is contained in:
Famiu Haque
2024-10-25 20:10:40 +06:00
committed by GitHub
parent 01739d4673
commit b922b7d6d7
9 changed files with 298 additions and 332 deletions

View File

@@ -90,6 +90,12 @@ local function get_flags(o)
return flags
end
--- @param opt_type vim.option_type
--- @return string
local function opt_type_enum(opt_type)
return ('kOptValType%s'):format(lowercase_to_titlecase(opt_type))
end
--- @param o vim.option_meta
--- @return string
local function get_type_flags(o)
@@ -99,7 +105,7 @@ local function get_type_flags(o)
for _, opt_type in ipairs(opt_types) do
assert(type(opt_type) == 'string')
type_flags = ('%s | (1 << kOptValType%s)'):format(type_flags, lowercase_to_titlecase(opt_type))
type_flags = ('%s | (1 << %s)'):format(type_flags, opt_type_enum(opt_type))
end
return type_flags
@@ -125,27 +131,48 @@ local function get_cond(c, base_string)
return cond_string
end
--- @param s string
--- @return string
local static_cstr_as_string = function(s)
return ('{ .data = %s, .size = sizeof(%s) - 1 }'):format(s, s)
end
--- @param v vim.option_value|function
--- @return string
local get_opt_val = function(v)
--- @type vim.option_type
local v_type
if type(v) == 'function' then
v, v_type = v() --[[ @as string, vim.option_type ]]
if v_type == 'string' then
v = static_cstr_as_string(v)
end
else
v_type = type(v) --[[ @as vim.option_type ]]
if v_type == 'boolean' then
v = v and 'true' or 'false'
elseif v_type == 'number' then
v = ('%iL'):format(v)
elseif v_type == 'string' then
v = static_cstr_as_string(cstr(v))
end
end
return ('{ .type = %s, .data.%s = %s }'):format(opt_type_enum(v_type), v_type, v)
end
--- @param d vim.option_value|function
--- @param n string
--- @return string
local get_defaults = function(d, n)
if d == nil then
error("option '" .. n .. "' should have a default value")
end
local value_dumpers = {
['function'] = function(v)
return v()
end,
string = function(v)
return '.string=' .. cstr(v)
end,
boolean = function(v)
return '.boolean=' .. (v and 'true' or 'false')
end,
number = function(v)
return ('.number=%iL'):format(v)
end,
}
return value_dumpers[type(d)](d)
return get_opt_val(d)
end
--- @type [string,string][]
@@ -173,7 +200,7 @@ local function dump_option(i, o)
w(' .var=&' .. o.varname)
elseif o.hidden or o.immutable then
-- Hidden and immutable options can directly point to the default value.
w((' .var=&options[%u].def_val'):format(i - 1))
w((' .var=&options[%u].def_val.data'):format(i - 1))
elseif #o.scope == 1 and o.scope[1] == 'window' then
w(' .var=VAR_WIN')
else
@@ -219,14 +246,16 @@ local function dump_option(i, o)
if o.defaults.condition then
w(get_cond(o.defaults.condition))
end
w(' .def_val' .. get_defaults(o.defaults.if_true, o.full_name))
w(' .def_val=' .. get_defaults(o.defaults.if_true, o.full_name))
if o.defaults.condition then
if o.defaults.if_false then
w('#else')
w(' .def_val' .. get_defaults(o.defaults.if_false, o.full_name))
w(' .def_val=' .. get_defaults(o.defaults.if_false, o.full_name))
end
w('#endif')
end
else
w(' .def_val=NIL_OPTVAL')
end
w(' },')
end