aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/generators
diff options
context:
space:
mode:
authorFamiu Haque <famiuhaque@proton.me>2024-11-23 14:22:06 +0600
committerGitHub <noreply@github.com>2024-11-23 08:22:06 +0000
commit8516c2dc1f301c439695629fff771227dbe00d30 (patch)
tree5e052ad234f99cdbfce89b03ba71796a8cd274ef /src/nvim/generators
parent9a681ad09e2add96d47bf3f39cca8029f3bf09df (diff)
downloadrneovim-8516c2dc1f301c439695629fff771227dbe00d30.tar.gz
rneovim-8516c2dc1f301c439695629fff771227dbe00d30.tar.bz2
rneovim-8516c2dc1f301c439695629fff771227dbe00d30.zip
refactor(options): autogenerate valid values and flag enums for options (#31089)
Problem: Option metadata like list of valid values for an option and option flags are not listed in the `options.lua` file and are instead manually defined in C, which means option metadata is split between several places. Solution: Put metadata such as list of valid values for an option and option flags in `options.lua`, and autogenerate the corresponding C variables and enums. Supersedes #28659 Co-authored-by: glepnir <glephunter@gmail.com>
Diffstat (limited to 'src/nvim/generators')
-rw-r--r--src/nvim/generators/gen_options.lua92
1 files changed, 92 insertions, 0 deletions
diff --git a/src/nvim/generators/gen_options.lua b/src/nvim/generators/gen_options.lua
index 02f3ac3257..779b31e7a0 100644
--- a/src/nvim/generators/gen_options.lua
+++ b/src/nvim/generators/gen_options.lua
@@ -1,10 +1,12 @@
local options_file = arg[1]
local options_enum_file = arg[2]
local options_map_file = arg[3]
+local option_vars_file = arg[4]
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 opt_vars_fd = assert(io.open(option_vars_file, 'w'))
local w = function(s)
if s:match('^ %.') then
@@ -24,6 +26,10 @@ local function map_w(s)
opt_map_fd:write(s .. '\n')
end
+local function vars_w(s)
+ opt_vars_fd:write(s .. '\n')
+end
+
--- @module 'nvim.options'
local options = require('options')
local options_meta = options.options
@@ -138,6 +144,92 @@ map_w('static ' .. hashfun)
opt_map_fd:close()
+vars_w('// IWYU pragma: private, include "nvim/option_vars.h"')
+
+-- Generate enums for option flags.
+for _, option in ipairs(options_meta) do
+ if option.flags and (type(option.flags) == 'table' or option.values) then
+ vars_w('')
+ vars_w('typedef enum {')
+
+ local opt_name = lowercase_to_titlecase(option.abbreviation or option.full_name)
+ --- @type table<string,integer>
+ local enum_values
+
+ if type(option.flags) == 'table' then
+ enum_values = option.flags --[[ @as table<string,integer> ]]
+ else
+ enum_values = {}
+ for i, flag_name in ipairs(option.values) do
+ assert(type(flag_name) == 'string')
+ enum_values[flag_name] = math.pow(2, i - 1)
+ end
+ end
+
+ -- Sort the keys by the flag value so that the enum can be generated in order.
+ --- @type string[]
+ local flag_names = vim.tbl_keys(enum_values)
+ table.sort(flag_names, function(a, b)
+ return enum_values[a] < enum_values[b]
+ end)
+
+ for _, flag_name in pairs(flag_names) do
+ vars_w(
+ (' kOpt%sFlag%s = 0x%02x,'):format(
+ opt_name,
+ lowercase_to_titlecase(flag_name),
+ enum_values[flag_name]
+ )
+ )
+ end
+
+ vars_w(('} Opt%sFlags;'):format(opt_name))
+ end
+end
+
+-- Generate valid values for each option.
+for _, option in ipairs(options_meta) do
+ --- @type function
+ local preorder_traversal
+ --- @param prefix string
+ --- @param values vim.option_valid_values
+ preorder_traversal = function(prefix, values)
+ vars_w('')
+ vars_w(
+ ('EXTERN const char *(%s_values[%s]) INIT( = {'):format(prefix, #vim.tbl_keys(values) + 1)
+ )
+
+ --- @type [string,vim.option_valid_values][]
+ local children = {}
+
+ for _, value in ipairs(values) do
+ if type(value) == 'string' then
+ vars_w((' "%s",'):format(value))
+ else
+ assert(type(value) == 'table' and type(value[1]) == 'string' and type(value[2]) == 'table')
+
+ vars_w((' "%s",'):format(value[1]))
+ table.insert(children, value)
+ end
+ end
+
+ vars_w(' NULL')
+ vars_w('});')
+
+ for _, value in pairs(children) do
+ -- Remove trailing colon from the added prefix to prevent syntax errors.
+ preorder_traversal(prefix .. '_' .. value[1]:gsub(':$', ''), value[2])
+ end
+ end
+
+ -- Since option values can be nested, we need to do preorder traversal to generate the values.
+ if option.values then
+ preorder_traversal(('opt_%s'):format(option.abbreviation or option.full_name), option.values)
+ end
+end
+
+opt_vars_fd:close()
+
local redraw_flags = {
ui_option = 'kOptFlagUIOption',
tabline = 'kOptFlagRedrTabl',