diff options
Diffstat (limited to 'src/nvim/generators/gen_options.lua')
-rw-r--r-- | src/nvim/generators/gen_options.lua | 219 |
1 files changed, 174 insertions, 45 deletions
diff --git a/src/nvim/generators/gen_options.lua b/src/nvim/generators/gen_options.lua index 92349b5298..02f3ac3257 100644 --- a/src/nvim/generators/gen_options.lua +++ b/src/nvim/generators/gen_options.lua @@ -1,6 +1,10 @@ local options_file = arg[1] +local options_enum_file = arg[2] +local options_map_file = arg[3] local opt_fd = assert(io.open(options_file, 'w')) +local opt_enum_fd = assert(io.open(options_enum_file, 'w')) +local opt_map_fd = assert(io.open(options_map_file, 'w')) local w = function(s) if s:match('^ %.') then @@ -10,10 +14,129 @@ local w = function(s) end end +--- @param s string +local function enum_w(s) + opt_enum_fd:write(s .. '\n') +end + +--- @param s string +local function map_w(s) + opt_map_fd:write(s .. '\n') +end + --- @module 'nvim.options' local options = require('options') +local options_meta = options.options local cstr = options.cstr +local valid_scopes = options.valid_scopes + +--- Options for each scope. +--- @type table<string, vim.option_meta[]> +local scope_options = {} +for _, scope in ipairs(valid_scopes) do + scope_options[scope] = {} +end + +--- @param s string +--- @return string +local lowercase_to_titlecase = function(s) + return s:sub(1, 1):upper() .. s:sub(2) +end + +-- Generate options enum file +enum_w('// IWYU pragma: private, include "nvim/option_defs.h"') +enum_w('') + +--- Map of option name to option index +--- @type table<string, string> +local option_index = {} + +-- Generate option index enum and populate the `option_index` and `scope_option` dicts. +enum_w('typedef enum {') +enum_w(' kOptInvalid = -1,') + +for i, o in ipairs(options_meta) do + local enum_val_name = 'kOpt' .. lowercase_to_titlecase(o.full_name) + enum_w((' %s = %u,'):format(enum_val_name, i - 1)) + + option_index[o.full_name] = enum_val_name + + if o.abbreviation then + option_index[o.abbreviation] = enum_val_name + end + + if o.alias then + o.alias = type(o.alias) == 'string' and { o.alias } or o.alias + + for _, v in ipairs(o.alias) do + option_index[v] = enum_val_name + end + end + + for _, scope in ipairs(o.scope) do + table.insert(scope_options[scope], o) + end +end + +enum_w(' // Option count') +enum_w('#define kOptCount ' .. tostring(#options_meta)) +enum_w('} OptIndex;') + +--- @param scope string +--- @param option_name string +--- @return string +local get_scope_option = function(scope, option_name) + return ('k%sOpt%s'):format(lowercase_to_titlecase(scope), lowercase_to_titlecase(option_name)) +end + +-- Generate option index enum for each scope +for _, scope in ipairs(valid_scopes) do + enum_w('') + + local scope_name = lowercase_to_titlecase(scope) + enum_w('typedef enum {') + enum_w((' %s = -1,'):format(get_scope_option(scope, 'Invalid'))) + + for idx, option in ipairs(scope_options[scope]) do + enum_w((' %s = %u,'):format(get_scope_option(scope, option.full_name), idx - 1)) + end + + enum_w((' // %s option count'):format(scope_name)) + enum_w(('#define %s %d'):format(get_scope_option(scope, 'Count'), #scope_options[scope])) + enum_w(('} %sOptIndex;'):format(scope_name)) +end + +-- Generate reverse lookup from option scope index to option index for each scope. +for _, scope in ipairs(valid_scopes) do + enum_w('') + enum_w(('EXTERN const OptIndex %s_opt_idx[] INIT( = {'):format(scope)) + for _, option in ipairs(scope_options[scope]) do + local idx = option_index[option.full_name] + enum_w((' [%s] = %s,'):format(get_scope_option(scope, option.full_name), idx)) + end + enum_w('});') +end + +opt_enum_fd:close() + +-- Generate option index map. +local hashy = require('generators.hashy') +local neworder, hashfun = hashy.hashy_hash('find_option', vim.tbl_keys(option_index), function(idx) + return ('option_hash_elems[%s].name'):format(idx) +end) + +map_w('static const struct { const char *name; OptIndex opt_idx; } option_hash_elems[] = {') + +for _, name in ipairs(neworder) do + assert(option_index[name] ~= nil) + map_w((' { .name = "%s", .opt_idx = %s },'):format(name, option_index[name])) +end + +map_w('};\n') +map_w('static ' .. hashfun) + +opt_map_fd:close() local redraw_flags = { ui_option = 'kOptFlagUIOption', @@ -35,12 +158,6 @@ local list_flags = { flagscomma = 'kOptFlagComma|kOptFlagFlagList', } ---- @param s string ---- @return string -local lowercase_to_titlecase = function(s) - return s:sub(1, 1):upper() .. s:sub(2) -end - --- @param o vim.option_meta --- @return string local function get_flags(o) @@ -95,6 +212,12 @@ local function opt_type_enum(opt_type) return ('kOptValType%s'):format(lowercase_to_titlecase(opt_type)) end +--- @param scope vim.option_scope +--- @return string +local function opt_scope_enum(scope) + return ('kOptScope%s'):format(lowercase_to_titlecase(scope)) +end + --- @param o vim.option_meta --- @return string local function get_type_flags(o) @@ -110,6 +233,35 @@ local function get_type_flags(o) return type_flags end +--- @param o vim.option_meta +--- @return string +local function get_scope_flags(o) + local scope_flags = '0' + + for _, scope in ipairs(o.scope) do + scope_flags = ('%s | (1 << %s)'):format(scope_flags, opt_scope_enum(scope)) + end + + return scope_flags +end + +--- @param o vim.option_meta +--- @return string +local function get_scope_idx(o) + --- @type string[] + local strs = {} + + for _, scope in pairs(valid_scopes) do + local has_scope = vim.tbl_contains(o.scope, scope) + strs[#strs + 1] = (' [%s] = %s'):format( + opt_scope_enum(scope), + get_scope_option(scope, has_scope and o.full_name or 'Invalid') + ) + end + + return ('{\n%s\n }'):format(table.concat(strs, ',\n')) +end + --- @param c string|string[] --- @param base_string? string --- @return string @@ -166,7 +318,6 @@ 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") @@ -174,9 +325,6 @@ local get_defaults = function(d, n) return get_opt_val(d) end ---- @type [string,string][] -local defines = {} - --- @param i integer --- @param o vim.option_meta local function dump_option(i, o) @@ -187,42 +335,28 @@ local function dump_option(i, o) end w(' .flags=' .. get_flags(o)) w(' .type_flags=' .. get_type_flags(o)) + w(' .scope_flags=' .. get_scope_flags(o)) + w(' .scope_idx=' .. get_scope_idx(o)) if o.enable_if then w(get_cond(o.enable_if)) end - if o.varname then - w(' .var=&' .. o.varname) - elseif o.immutable then - -- Immutable options can directly point to the default value. - w((' .var=&options[%u].def_val.data'):format(i - 1)) - elseif #o.scope == 1 and o.scope[1] == 'window' then - w(' .var=VAR_WIN') + local is_window_local = #o.scope == 1 and o.scope[1] == 'win' + + if not is_window_local then + if o.varname then + w(' .var=&' .. o.varname) + elseif o.immutable then + -- Immutable options can directly point to the default value. + w((' .var=&options[%u].def_val.data'):format(i - 1)) + else + -- Option must be immutable or have a variable. + assert(false) + end else - -- Option must be immutable or have a variable. - assert(false) + w(' .var=NULL') end w(' .immutable=' .. (o.immutable and 'true' or 'false')) - if #o.scope == 1 and o.scope[1] == 'global' then - w(' .indir=PV_NONE') - else - assert(#o.scope == 1 or #o.scope == 2) - assert(#o.scope == 1 or o.scope[1] == 'global') - local min_scope = o.scope[#o.scope] - local varname = o.pv_name or o.varname or ('p_' .. (o.abbreviation or o.full_name)) - local pv_name = ( - 'OPT_' - .. min_scope:sub(1, 3):upper() - .. '(' - .. (min_scope:sub(1, 1):upper() .. 'V_' .. varname:sub(3):upper()) - .. ')' - ) - if #o.scope == 2 then - pv_name = 'OPT_BOTH(' .. pv_name .. ')' - end - table.insert(defines, { 'PV_' .. varname:sub(3):upper(), pv_name }) - w(' .indir=' .. pv_name) - end if o.cb then w(' .opt_did_set_cb=' .. o.cb) end @@ -235,7 +369,6 @@ local function dump_option(i, o) w((' .var=&options[%u].def_val.data'):format(i - 1)) -- Option is always immutable on the false branch of `enable_if`. w(' .immutable=true') - w(' .indir=PV_NONE') w('#endif') end if o.defaults then @@ -256,6 +389,7 @@ local function dump_option(i, o) w(' },') end +-- Generate options[] array. w([[ #include "nvim/ex_docmd.h" #include "nvim/ex_getln.h" @@ -274,8 +408,3 @@ for i, o in ipairs(options.options) do dump_option(i, o) end w('};') -w('') - -for _, v in ipairs(defines) do - w('#define ' .. v[1] .. ' ' .. v[2]) -end |