aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/generators/gen_options.lua
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/generators/gen_options.lua')
-rw-r--r--src/nvim/generators/gen_options.lua219
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