diff options
author | Josh Rahm <joshuarahm@gmail.com> | 2024-11-25 19:15:05 +0000 |
---|---|---|
committer | Josh Rahm <joshuarahm@gmail.com> | 2024-11-25 19:27:38 +0000 |
commit | c5d770d311841ea5230426cc4c868e8db27300a8 (patch) | |
tree | dd21f70127b4b8b5f109baefc8ecc5016f507c91 /src/nvim/generators | |
parent | 9be89f131f87608f224f0ee06d199fcd09d32176 (diff) | |
parent | 081beb3659bd6d8efc3e977a160b1e72becbd8a2 (diff) | |
download | rneovim-c5d770d311841ea5230426cc4c868e8db27300a8.tar.gz rneovim-c5d770d311841ea5230426cc4c868e8db27300a8.tar.bz2 rneovim-c5d770d311841ea5230426cc4c868e8db27300a8.zip |
Merge remote-tracking branch 'upstream/master' into mix_20240309
Diffstat (limited to 'src/nvim/generators')
-rw-r--r-- | src/nvim/generators/gen_api_dispatch.lua | 2 | ||||
-rw-r--r-- | src/nvim/generators/gen_api_ui_events.lua | 4 | ||||
-rw-r--r-- | src/nvim/generators/gen_options.lua | 347 | ||||
-rw-r--r-- | src/nvim/generators/gen_options_enum.lua | 129 |
4 files changed, 254 insertions, 228 deletions
diff --git a/src/nvim/generators/gen_api_dispatch.lua b/src/nvim/generators/gen_api_dispatch.lua index 9e0aa407a1..a78f746fee 100644 --- a/src/nvim/generators/gen_api_dispatch.lua +++ b/src/nvim/generators/gen_api_dispatch.lua @@ -750,7 +750,7 @@ local function process_function(fn) write_shifted_output( [[ if (!nlua_is_deferred_safe()) { - return luaL_error(lstate, e_luv_api_disabled, "%s"); + return luaL_error(lstate, e_fast_api_disabled, "%s"); } ]], fn.name diff --git a/src/nvim/generators/gen_api_ui_events.lua b/src/nvim/generators/gen_api_ui_events.lua index 3e8ae19c9a..30a83330eb 100644 --- a/src/nvim/generators/gen_api_ui_events.lua +++ b/src/nvim/generators/gen_api_ui_events.lua @@ -136,8 +136,8 @@ for i = 1, #events do call_output:write(' }\n') call_output:write(' entered = true;\n') write_arglist(call_output, ev) - call_output:write(' ui_call_event("' .. ev.name .. '", ' .. args .. ');\n') - call_output:write(' entered = false;\n') + call_output:write((' ui_call_event("%s", %s, %s)'):format(ev.name, tostring(ev.fast), args)) + call_output:write(';\n entered = false;\n') elseif ev.compositor_impl then call_output:write(' ui_comp_' .. ev.name) write_signature(call_output, ev, '', true) diff --git a/src/nvim/generators/gen_options.lua b/src/nvim/generators/gen_options.lua index 591a6b93df..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,30 +14,29 @@ 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 -local redraw_flags = { - ui_option = 'P_UI_OPTION', - tabline = 'P_RTABL', - statuslines = 'P_RSTAT', - current_window = 'P_RWIN', - current_buffer = 'P_RBUF', - all_windows = 'P_RALL', - curswant = 'P_CURSWANT', - highlight_only = 'P_HLONLY', -} - -local list_flags = { - comma = 'P_COMMA', - onecomma = 'P_ONECOMMA', - commacolon = 'P_COMMA|P_COLON', - onecommacolon = 'P_ONECOMMA|P_COLON', - flags = 'P_FLAGLIST', - flagscomma = 'P_COMMA|P_FLAGLIST', -} +--- 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 @@ -41,6 +44,120 @@ 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', + tabline = 'kOptFlagRedrTabl', + statuslines = 'kOptFlagRedrStat', + current_window = 'kOptFlagRedrWin', + current_buffer = 'kOptFlagRedrBuf', + all_windows = 'kOptFlagRedrAll', + curswant = 'kOptFlagCurswant', + highlight_only = 'kOptFlagHLOnly', +} + +local list_flags = { + comma = 'kOptFlagComma', + onecomma = 'kOptFlagOneComma', + commacolon = 'kOptFlagComma|kOptFlagColon', + onecommacolon = 'kOptFlagOneComma|kOptFlagColon', + flags = 'kOptFlagFlagList', + flagscomma = 'kOptFlagComma|kOptFlagFlagList', +} + --- @param o vim.option_meta --- @return string local function get_flags(o) @@ -61,28 +178,27 @@ local function get_flags(o) end end if o.expand then - add_flag('P_EXPAND') + add_flag('kOptFlagExpand') if o.expand == 'nodefault' then - add_flag('P_NO_DEF_EXP') + add_flag('kOptFlagNoDefExp') end end for _, flag_desc in ipairs({ - { 'alloced' }, - { 'nodefault' }, - { 'no_mkrc' }, + { 'nodefault', 'NoDefault' }, + { 'no_mkrc', 'NoMkrc' }, { 'secure' }, { 'gettext' }, - { 'noglob' }, - { 'normal_fname_chars', 'P_NFNAME' }, - { 'normal_dname_chars', 'P_NDNAME' }, - { 'pri_mkrc' }, - { 'deny_in_modelines', 'P_NO_ML' }, - { 'deny_duplicates', 'P_NODUP' }, - { 'modelineexpr', 'P_MLE' }, + { 'noglob', 'NoGlob' }, + { 'normal_fname_chars', 'NFname' }, + { 'normal_dname_chars', 'NDname' }, + { 'pri_mkrc', 'PriMkrc' }, + { 'deny_in_modelines', 'NoML' }, + { 'deny_duplicates', 'NoDup' }, + { 'modelineexpr', 'MLE' }, { 'func' }, }) do local key_name = flag_desc[1] - local def_name = flag_desc[2] or ('P_' .. key_name:upper()) + local def_name = 'kOptFlag' .. (flag_desc[2] or lowercase_to_titlecase(key_name)) if o[key_name] then add_flag(def_name) end @@ -90,6 +206,18 @@ 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 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) @@ -99,12 +227,41 @@ 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 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 @@ -125,32 +282,49 @@ 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][] -local defines = {} - --- @param i integer --- @param o vim.option_meta local function dump_option(i, o) @@ -161,48 +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 - -- An option cannot be both hidden and immutable. - assert(not o.hidden or not o.immutable) + local is_window_local = #o.scope == 1 and o.scope[1] == 'win' - local has_var = true - if o.varname then - 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)) - elseif #o.scope == 1 and o.scope[1] == 'window' then - w(' .var=VAR_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 - has_var = false + w(' .var=NULL') end - -- `enable_if = false` should be present iff there is no variable. - assert((o.enable_if == false) == not has_var) - w(' .hidden=' .. (o.hidden and 'true' or 'false')) 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 @@ -211,27 +365,33 @@ local function dump_option(i, o) end if o.enable_if then w('#else') - w(' .var=NULL') - w(' .indir=PV_NONE') + -- Hidden option directly points to default value. + 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('#endif') end if o.defaults then 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 +-- Generate options[] array. w([[ +#include "nvim/ex_docmd.h" #include "nvim/ex_getln.h" #include "nvim/insexpand.h" #include "nvim/mapping.h" @@ -248,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 diff --git a/src/nvim/generators/gen_options_enum.lua b/src/nvim/generators/gen_options_enum.lua deleted file mode 100644 index d1419137d3..0000000000 --- a/src/nvim/generators/gen_options_enum.lua +++ /dev/null @@ -1,129 +0,0 @@ --- Generates option index enum and map of option name to option index. --- Handles option full name, short name and aliases. --- Also generates BV_ and WV_ enum constants. - -local options_enum_file = arg[1] -local options_map_file = arg[2] -local options_enum_fd = assert(io.open(options_enum_file, 'w')) -local options_map_fd = assert(io.open(options_map_file, 'w')) - ---- @param s string -local function enum_w(s) - options_enum_fd:write(s .. '\n') -end - ---- @param s string -local function map_w(s) - options_map_fd:write(s .. '\n') -end - -enum_w('// IWYU pragma: private, include "nvim/option_defs.h"') -enum_w('') - ---- @param s string ---- @return string -local lowercase_to_titlecase = function(s) - return s:sub(1, 1):upper() .. s:sub(2) -end - ---- @type vim.option_meta[] -local options = require('options').options - --- Generate BV_ enum constants. -enum_w('/// "indir" values for buffer-local options.') -enum_w('/// These need to be defined globally, so that the BV_COUNT can be used with') -enum_w('/// b_p_script_stx[].') -enum_w('enum {') - -local bv_val = 0 - -for _, o in ipairs(options) do - assert(#o.scope == 1 or #o.scope == 2) - assert(#o.scope == 1 or o.scope[1] == 'global') - local min_scope = o.scope[#o.scope] - if min_scope == 'buffer' then - local varname = o.pv_name or o.varname or ('p_' .. (o.abbreviation or o.full_name)) - local bv_name = 'BV_' .. varname:sub(3):upper() - enum_w((' %s = %u,'):format(bv_name, bv_val)) - bv_val = bv_val + 1 - end -end - -enum_w((' BV_COUNT = %u, ///< must be the last one'):format(bv_val)) -enum_w('};') -enum_w('') - --- Generate WV_ enum constants. -enum_w('/// "indir" values for window-local options.') -enum_w('/// These need to be defined globally, so that the WV_COUNT can be used in the') -enum_w('/// window structure.') -enum_w('enum {') - -local wv_val = 0 - -for _, o in ipairs(options) do - assert(#o.scope == 1 or #o.scope == 2) - assert(#o.scope == 1 or o.scope[1] == 'global') - local min_scope = o.scope[#o.scope] - if min_scope == 'window' then - local varname = o.pv_name or o.varname or ('p_' .. (o.abbreviation or o.full_name)) - local wv_name = 'WV_' .. varname:sub(3):upper() - enum_w((' %s = %u,'):format(wv_name, wv_val)) - wv_val = wv_val + 1 - end -end - -enum_w((' WV_COUNT = %u, ///< must be the last one'):format(wv_val)) -enum_w('};') -enum_w('') - ---- @type { [string]: string } -local option_index = {} - --- Generate option index enum and populate the `option_index` dict. -enum_w('typedef enum {') -enum_w(' kOptInvalid = -1,') - -for i, o in ipairs(options) 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 -end - -enum_w(' // Option count, used when iterating through options') -enum_w('#define kOptIndexCount ' .. tostring(#options)) -enum_w('} OptIndex;') -enum_w('') - -options_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) - -options_map_fd:close() |