diff options
| author | Lewis Russell <lewis6991@gmail.com> | 2025-02-26 11:38:07 +0000 |
|---|---|---|
| committer | Lewis Russell <me@lewisr.dev> | 2025-02-26 16:54:37 +0000 |
| commit | 0f24b0826a27b7868a3aacc25199787e7453d4cc (patch) | |
| tree | 49585aac252581a735577f2e5711201a85ab8a7e /src/nvim/generators | |
| parent | 85caaa70d44b7b18c633aa0b140de5f3f6d3eee7 (diff) | |
| download | rneovim-0f24b0826a27b7868a3aacc25199787e7453d4cc.tar.gz rneovim-0f24b0826a27b7868a3aacc25199787e7453d4cc.tar.bz2 rneovim-0f24b0826a27b7868a3aacc25199787e7453d4cc.zip | |
build: move all generator scripts to `src/gen/`
- Move all generator Lua scripts to the `src/gen/`
- Add a `.luarc.json` to `src/gen/`
- Add a `preload.lua` to `src/gen/`
- Add `src` to `package.path` so it aligns with `.luarc.json'
- Fix all `require` statements in `src/gen/` so they are consistent:
- `require('scripts.foo')` -> `require('gen.foo')`
- `require('src.nvim.options')` -> `require('nvim.options')`
- `require('api.dispatch_deprecated')` -> `require('nvim.api.dispatch_deprecated')`
Diffstat (limited to 'src/nvim/generators')
| -rw-r--r-- | src/nvim/generators/c_grammar.lua | 300 | ||||
| -rw-r--r-- | src/nvim/generators/dump_bin_array.lua | 17 | ||||
| -rw-r--r-- | src/nvim/generators/gen_api_dispatch.lua | 990 | ||||
| -rw-r--r-- | src/nvim/generators/gen_api_ui_events.lua | 219 | ||||
| -rw-r--r-- | src/nvim/generators/gen_char_blob.lua | 96 | ||||
| -rw-r--r-- | src/nvim/generators/gen_declarations.lua | 186 | ||||
| -rw-r--r-- | src/nvim/generators/gen_eval.lua | 112 | ||||
| -rw-r--r-- | src/nvim/generators/gen_events.lua | 42 | ||||
| -rw-r--r-- | src/nvim/generators/gen_ex_cmds.lua | 194 | ||||
| -rw-r--r-- | src/nvim/generators/gen_options.lua | 535 | ||||
| -rw-r--r-- | src/nvim/generators/gen_vimvim.lua | 156 | ||||
| -rw-r--r-- | src/nvim/generators/hashy.lua | 145 | ||||
| -rw-r--r-- | src/nvim/generators/nvim_version.lua.in | 9 | ||||
| -rw-r--r-- | src/nvim/generators/preload.lua | 13 |
14 files changed, 0 insertions, 3014 deletions
diff --git a/src/nvim/generators/c_grammar.lua b/src/nvim/generators/c_grammar.lua deleted file mode 100644 index 890c260843..0000000000 --- a/src/nvim/generators/c_grammar.lua +++ /dev/null @@ -1,300 +0,0 @@ --- lpeg grammar for building api metadata from a set of header files. It --- ignores comments and preprocessor commands and parses a very small subset --- of C prototypes with a limited set of types - ---- @class nvim.c_grammar.Proto ---- @field [1] 'proto' ---- @field pos integer ---- @field endpos integer ---- @field fast boolean ---- @field name string ---- @field return_type string ---- @field parameters [string, string][] ---- @field static true? ---- @field inline true? - ---- @class nvim.c_grammar.Preproc ---- @field [1] 'preproc' ---- @field content string - ---- @class nvim.c_grammar.Empty ---- @field [1] 'empty' - ---- @alias nvim.c_grammar.result ---- | nvim.c_grammar.Proto ---- | nvim.c_grammar.Preproc ---- | nvim.c_grammar.Empty - ---- @class nvim.c_grammar ---- @field match fun(self, input: string): nvim.c_grammar.result[] - -local lpeg = vim.lpeg - -local P, R, S, V = lpeg.P, lpeg.R, lpeg.S, lpeg.V -local C, Ct, Cc, Cg, Cp = lpeg.C, lpeg.Ct, lpeg.Cc, lpeg.Cg, lpeg.Cp - ---- @param pat vim.lpeg.Pattern -local function rep(pat) - return pat ^ 0 -end - ---- @param pat vim.lpeg.Pattern -local function rep1(pat) - return pat ^ 1 -end - ---- @param pat vim.lpeg.Pattern -local function opt(pat) - return pat ^ -1 -end - -local any = P(1) -local letter = R('az', 'AZ') + S('_$') -local num = R('09') -local alpha = letter + num -local nl = P('\r\n') + P('\n') -local space = S(' \t') -local str = P('"') * rep((P('\\') * any) + (1 - P('"'))) * P('"') -local char = P("'") * (any - P("'")) * P("'") -local ws = space + nl -local wb = #-alpha -- word boundary -local id = letter * rep(alpha) - -local comment_inline = P('/*') * rep(1 - P('*/')) * P('*/') -local comment = P('//') * rep(1 - nl) * nl -local preproc = Ct(Cc('preproc') * P('#') * Cg(rep(1 - nl) * nl, 'content')) - -local fill = rep(ws + comment_inline + comment + preproc) - ---- @param s string ---- @return vim.lpeg.Pattern -local function word(s) - return fill * P(s) * wb * fill -end - ---- @param x vim.lpeg.Pattern -local function comma1(x) - return x * rep(fill * P(',') * fill * x) -end - ---- @param v string -local function Pf(v) - return fill * P(v) * fill -end - ---- @param x vim.lpeg.Pattern -local function paren(x) - return P('(') * fill * x * fill * P(')') -end - -local cdoc_comment = P('///') * opt(Ct(Cg(rep(space) * rep(1 - nl), 'comment'))) - -local braces = P({ - 'S', - A = comment_inline + comment + preproc + str + char + (any - S('{}')), - S = P('{') * rep(V('A')) * rep(V('S') + V('A')) * P('}'), -}) - --- stylua: ignore start -local typed_container = P({ - 'S', - S = ( - (P('Union') * paren(comma1(V('ID')))) - + (P('ArrayOf') * paren(id * opt(P(',') * fill * rep1(num)))) - + (P('DictOf') * paren(id)) - + (P('LuaRefOf') * paren( - paren(comma1((V('ID') + str) * rep1(ws) * opt(P('*')) * id)) - * opt(P(',') * fill * opt(P('*')) * V('ID')) - )) - + (P('Dict') * paren(id))), - ID = V('S') + id, -}) --- stylua: ignore end - -local ptr_mod = word('restrict') + word('__restrict') + word('const') -local opt_ptr = rep(Pf('*') * opt(ptr_mod)) - ---- @param name string ---- @param var string ---- @return vim.lpeg.Pattern -local function attr(name, var) - return Cg((P(name) * Cc(true)), var) -end - ---- @param name string ---- @param var string ---- @return vim.lpeg.Pattern -local function attr_num(name, var) - return Cg((P(name) * paren(C(rep1(num)))), var) -end - -local fattr = ( - attr_num('FUNC_API_SINCE', 'since') - + attr_num('FUNC_API_DEPRECATED_SINCE', 'deprecated_since') - + attr('FUNC_API_FAST', 'fast') - + attr('FUNC_API_RET_ALLOC', 'ret_alloc') - + attr('FUNC_API_NOEXPORT', 'noexport') - + attr('FUNC_API_REMOTE_ONLY', 'remote_only') - + attr('FUNC_API_LUA_ONLY', 'lua_only') - + attr('FUNC_API_TEXTLOCK_ALLOW_CMDWIN', 'textlock_allow_cmdwin') - + attr('FUNC_API_TEXTLOCK', 'textlock') - + attr('FUNC_API_REMOTE_IMPL', 'remote_impl') - + attr('FUNC_API_COMPOSITOR_IMPL', 'compositor_impl') - + attr('FUNC_API_CLIENT_IMPL', 'client_impl') - + attr('FUNC_API_CLIENT_IGNORE', 'client_ignore') - + (P('FUNC_') * rep(alpha) * opt(fill * paren(rep(1 - P(')') * any)))) -) - -local void = P('void') * wb - -local api_param_type = ( - (word('Error') * opt_ptr * Cc('error')) - + (word('Arena') * opt_ptr * Cc('arena')) - + (word('lua_State') * opt_ptr * Cc('lstate')) -) - -local ctype = C( - opt(word('const')) - * ( - typed_container - -- 'unsigned' is a type modifier, and a type itself - + (word('unsigned char') + word('unsigned')) - + (word('struct') * fill * id) - + id - ) - * opt(word('const')) - * opt_ptr -) - -local return_type = (C(void) * fill) + ctype - --- stylua: ignore start -local params = Ct( - (void * #P(')')) - + comma1(Ct( - (api_param_type + ctype) - * fill - * C(id) - * rep(Pf('[') * rep(alpha) * Pf(']')) - * rep(fill * fattr) - )) - * opt(Pf(',') * P('...')) -) --- stylua: ignore end - -local ignore_line = rep1(1 - nl) * nl -local empty_line = Ct(Cc('empty') * nl * nl) - -local proto_name = opt_ptr * fill * id - --- __inline is used in MSVC -local decl_mod = ( - Cg(word('static') * Cc(true), 'static') - + Cg((word('inline') + word('__inline')) * Cc(true), 'inline') -) - -local proto = Ct( - Cg(Cp(), 'pos') - * Cc('proto') - * -#P('typedef') - * #alpha - * opt(P('DLLEXPORT') * rep1(ws)) - * rep(decl_mod) - * Cg(return_type, 'return_type') - * fill - * Cg(proto_name, 'name') - * fill - * paren(Cg(params, 'parameters')) - * Cg(Cc(false), 'fast') - * rep(fill * fattr) - * Cg(Cp(), 'endpos') - * (fill * (S(';') + braces)) -) - -local keyset_field = Ct( - Cg(ctype, 'type') - * fill - * Cg(id, 'name') - * fill - * opt(P('DictKey') * paren(Cg(rep1(1 - P(')')), 'dict_key'))) - * Pf(';') -) - -local keyset = Ct( - P('typedef') - * word('struct') - * Pf('{') - * Cg(Ct(rep1(keyset_field)), 'fields') - * Pf('}') - * P('Dict') - * paren(Cg(id, 'keyset_name')) - * Pf(';') -) - -local grammar = - Ct(rep1(empty_line + proto + cdoc_comment + comment + preproc + ws + keyset + ignore_line)) - -if arg[1] == '--test' then - for i, t in ipairs({ - 'void multiqueue_put_event(MultiQueue *self, Event event) {} ', - 'void *xmalloc(size_t size) {} ', - { - 'struct tm *os_localtime_r(const time_t *restrict clock,', - ' struct tm *restrict result) FUNC_ATTR_NONNULL_ALL {}', - }, - { - '_Bool', - '# 163 "src/nvim/event/multiqueue.c"', - ' multiqueue_empty(MultiQueue *self)', - '{}', - }, - 'const char *find_option_end(const char *arg, OptIndex *opt_idxp) {}', - 'bool semsg(const char *const fmt, ...) {}', - 'int32_t utf_ptr2CharInfo_impl(uint8_t const *p, uintptr_t const len) {}', - 'void ex_argdedupe(exarg_T *eap FUNC_ATTR_UNUSED) {}', - 'static TermKeySym register_c0(TermKey *tk, TermKeySym sym, unsigned char ctrl, const char *name) {}', - 'unsigned get_bkc_flags(buf_T *buf) {}', - 'char *xstpcpy(char *restrict dst, const char *restrict src) {}', - 'bool try_leave(const TryState *const tstate, Error *const err) {}', - 'void api_set_error(ErrorType errType) {}', - { - 'void nvim_subscribe(uint64_t channel_id, String event)', - 'FUNC_API_SINCE(1) FUNC_API_DEPRECATED_SINCE(13) FUNC_API_REMOTE_ONLY', - '{}', - }, - - -- Do not consume leading preproc statements - { - '#line 1 "D:/a/neovim/neovim/src\\nvim/mark.h"', - 'static __inline int mark_global_index(const char name)', - ' FUNC_ATTR_CONST', - '{}', - }, - { - '', - '#line 1 "D:/a/neovim/neovim/src\\nvim/mark.h"', - 'static __inline int mark_global_index(const char name)', - '{}', - }, - { - 'size_t xstrlcpy(char *__restrict dst, const char *__restrict src, size_t dsize)', - ' FUNC_ATTR_NONNULL_ALL', - ' {}', - }, - }) do - if type(t) == 'table' then - t = table.concat(t, '\n') .. '\n' - end - t = t:gsub(' +', ' ') - local r = grammar:match(t) - if not r then - print('Test ' .. i .. ' failed') - print(' |' .. table.concat(vim.split(t, '\n'), '\n |')) - end - end -end - -return { - grammar = grammar --[[@as nvim.c_grammar]], - typed_container = typed_container, -} diff --git a/src/nvim/generators/dump_bin_array.lua b/src/nvim/generators/dump_bin_array.lua deleted file mode 100644 index c6cda25e73..0000000000 --- a/src/nvim/generators/dump_bin_array.lua +++ /dev/null @@ -1,17 +0,0 @@ -local function dump_bin_array(output, name, data) - output:write([[ - static const uint8_t ]] .. name .. [[[] = { -]]) - - for i = 1, #data do - output:write(string.byte(data, i) .. ', ') - if i % 10 == 0 then - output:write('\n ') - end - end - output:write([[ -}; -]]) -end - -return dump_bin_array diff --git a/src/nvim/generators/gen_api_dispatch.lua b/src/nvim/generators/gen_api_dispatch.lua deleted file mode 100644 index 378297d86a..0000000000 --- a/src/nvim/generators/gen_api_dispatch.lua +++ /dev/null @@ -1,990 +0,0 @@ --- Example (manual) invocation: --- --- make --- cp build/nvim_version.lua src/nvim/ --- cd src/nvim --- nvim -l generators/gen_api_dispatch.lua "../../build/src/nvim/auto/api/private/dispatch_wrappers.generated.h" "../../build/src/nvim/auto/api/private/api_metadata.generated.h" "../../build/funcs_metadata.mpack" "../../build/src/nvim/auto/lua_api_c_bindings.generated.h" "../../build/src/nvim/auto/keysets_defs.generated.h" "../../build/ui_metadata.mpack" "../../build/cmake.config/auto/versiondef_git.h" "./api/autocmd.h" "./api/buffer.h" "./api/command.h" "./api/deprecated.h" "./api/extmark.h" "./api/keysets_defs.h" "./api/options.h" "./api/tabpage.h" "./api/ui.h" "./api/vim.h" "./api/vimscript.h" "./api/win_config.h" "./api/window.h" "../../build/include/api/autocmd.h.generated.h" "../../build/include/api/buffer.h.generated.h" "../../build/include/api/command.h.generated.h" "../../build/include/api/deprecated.h.generated.h" "../../build/include/api/extmark.h.generated.h" "../../build/include/api/options.h.generated.h" "../../build/include/api/tabpage.h.generated.h" "../../build/include/api/ui.h.generated.h" "../../build/include/api/vim.h.generated.h" "../../build/include/api/vimscript.h.generated.h" "../../build/include/api/win_config.h.generated.h" "../../build/include/api/window.h.generated.h" - -local mpack = vim.mpack - -local hashy = require 'generators.hashy' - -local pre_args = 7 -assert(#arg >= pre_args) --- output h file with generated dispatch functions (dispatch_wrappers.generated.h) -local dispatch_outputf = arg[1] --- output h file with packed metadata (api_metadata.generated.h) -local api_metadata_outputf = arg[2] --- output metadata mpack file, for use by other build scripts (funcs_metadata.mpack) -local mpack_outputf = arg[3] -local lua_c_bindings_outputf = arg[4] -- lua_api_c_bindings.generated.c -local keysets_outputf = arg[5] -- keysets_defs.generated.h -local ui_metadata_inputf = arg[6] -- ui events metadata -local git_version_inputf = arg[7] -- git version header - -local functions = {} - --- names of all headers relative to the source root (for inclusion in the --- generated file) -local headers = {} - --- set of function names, used to detect duplicates -local function_names = {} - -local c_grammar = require('generators.c_grammar') - -local startswith = vim.startswith - -local function add_function(fn) - local public = startswith(fn.name, 'nvim_') or fn.deprecated_since - if public and not fn.noexport then - functions[#functions + 1] = fn - function_names[fn.name] = true - if - #fn.parameters >= 2 - and fn.parameters[2][1] == 'Array' - and fn.parameters[2][2] == 'uidata' - then - -- function receives the "args" as a parameter - fn.receives_array_args = true - -- remove the args parameter - table.remove(fn.parameters, 2) - end - if #fn.parameters ~= 0 and fn.parameters[1][2] == 'channel_id' then - -- this function should receive the channel id - fn.receives_channel_id = true - -- remove the parameter since it won't be passed by the api client - table.remove(fn.parameters, 1) - end - if #fn.parameters ~= 0 and fn.parameters[#fn.parameters][1] == 'error' then - -- function can fail if the last parameter type is 'Error' - fn.can_fail = true - -- remove the error parameter, msgpack has it's own special field - -- for specifying errors - fn.parameters[#fn.parameters] = nil - end - if #fn.parameters ~= 0 and fn.parameters[#fn.parameters][1] == 'lstate' then - fn.has_lua_imp = true - fn.parameters[#fn.parameters] = nil - end - if #fn.parameters ~= 0 and fn.parameters[#fn.parameters][1] == 'arena' then - fn.receives_arena = true - fn.parameters[#fn.parameters] = nil - end - end -end - -local keysets = {} - -local function add_keyset(val) - local keys = {} - local types = {} - local c_names = {} - local is_set_name = 'is_set__' .. val.keyset_name .. '_' - local has_optional = false - for i, field in ipairs(val.fields) do - local dict_key = field.dict_key or field.name - if field.type ~= 'Object' then - types[dict_key] = field.type - end - if field.name ~= is_set_name and field.type ~= 'OptionalKeys' then - table.insert(keys, dict_key) - if dict_key ~= field.name then - c_names[dict_key] = field.name - end - else - if i > 1 then - error("'is_set__{type}_' must be first if present") - elseif field.name ~= is_set_name then - error(val.keyset_name .. ': name of first key should be ' .. is_set_name) - elseif field.type ~= 'OptionalKeys' then - error("'" .. is_set_name .. "' must have type 'OptionalKeys'") - end - has_optional = true - end - end - table.insert(keysets, { - name = val.keyset_name, - keys = keys, - c_names = c_names, - types = types, - has_optional = has_optional, - }) -end - -local ui_options_text = nil - --- read each input file, parse and append to the api metadata -for i = pre_args + 1, #arg do - local full_path = arg[i] - local parts = {} - for part in string.gmatch(full_path, '[^/]+') do - parts[#parts + 1] = part - end - headers[#headers + 1] = parts[#parts - 1] .. '/' .. parts[#parts] - - local input = assert(io.open(full_path, 'rb')) - - local text = input:read('*all') - local tmp = c_grammar.grammar:match(text) - for j = 1, #tmp do - local val = tmp[j] - if val.keyset_name then - add_keyset(val) - elseif val.name then - add_function(val) - end - end - - ui_options_text = ui_options_text or string.match(text, 'ui_ext_names%[][^{]+{([^}]+)}') - input:close() -end - -local function shallowcopy(orig) - local copy = {} - for orig_key, orig_value in pairs(orig) do - copy[orig_key] = orig_value - end - return copy -end - --- Export functions under older deprecated names. --- These will be removed eventually. -local deprecated_aliases = require('api.dispatch_deprecated') -for _, f in ipairs(shallowcopy(functions)) do - local ismethod = false - if startswith(f.name, 'nvim_') then - if startswith(f.name, 'nvim__') or f.name == 'nvim_error_event' then - f.since = -1 - elseif f.since == nil then - print('Function ' .. f.name .. ' lacks since field.\n') - os.exit(1) - end - f.since = tonumber(f.since) - if f.deprecated_since ~= nil then - f.deprecated_since = tonumber(f.deprecated_since) - end - - if startswith(f.name, 'nvim_buf_') then - ismethod = true - elseif startswith(f.name, 'nvim_win_') then - ismethod = true - elseif startswith(f.name, 'nvim_tabpage_') then - ismethod = true - end - f.remote = f.remote_only or not f.lua_only - f.lua = f.lua_only or not f.remote_only - f.eval = (not f.lua_only) and not f.remote_only - else - f.deprecated_since = tonumber(f.deprecated_since) - assert(f.deprecated_since == 1) - f.remote = true - f.since = 0 - end - f.method = ismethod - local newname = deprecated_aliases[f.name] - if newname ~= nil then - if function_names[newname] then - -- duplicate - print( - 'Function ' - .. f.name - .. ' has deprecated alias\n' - .. newname - .. ' which has a separate implementation.\n' - .. 'Please remove it from src/nvim/api/dispatch_deprecated.lua' - ) - os.exit(1) - end - local newf = shallowcopy(f) - newf.name = newname - if newname == 'ui_try_resize' then - -- The return type was incorrectly set to Object in 0.1.5. - -- Keep it that way for clients that rely on this. - newf.return_type = 'Object' - end - newf.impl_name = f.name - newf.lua = false - newf.eval = false - newf.since = 0 - newf.deprecated_since = 1 - functions[#functions + 1] = newf - end -end - --- don't expose internal attributes like "impl_name" in public metadata -local exported_attributes = { 'name', 'return_type', 'method', 'since', 'deprecated_since' } -local exported_functions = {} -for _, f in ipairs(functions) do - if not (startswith(f.name, 'nvim__') or f.name == 'nvim_error_event' or f.name == 'redraw') then - local f_exported = {} - for _, attr in ipairs(exported_attributes) do - f_exported[attr] = f[attr] - end - f_exported.parameters = {} - for i, param in ipairs(f.parameters) do - if param[1] == 'DictOf(LuaRef)' then - param = { 'Dict', param[2] } - elseif startswith(param[1], 'Dict(') then - param = { 'Dict', param[2] } - end - f_exported.parameters[i] = param - end - if startswith(f.return_type, 'Dict(') then - f_exported.return_type = 'Dict' - end - exported_functions[#exported_functions + 1] = f_exported - end -end - -local ui_options = { 'rgb' } -for x in string.gmatch(ui_options_text, '"([a-z][a-z_]+)"') do - table.insert(ui_options, x) -end - -local version = require 'nvim_version' -- `build/nvim_version.lua` file. -local git_version = io.open(git_version_inputf):read '*a' -local version_build = string.match(git_version, '#define NVIM_VERSION_BUILD "([^"]+)"') or vim.NIL - --- serialize the API metadata using msgpack and embed into the resulting --- binary for easy querying by clients -local api_metadata_output = assert(io.open(api_metadata_outputf, 'wb')) -local pieces = {} - --- Naively using mpack.encode({foo=x, bar=y}) will make the build --- "non-reproducible". Emit maps directly as FIXDICT(2) "foo" x "bar" y instead -local function fixdict(num) - if num > 15 then - error 'implement more dict codes' - end - table.insert(pieces, string.char(128 + num)) -end -local function put(item, item2) - table.insert(pieces, mpack.encode(item)) - if item2 ~= nil then - table.insert(pieces, mpack.encode(item2)) - end -end - -fixdict(6) - -put('version') -fixdict(1 + #version) -for _, item in ipairs(version) do - -- NB: all items are mandatory. But any error will be less confusing - -- with placeholder vim.NIL (than invalid mpack data) - local val = item[2] == nil and vim.NIL or item[2] - put(item[1], val) -end -put('build', version_build) - -put('functions', exported_functions) -put('ui_events') -table.insert(pieces, io.open(ui_metadata_inputf, 'rb'):read('*all')) -put('ui_options', ui_options) - -put('error_types') -fixdict(2) -put('Exception', { id = 0 }) -put('Validation', { id = 1 }) - -put('types') -local types = - { { 'Buffer', 'nvim_buf_' }, { 'Window', 'nvim_win_' }, { 'Tabpage', 'nvim_tabpage_' } } -fixdict(#types) -for i, item in ipairs(types) do - put(item[1]) - fixdict(2) - put('id', i - 1) - put('prefix', item[2]) -end - -local packed = table.concat(pieces) -local dump_bin_array = require('generators.dump_bin_array') -dump_bin_array(api_metadata_output, 'packed_api_metadata', packed) -api_metadata_output:close() - --- start building the dispatch wrapper output -local output = assert(io.open(dispatch_outputf, 'wb')) - -local keysets_defs = assert(io.open(keysets_outputf, 'wb')) - --- =========================================================================== --- NEW API FILES MUST GO HERE. --- --- When creating a new API file, you must include it here, --- so that the dispatcher can find the C functions that you are creating! --- =========================================================================== -output:write([[ -#include "nvim/errors.h" -#include "nvim/ex_docmd.h" -#include "nvim/ex_getln.h" -#include "nvim/globals.h" -#include "nvim/log.h" -#include "nvim/map_defs.h" - -#include "nvim/api/autocmd.h" -#include "nvim/api/buffer.h" -#include "nvim/api/command.h" -#include "nvim/api/deprecated.h" -#include "nvim/api/extmark.h" -#include "nvim/api/options.h" -#include "nvim/api/tabpage.h" -#include "nvim/api/ui.h" -#include "nvim/api/vim.h" -#include "nvim/api/vimscript.h" -#include "nvim/api/win_config.h" -#include "nvim/api/window.h" -#include "nvim/ui_client.h" - -]]) - -keysets_defs:write('// IWYU pragma: private, include "nvim/api/private/dispatch.h"\n\n') - -for _, k in ipairs(keysets) do - local neworder, hashfun = hashy.hashy_hash(k.name, k.keys, function(idx) - return k.name .. '_table[' .. idx .. '].str' - end) - - keysets_defs:write('extern KeySetLink ' .. k.name .. '_table[' .. (1 + #neworder) .. '];\n') - - local function typename(type) - if type == 'HLGroupID' then - return 'kObjectTypeInteger' - elseif not type or vim.startswith(type, 'Union') then - return 'kObjectTypeNil' - elseif vim.startswith(type, 'LuaRefOf') then - return 'kObjectTypeLuaRef' - elseif type == 'StringArray' then - return 'kUnpackTypeStringArray' - elseif vim.startswith(type, 'ArrayOf') then - return 'kObjectTypeArray' - else - return 'kObjectType' .. type - end - end - - output:write('KeySetLink ' .. k.name .. '_table[] = {\n') - for i, key in ipairs(neworder) do - local ind = -1 - if k.has_optional then - ind = i - keysets_defs:write('#define KEYSET_OPTIDX_' .. k.name .. '__' .. key .. ' ' .. ind .. '\n') - end - output:write( - ' {"' - .. key - .. '", offsetof(KeyDict_' - .. k.name - .. ', ' - .. (k.c_names[key] or key) - .. '), ' - .. typename(k.types[key]) - .. ', ' - .. ind - .. ', ' - .. (k.types[key] == 'HLGroupID' and 'true' or 'false') - .. '},\n' - ) - end - output:write(' {NULL, 0, kObjectTypeNil, -1, false},\n') - output:write('};\n\n') - - output:write(hashfun) - - output:write([[ -KeySetLink *KeyDict_]] .. k.name .. [[_get_field(const char *str, size_t len) -{ - int hash = ]] .. k.name .. [[_hash(str, len); - if (hash == -1) { - return NULL; - } - return &]] .. k.name .. [[_table[hash]; -} - -]]) -end - -local function real_type(type) - local rv = type - local rmatch = string.match(type, 'Dict%(([_%w]+)%)') - if rmatch then - return 'KeyDict_' .. rmatch - elseif c_grammar.typed_container:match(rv) then - if rv:match('Array') then - rv = 'Array' - else - rv = 'Dict' - end - end - return rv -end - -local function attr_name(rt) - if rt == 'Float' then - return 'floating' - else - return rt:lower() - end -end - --- start the handler functions. Visit each function metadata to build the --- handler function with code generated for validating arguments and calling to --- the real API. -for i = 1, #functions do - local fn = functions[i] - if fn.impl_name == nil and fn.remote then - local args = {} - - output:write( - 'Object handle_' .. fn.name .. '(uint64_t channel_id, Array args, Arena* arena, Error *error)' - ) - output:write('\n{') - output:write('\n#ifdef NVIM_LOG_DEBUG') - output:write('\n DLOG("RPC: ch %" PRIu64 ": invoke ' .. fn.name .. '", channel_id);') - output:write('\n#endif') - output:write('\n Object ret = NIL;') - -- Declare/initialize variables that will hold converted arguments - for j = 1, #fn.parameters do - local param = fn.parameters[j] - local rt = real_type(param[1]) - local converted = 'arg_' .. j - output:write('\n ' .. rt .. ' ' .. converted .. ';') - end - output:write('\n') - if not fn.receives_array_args then - output:write('\n if (args.size != ' .. #fn.parameters .. ') {') - output:write( - '\n api_set_error(error, kErrorTypeException, \ - "Wrong number of arguments: expecting ' - .. #fn.parameters - .. ' but got %zu", args.size);' - ) - output:write('\n goto cleanup;') - output:write('\n }\n') - end - - -- Validation/conversion for each argument - for j = 1, #fn.parameters do - local converted, param - param = fn.parameters[j] - converted = 'arg_' .. j - local rt = real_type(param[1]) - if rt == 'Object' then - output:write('\n ' .. converted .. ' = args.items[' .. (j - 1) .. '];\n') - elseif rt:match('^KeyDict_') then - converted = '&' .. converted - output:write('\n if (args.items[' .. (j - 1) .. '].type == kObjectTypeDict) {') --luacheck: ignore 631 - output:write('\n memset(' .. converted .. ', 0, sizeof(*' .. converted .. '));') -- TODO: neeeee - output:write( - '\n if (!api_dict_to_keydict(' - .. converted - .. ', ' - .. rt - .. '_get_field, args.items[' - .. (j - 1) - .. '].data.dict, error)) {' - ) - output:write('\n goto cleanup;') - output:write('\n }') - output:write( - '\n } else if (args.items[' - .. (j - 1) - .. '].type == kObjectTypeArray && args.items[' - .. (j - 1) - .. '].data.array.size == 0) {' - ) --luacheck: ignore 631 - output:write('\n memset(' .. converted .. ', 0, sizeof(*' .. converted .. '));') - - output:write('\n } else {') - output:write( - '\n api_set_error(error, kErrorTypeException, \ - "Wrong type for argument ' - .. j - .. ' when calling ' - .. fn.name - .. ', expecting ' - .. param[1] - .. '");' - ) - output:write('\n goto cleanup;') - output:write('\n }\n') - else - if rt:match('^Buffer$') or rt:match('^Window$') or rt:match('^Tabpage$') then - -- Buffer, Window, and Tabpage have a specific type, but are stored in integer - output:write( - '\n if (args.items[' - .. (j - 1) - .. '].type == kObjectType' - .. rt - .. ' && args.items[' - .. (j - 1) - .. '].data.integer >= 0) {' - ) - output:write( - '\n ' .. converted .. ' = (handle_T)args.items[' .. (j - 1) .. '].data.integer;' - ) - else - output:write('\n if (args.items[' .. (j - 1) .. '].type == kObjectType' .. rt .. ') {') - output:write( - '\n ' - .. converted - .. ' = args.items[' - .. (j - 1) - .. '].data.' - .. attr_name(rt) - .. ';' - ) - end - if - rt:match('^Buffer$') - or rt:match('^Window$') - or rt:match('^Tabpage$') - or rt:match('^Boolean$') - then - -- accept nonnegative integers for Booleans, Buffers, Windows and Tabpages - output:write( - '\n } else if (args.items[' - .. (j - 1) - .. '].type == kObjectTypeInteger && args.items[' - .. (j - 1) - .. '].data.integer >= 0) {' - ) - output:write( - '\n ' .. converted .. ' = (handle_T)args.items[' .. (j - 1) .. '].data.integer;' - ) - end - if rt:match('^Float$') then - -- accept integers for Floats - output:write('\n } else if (args.items[' .. (j - 1) .. '].type == kObjectTypeInteger) {') - output:write( - '\n ' .. converted .. ' = (Float)args.items[' .. (j - 1) .. '].data.integer;' - ) - end - -- accept empty lua tables as empty dictionaries - if rt:match('^Dict') then - output:write( - '\n } else if (args.items[' - .. (j - 1) - .. '].type == kObjectTypeArray && args.items[' - .. (j - 1) - .. '].data.array.size == 0) {' - ) --luacheck: ignore 631 - output:write('\n ' .. converted .. ' = (Dict)ARRAY_DICT_INIT;') - end - output:write('\n } else {') - output:write( - '\n api_set_error(error, kErrorTypeException, \ - "Wrong type for argument ' - .. j - .. ' when calling ' - .. fn.name - .. ', expecting ' - .. param[1] - .. '");' - ) - output:write('\n goto cleanup;') - output:write('\n }\n') - end - args[#args + 1] = converted - end - - if fn.textlock then - output:write('\n if (text_locked()) {') - output:write('\n api_set_error(error, kErrorTypeException, "%s", get_text_locked_msg());') - output:write('\n goto cleanup;') - output:write('\n }\n') - elseif fn.textlock_allow_cmdwin then - output:write('\n if (textlock != 0 || expr_map_locked()) {') - output:write('\n api_set_error(error, kErrorTypeException, "%s", e_textlock);') - output:write('\n goto cleanup;') - output:write('\n }\n') - end - - -- function call - output:write('\n ') - if fn.return_type ~= 'void' then - -- has a return value, prefix the call with a declaration - output:write(fn.return_type .. ' rv = ') - end - - -- write the function name and the opening parenthesis - output:write(fn.name .. '(') - - local call_args = {} - if fn.receives_channel_id then - table.insert(call_args, 'channel_id') - end - - if fn.receives_array_args then - table.insert(call_args, 'args') - end - - for _, a in ipairs(args) do - table.insert(call_args, a) - end - - if fn.receives_arena then - table.insert(call_args, 'arena') - end - - if fn.has_lua_imp then - table.insert(call_args, 'NULL') - end - - if fn.can_fail then - table.insert(call_args, 'error') - end - - output:write(table.concat(call_args, ', ')) - output:write(');\n') - - if fn.can_fail then - -- if the function can fail, also pass a pointer to the local error object - -- and check for the error - output:write('\n if (ERROR_SET(error)) {') - output:write('\n goto cleanup;') - output:write('\n }\n') - end - - local ret_type = real_type(fn.return_type) - if string.match(ret_type, '^KeyDict_') then - local table = string.sub(ret_type, 9) .. '_table' - output:write( - '\n ret = DICT_OBJ(api_keydict_to_dict(&rv, ' - .. table - .. ', ARRAY_SIZE(' - .. table - .. '), arena));' - ) - elseif ret_type ~= 'void' then - output:write('\n ret = ' .. string.upper(real_type(fn.return_type)) .. '_OBJ(rv);') - end - output:write('\n\ncleanup:') - - output:write('\n return ret;\n}\n\n') - end -end - -local remote_fns = {} -for _, fn in ipairs(functions) do - if fn.remote then - remote_fns[fn.name] = fn - end -end -remote_fns.redraw = { impl_name = 'ui_client_redraw', fast = true } - -local names = vim.tbl_keys(remote_fns) -table.sort(names) -local hashorder, hashfun = hashy.hashy_hash('msgpack_rpc_get_handler_for', names, function(idx) - return 'method_handlers[' .. idx .. '].name' -end) - -output:write('const MsgpackRpcRequestHandler method_handlers[] = {\n') -for n, name in ipairs(hashorder) do - local fn = remote_fns[name] - fn.handler_id = n - 1 - output:write( - ' { .name = "' - .. name - .. '", .fn = handle_' - .. (fn.impl_name or fn.name) - .. ', .fast = ' - .. tostring(fn.fast) - .. ', .ret_alloc = ' - .. tostring(not not fn.ret_alloc) - .. '},\n' - ) -end -output:write('};\n\n') -output:write(hashfun) - -output:close() - -functions.keysets = keysets -local mpack_output = assert(io.open(mpack_outputf, 'wb')) -mpack_output:write(mpack.encode(functions)) -mpack_output:close() - -local function include_headers(output_handle, headers_to_include) - for i = 1, #headers_to_include do - if headers_to_include[i]:sub(-12) ~= '.generated.h' then - output_handle:write('\n#include "nvim/' .. headers_to_include[i] .. '"') - end - end -end - -local function write_shifted_output(str, ...) - str = str:gsub('\n ', '\n') - str = str:gsub('^ ', '') - str = str:gsub(' +$', '') - output:write(string.format(str, ...)) -end - --- start building lua output -output = assert(io.open(lua_c_bindings_outputf, 'wb')) - -include_headers(output, headers) -output:write('\n') - -local lua_c_functions = {} - -local function process_function(fn) - local lua_c_function_name = ('nlua_api_%s'):format(fn.name) - write_shifted_output( - [[ - - static int %s(lua_State *lstate) - { - Error err = ERROR_INIT; - Arena arena = ARENA_EMPTY; - char *err_param = 0; - if (lua_gettop(lstate) != %i) { - api_set_error(&err, kErrorTypeValidation, "Expected %i argument%s"); - goto exit_0; - } - ]], - lua_c_function_name, - #fn.parameters, - #fn.parameters, - (#fn.parameters == 1) and '' or 's' - ) - lua_c_functions[#lua_c_functions + 1] = { - binding = lua_c_function_name, - api = fn.name, - } - - if not fn.fast then - write_shifted_output( - [[ - if (!nlua_is_deferred_safe()) { - return luaL_error(lstate, e_fast_api_disabled, "%s"); - } - ]], - fn.name - ) - end - - if fn.textlock then - write_shifted_output([[ - if (text_locked()) { - api_set_error(&err, kErrorTypeException, "%%s", get_text_locked_msg()); - goto exit_0; - } - ]]) - elseif fn.textlock_allow_cmdwin then - write_shifted_output([[ - if (textlock != 0 || expr_map_locked()) { - api_set_error(&err, kErrorTypeException, "%%s", e_textlock); - goto exit_0; - } - ]]) - end - - local cparams = '' - local free_code = {} - for j = #fn.parameters, 1, -1 do - local param = fn.parameters[j] - local cparam = string.format('arg%u', j) - local param_type = real_type(param[1]) - local extra = param_type == 'Dict' and 'false, ' or '' - local arg_free_code = '' - if param[1] == 'Object' then - extra = 'true, ' - arg_free_code = ' api_luarefs_free_object(' .. cparam .. ');' - elseif param[1] == 'DictOf(LuaRef)' then - extra = 'true, ' - arg_free_code = ' api_luarefs_free_dict(' .. cparam .. ');' - elseif param[1] == 'LuaRef' then - arg_free_code = ' api_free_luaref(' .. cparam .. ');' - end - local errshift = 0 - local seterr = '' - if string.match(param_type, '^KeyDict_') then - write_shifted_output( - [[ - %s %s = KEYDICT_INIT; - nlua_pop_keydict(lstate, &%s, %s_get_field, &err_param, &arena, &err); - ]], - param_type, - cparam, - cparam, - param_type - ) - cparam = '&' .. cparam - errshift = 1 -- free incomplete dict on error - arg_free_code = ' api_luarefs_free_keydict(' - .. cparam - .. ', ' - .. string.sub(param_type, 9) - .. '_table);' - else - write_shifted_output( - [[ - const %s %s = nlua_pop_%s(lstate, %s&arena, &err);]], - param[1], - cparam, - param_type, - extra - ) - seterr = '\n err_param = "' .. param[2] .. '";' - end - - write_shifted_output([[ - - if (ERROR_SET(&err)) {]] .. seterr .. [[ - - goto exit_%u; - } - - ]], #fn.parameters - j + errshift) - free_code[#free_code + 1] = arg_free_code - cparams = cparam .. ', ' .. cparams - end - if fn.receives_channel_id then - cparams = 'LUA_INTERNAL_CALL, ' .. cparams - end - if fn.receives_arena then - cparams = cparams .. '&arena, ' - end - - if fn.has_lua_imp then - cparams = cparams .. 'lstate, ' - end - - if fn.can_fail then - cparams = cparams .. '&err' - else - cparams = cparams:gsub(', $', '') - end - local free_at_exit_code = '' - for i = 1, #free_code do - local rev_i = #free_code - i + 1 - local code = free_code[rev_i] - if i == 1 and not string.match(real_type(fn.parameters[1][1]), '^KeyDict_') then - free_at_exit_code = free_at_exit_code .. ('\n%s'):format(code) - else - free_at_exit_code = free_at_exit_code .. ('\nexit_%u:\n%s'):format(rev_i, code) - end - end - local err_throw_code = [[ - -exit_0: - arena_mem_free(arena_finish(&arena)); - if (ERROR_SET(&err)) { - luaL_where(lstate, 1); - if (err_param) { - lua_pushstring(lstate, "Invalid '"); - lua_pushstring(lstate, err_param); - lua_pushstring(lstate, "': "); - } - lua_pushstring(lstate, err.msg); - api_clear_error(&err); - lua_concat(lstate, err_param ? 5 : 2); - return lua_error(lstate); - } -]] - local return_type - if fn.return_type ~= 'void' then - if fn.return_type:match('^ArrayOf') then - return_type = 'Array' - else - return_type = fn.return_type - end - local free_retval = '' - if fn.ret_alloc then - free_retval = ' api_free_' .. return_type:lower() .. '(ret);' - end - write_shifted_output(' %s ret = %s(%s);\n', fn.return_type, fn.name, cparams) - - local ret_type = real_type(fn.return_type) - local ret_mode = (ret_type == 'Object') and '&' or '' - if fn.has_lua_imp then - -- only push onto the Lua stack if we haven't already - write_shifted_output( - [[ - if (lua_gettop(lstate) == 0) { - nlua_push_%s(lstate, %sret, kNluaPushSpecial | kNluaPushFreeRefs); - } - ]], - return_type, - ret_mode - ) - elseif string.match(ret_type, '^KeyDict_') then - write_shifted_output( - ' nlua_push_keydict(lstate, &ret, %s_table);\n', - string.sub(ret_type, 9) - ) - else - local special = (fn.since ~= nil and fn.since < 11) - write_shifted_output( - ' nlua_push_%s(lstate, %sret, %s | kNluaPushFreeRefs);\n', - return_type, - ret_mode, - special and 'kNluaPushSpecial' or '0' - ) - end - - -- NOTE: we currently assume err_throw needs nothing from arena - write_shifted_output( - [[ - %s - %s - %s - return 1; - ]], - free_retval, - free_at_exit_code, - err_throw_code - ) - else - write_shifted_output( - [[ - %s(%s); - %s - %s - return 0; - ]], - fn.name, - cparams, - free_at_exit_code, - err_throw_code - ) - end - write_shifted_output([[ - } - ]]) -end - -for _, fn in ipairs(functions) do - if fn.lua or fn.name:sub(1, 4) == '_vim' then - process_function(fn) - end -end - -output:write(string.format( - [[ -void nlua_add_api_functions(lua_State *lstate) -{ - lua_createtable(lstate, 0, %u); -]], - #lua_c_functions -)) -for _, func in ipairs(lua_c_functions) do - output:write(string.format( - [[ - - lua_pushcfunction(lstate, &%s); - lua_setfield(lstate, -2, "%s");]], - func.binding, - func.api - )) -end -output:write([[ - - lua_setfield(lstate, -2, "api"); -} -]]) - -output:close() -keysets_defs:close() diff --git a/src/nvim/generators/gen_api_ui_events.lua b/src/nvim/generators/gen_api_ui_events.lua deleted file mode 100644 index a3bb76cb91..0000000000 --- a/src/nvim/generators/gen_api_ui_events.lua +++ /dev/null @@ -1,219 +0,0 @@ -local mpack = vim.mpack - -assert(#arg == 5) -local input = io.open(arg[1], 'rb') -local call_output = io.open(arg[2], 'wb') -local remote_output = io.open(arg[3], 'wb') -local metadata_output = io.open(arg[4], 'wb') -local client_output = io.open(arg[5], 'wb') - -local c_grammar = require('generators.c_grammar') -local events = c_grammar.grammar:match(input:read('*all')) - -local hashy = require 'generators.hashy' - -local function write_signature(output, ev, prefix, notype) - output:write('(' .. prefix) - if prefix == '' and #ev.parameters == 0 then - output:write('void') - end - for j = 1, #ev.parameters do - if j > 1 or prefix ~= '' then - output:write(', ') - end - local param = ev.parameters[j] - if not notype then - output:write(param[1] .. ' ') - end - output:write(param[2]) - end - output:write(')') -end - -local function write_arglist(output, ev) - if #ev.parameters == 0 then - return - end - output:write(' MAXSIZE_TEMP_ARRAY(args, ' .. #ev.parameters .. ');\n') - for j = 1, #ev.parameters do - local param = ev.parameters[j] - local kind = string.upper(param[1]) - output:write(' ADD_C(args, ') - output:write(kind .. '_OBJ(' .. param[2] .. ')') - output:write(');\n') - end -end - -local function call_ui_event_method(output, ev) - output:write('void ui_client_event_' .. ev.name .. '(Array args)\n{\n') - - local hlattrs_args_count = 0 - if #ev.parameters > 0 then - output:write(' if (args.size < ' .. #ev.parameters) - for j = 1, #ev.parameters do - local kind = ev.parameters[j][1] - if kind ~= 'Object' then - if kind == 'HlAttrs' then - kind = 'Dict' - end - output:write('\n || args.items[' .. (j - 1) .. '].type != kObjectType' .. kind .. '') - end - end - output:write(') {\n') - output:write(' ELOG("Error handling ui event \'' .. ev.name .. '\'");\n') - output:write(' return;\n') - output:write(' }\n') - end - - for j = 1, #ev.parameters do - local param = ev.parameters[j] - local kind = param[1] - output:write(' ' .. kind .. ' arg_' .. j .. ' = ') - if kind == 'HlAttrs' then - -- The first HlAttrs argument is rgb_attrs and second is cterm_attrs - output:write( - 'ui_client_dict2hlattrs(args.items[' - .. (j - 1) - .. '].data.dict, ' - .. (hlattrs_args_count == 0 and 'true' or 'false') - .. ');\n' - ) - hlattrs_args_count = hlattrs_args_count + 1 - elseif kind == 'Object' then - output:write('args.items[' .. (j - 1) .. '];\n') - elseif kind == 'Window' then - output:write('(Window)args.items[' .. (j - 1) .. '].data.integer;\n') - else - output:write('args.items[' .. (j - 1) .. '].data.' .. string.lower(kind) .. ';\n') - end - end - - output:write(' tui_' .. ev.name .. '(tui') - for j = 1, #ev.parameters do - output:write(', arg_' .. j) - end - output:write(');\n') - - output:write('}\n\n') -end - -events = vim.tbl_filter(function(ev) - return ev[1] ~= 'empty' and ev[1] ~= 'preproc' -end, events) - -for i = 1, #events do - local ev = events[i] - assert(ev.return_type == 'void') - - if ev.since == nil and not ev.noexport then - print('Ui event ' .. ev.name .. ' lacks since field.\n') - os.exit(1) - end - ev.since = tonumber(ev.since) - - local args = #ev.parameters > 0 and 'args' or 'noargs' - if not ev.remote_only then - if not ev.remote_impl and not ev.noexport then - remote_output:write('void remote_ui_' .. ev.name) - write_signature(remote_output, ev, 'RemoteUI *ui') - remote_output:write('\n{\n') - write_arglist(remote_output, ev) - remote_output:write(' push_call(ui, "' .. ev.name .. '", ' .. args .. ');\n') - remote_output:write('}\n\n') - end - end - - if not (ev.remote_only and ev.remote_impl) then - call_output:write('void ui_call_' .. ev.name) - write_signature(call_output, ev, '') - call_output:write('\n{\n') - if ev.remote_only then - -- Lua callbacks may emit other events or the same event again. Avoid the latter - -- by adding a recursion guard to each generated function that may call a Lua callback. - call_output:write(' static bool entered = false;\n') - call_output:write(' if (entered) {\n') - call_output:write(' return;\n') - call_output:write(' }\n') - call_output:write(' entered = true;\n') - write_arglist(call_output, ev) - 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) - call_output:write(';\n') - call_output:write(' UI_CALL') - write_signature(call_output, ev, '!ui->composed, ' .. ev.name .. ', ui', true) - call_output:write(';\n') - else - call_output:write(' UI_CALL') - write_signature(call_output, ev, 'true, ' .. ev.name .. ', ui', true) - call_output:write(';\n') - end - call_output:write('}\n\n') - end - - if ev.compositor_impl then - call_output:write('void ui_composed_call_' .. ev.name) - write_signature(call_output, ev, '') - call_output:write('\n{\n') - call_output:write(' UI_CALL') - write_signature(call_output, ev, 'ui->composed, ' .. ev.name .. ', ui', true) - call_output:write(';\n') - call_output:write('}\n\n') - end - - if (not ev.remote_only) and not ev.noexport and not ev.client_impl and not ev.client_ignore then - call_ui_event_method(client_output, ev) - end -end - -local client_events = {} -for _, ev in ipairs(events) do - if (not ev.noexport) and ((not ev.remote_only) or ev.client_impl) and not ev.client_ignore then - client_events[ev.name] = ev - end -end - -local hashorder, hashfun = hashy.hashy_hash( - 'ui_client_handler', - vim.tbl_keys(client_events), - function(idx) - return 'event_handlers[' .. idx .. '].name' - end -) - -client_output:write('static const UIClientHandler event_handlers[] = {\n') - -for _, name in ipairs(hashorder) do - client_output:write(' { .name = "' .. name .. '", .fn = ui_client_event_' .. name .. '},\n') -end - -client_output:write('\n};\n\n') -client_output:write(hashfun) - -call_output:close() -remote_output:close() -client_output:close() - --- don't expose internal attributes like "impl_name" in public metadata -local exported_attributes = { 'name', 'parameters', 'since', 'deprecated_since' } -local exported_events = {} -for _, ev in ipairs(events) do - local ev_exported = {} - for _, attr in ipairs(exported_attributes) do - ev_exported[attr] = ev[attr] - end - for _, p in ipairs(ev_exported.parameters) do - if p[1] == 'HlAttrs' or p[1] == 'Dict' then - -- TODO(justinmk): for back-compat, but do clients actually look at this? - p[1] = 'Dictionary' - end - end - if not ev.noexport then - exported_events[#exported_events + 1] = ev_exported - end -end - -metadata_output:write(mpack.encode(exported_events)) -metadata_output:close() diff --git a/src/nvim/generators/gen_char_blob.lua b/src/nvim/generators/gen_char_blob.lua deleted file mode 100644 index c40e0d6e82..0000000000 --- a/src/nvim/generators/gen_char_blob.lua +++ /dev/null @@ -1,96 +0,0 @@ -if arg[1] == '--help' then - print('Usage:') - print(' ' .. arg[0] .. ' [-c] target source varname [source varname]...') - print('') - print('Generates C file with big uint8_t blob.') - print('Blob will be stored in a static const array named varname.') - os.exit() -end - --- Recognized options: --- -c compile Lua bytecode -local options = {} - -while true do - local opt = string.match(arg[1], '^-(%w)') - if not opt then - break - end - - options[opt] = true - table.remove(arg, 1) -end - -assert(#arg >= 3 and (#arg - 1) % 2 == 0) - -local target_file = arg[1] or error('Need a target file') -local target = io.open(target_file, 'w') - -target:write('#include <stdint.h>\n\n') - -local index_items = {} - -local warn_on_missing_compiler = true -local modnames = {} -for argi = 2, #arg, 2 do - local source_file = arg[argi] - local modname = arg[argi + 1] - if modnames[modname] then - error(string.format('modname %q is already specified for file %q', modname, modnames[modname])) - end - modnames[modname] = source_file - - local varname = string.gsub(modname, '%.', '_dot_') .. '_module' - target:write(('static const uint8_t %s[] = {\n'):format(varname)) - - local output - if options.c then - local luac = os.getenv('LUAC_PRG') - if luac and luac ~= '' then - output = io.popen(luac:format(source_file), 'r'):read('*a') - elseif warn_on_missing_compiler then - print('LUAC_PRG is missing, embedding raw source') - warn_on_missing_compiler = false - end - end - - if not output then - local source = io.open(source_file, 'r') - or error(string.format("source_file %q doesn't exist", source_file)) - output = source:read('*a') - source:close() - end - - local num_bytes = 0 - local MAX_NUM_BYTES = 15 -- 78 / 5: maximum number of bytes on one line - target:write(' ') - - local increase_num_bytes - increase_num_bytes = function() - num_bytes = num_bytes + 1 - if num_bytes == MAX_NUM_BYTES then - num_bytes = 0 - target:write('\n ') - end - end - - for i = 1, string.len(output) do - local byte = output:byte(i) - target:write(string.format(' %3u,', byte)) - increase_num_bytes() - end - - target:write(' 0};\n') - if modname ~= '_' then - table.insert( - index_items, - ' { "' .. modname .. '", ' .. varname .. ', sizeof ' .. varname .. ' },\n\n' - ) - end -end - -target:write('static ModuleDef builtin_modules[] = {\n') -target:write(table.concat(index_items)) -target:write('};\n') - -target:close() diff --git a/src/nvim/generators/gen_declarations.lua b/src/nvim/generators/gen_declarations.lua deleted file mode 100644 index 6e1ea92572..0000000000 --- a/src/nvim/generators/gen_declarations.lua +++ /dev/null @@ -1,186 +0,0 @@ -local grammar = require('generators.c_grammar').grammar - ---- @param fname string ---- @return string? -local function read_file(fname) - local f = io.open(fname, 'r') - if not f then - return - end - local contents = f:read('*a') - f:close() - return contents -end - ---- @param fname string ---- @param contents string[] -local function write_file(fname, contents) - local contents_s = table.concat(contents, '\n') .. '\n' - local fcontents = read_file(fname) - if fcontents == contents_s then - return - end - local f = assert(io.open(fname, 'w')) - f:write(contents_s) - f:close() -end - ---- @param fname string ---- @param non_static_fname string ---- @return string? non_static -local function add_iwyu_non_static(fname, non_static_fname) - if fname:find('.*/src/nvim/.*%.c$') then - -- Add an IWYU pragma comment if the corresponding .h file exists. - local header_fname = fname:sub(1, -3) .. '.h' - local header_f = io.open(header_fname, 'r') - if header_f then - header_f:close() - return (header_fname:gsub('.*/src/nvim/', 'nvim/')) - end - elseif non_static_fname:find('/include/api/private/dispatch_wrappers%.h%.generated%.h$') then - return 'nvim/api/private/dispatch.h' - elseif non_static_fname:find('/include/ui_events_call%.h%.generated%.h$') then - return 'nvim/ui.h' - elseif non_static_fname:find('/include/ui_events_client%.h%.generated%.h$') then - return 'nvim/ui_client.h' - elseif non_static_fname:find('/include/ui_events_remote%.h%.generated%.h$') then - return 'nvim/api/ui.h' - end -end - ---- @param d string -local function process_decl(d) - -- Comments are really handled by preprocessor, so the following is not - -- needed - d = d:gsub('/%*.-%*/', '') - d = d:gsub('//.-\n', '\n') - d = d:gsub('# .-\n', '') - d = d:gsub('\n', ' ') - d = d:gsub('%s+', ' ') - d = d:gsub(' ?%( ?', '(') - d = d:gsub(' ?, ?', ', ') - d = d:gsub(' ?(%*+) ?', ' %1') - d = d:gsub(' ?(FUNC_ATTR_)', ' %1') - d = d:gsub(' $', '') - d = d:gsub('^ ', '') - return d .. ';' -end - ---- @param fname string ---- @param text string ---- @return string[] static ---- @return string[] non_static ---- @return boolean any_static -local function gen_declarations(fname, text) - local non_static = {} --- @type string[] - local static = {} --- @type string[] - - local neededfile = fname:match('[^/]+$') - local curfile = nil - local any_static = false - for _, node in ipairs(grammar:match(text)) do - if node[1] == 'preproc' then - curfile = node.content:match('^%a* %d+ "[^"]-/?([^"/]+)"') or curfile - elseif node[1] == 'proto' and curfile == neededfile then - local node_text = text:sub(node.pos, node.endpos - 1) - local declaration = process_decl(node_text) - - if node.static then - if not any_static and declaration:find('FUNC_ATTR_') then - any_static = true - end - static[#static + 1] = declaration - else - non_static[#non_static + 1] = 'DLLEXPORT ' .. declaration - end - end - end - - return static, non_static, any_static -end - -local usage = [[ -Usage: - - gen_declarations.lua definitions.c static.h non-static.h definitions.i - -Generates declarations for a C file definitions.c, putting declarations for -static functions into static.h and declarations for non-static functions into -non-static.h. File `definitions.i' should contain an already preprocessed -version of definitions.c and it is the only one which is actually parsed, -definitions.c is needed only to determine functions from which file out of all -functions found in definitions.i are needed and to generate an IWYU comment. -]] - -local function main() - local fname = arg[1] - local static_fname = arg[2] - local non_static_fname = arg[3] - local preproc_fname = arg[4] - local static_basename = arg[5] - - if fname == '--help' or #arg < 5 then - print(usage) - os.exit() - end - - local text = assert(read_file(preproc_fname)) - - local static_decls, non_static_decls, any_static = gen_declarations(fname, text) - - local static = {} --- @type string[] - if fname:find('.*/src/nvim/.*%.h$') then - static[#static + 1] = ('// IWYU pragma: private, include "%s"'):format( - fname:gsub('.*/src/nvim/', 'nvim/') - ) - end - vim.list_extend(static, { - '#define DEFINE_FUNC_ATTRIBUTES', - '#include "nvim/func_attr.h"', - '#undef DEFINE_FUNC_ATTRIBUTES', - }) - vim.list_extend(static, static_decls) - vim.list_extend(static, { - '#define DEFINE_EMPTY_ATTRIBUTES', - '#include "nvim/func_attr.h" // IWYU pragma: export', - '', - }) - - write_file(static_fname, static) - - if any_static then - local orig_text = assert(read_file(fname)) - local pat = '\n#%s?include%s+"' .. static_basename .. '"\n' - local pat_comment = '\n#%s?include%s+"' .. static_basename .. '"%s*//' - if not orig_text:find(pat) and not orig_text:find(pat_comment) then - error(('fail: missing include for %s in %s'):format(static_basename, fname)) - end - end - - if non_static_fname ~= 'SKIP' then - local non_static = {} --- @type string[] - local iwyu_non_static = add_iwyu_non_static(fname, non_static_fname) - if iwyu_non_static then - non_static[#non_static + 1] = ('// IWYU pragma: private, include "%s"'):format( - iwyu_non_static - ) - end - vim.list_extend(non_static, { - '#define DEFINE_FUNC_ATTRIBUTES', - '#include "nvim/func_attr.h"', - '#undef DEFINE_FUNC_ATTRIBUTES', - '#ifndef DLLEXPORT', - '# ifdef MSWIN', - '# define DLLEXPORT __declspec(dllexport)', - '# else', - '# define DLLEXPORT', - '# endif', - '#endif', - }) - vim.list_extend(non_static, non_static_decls) - non_static[#non_static + 1] = '#include "nvim/func_attr.h"' - write_file(non_static_fname, non_static) - end -end - -return main() diff --git a/src/nvim/generators/gen_eval.lua b/src/nvim/generators/gen_eval.lua deleted file mode 100644 index 0b6ee6cb24..0000000000 --- a/src/nvim/generators/gen_eval.lua +++ /dev/null @@ -1,112 +0,0 @@ -local mpack = vim.mpack - -local autodir = arg[1] -local metadata_file = arg[2] -local funcs_file = arg[3] - -local funcsfname = autodir .. '/funcs.generated.h' - ---Will generate funcs.generated.h with definition of functions static const array. - -local hashy = require 'generators.hashy' - -local hashpipe = assert(io.open(funcsfname, 'wb')) - -hashpipe:write([[ -#include "nvim/arglist.h" -#include "nvim/cmdexpand.h" -#include "nvim/cmdhist.h" -#include "nvim/digraph.h" -#include "nvim/eval.h" -#include "nvim/eval/buffer.h" -#include "nvim/eval/deprecated.h" -#include "nvim/eval/fs.h" -#include "nvim/eval/funcs.h" -#include "nvim/eval/typval.h" -#include "nvim/eval/vars.h" -#include "nvim/eval/window.h" -#include "nvim/ex_docmd.h" -#include "nvim/ex_getln.h" -#include "nvim/fold.h" -#include "nvim/getchar.h" -#include "nvim/insexpand.h" -#include "nvim/mapping.h" -#include "nvim/match.h" -#include "nvim/mbyte.h" -#include "nvim/menu.h" -#include "nvim/mouse.h" -#include "nvim/move.h" -#include "nvim/quickfix.h" -#include "nvim/runtime.h" -#include "nvim/search.h" -#include "nvim/state.h" -#include "nvim/strings.h" -#include "nvim/sign.h" -#include "nvim/testing.h" -#include "nvim/undo.h" - -]]) - -local funcs = require('eval').funcs -for _, func in pairs(funcs) do - if func.float_func then - func.func = 'float_op_wrapper' - func.data = '{ .float_func = &' .. func.float_func .. ' }' - end -end - -local metadata = mpack.decode(io.open(metadata_file, 'rb'):read('*all')) -for _, fun in ipairs(metadata) do - if fun.eval then - funcs[fun.name] = { - args = #fun.parameters, - func = 'api_wrapper', - data = '{ .api_handler = &method_handlers[' .. fun.handler_id .. '] }', - } - end -end - -local func_names = vim.tbl_filter(function(name) - return name:match('__%d*$') == nil -end, vim.tbl_keys(funcs)) - -table.sort(func_names) - -local funcsdata = assert(io.open(funcs_file, 'w')) -funcsdata:write(mpack.encode(func_names)) -funcsdata:close() - -local neworder, hashfun = hashy.hashy_hash('find_internal_func', func_names, function(idx) - return 'functions[' .. idx .. '].name' -end) - -hashpipe:write('static const EvalFuncDef functions[] = {\n') - -for _, name in ipairs(neworder) do - local def = funcs[name] - local args = def.args or 0 - if type(args) == 'number' then - args = { args, args } - elseif #args == 1 then - args[2] = 'MAX_FUNC_ARGS' - end - local base = def.base or 'BASE_NONE' - local func = def.func or ('f_' .. name) - local data = def.data or '{ .null = NULL }' - local fast = def.fast and 'true' or 'false' - hashpipe:write( - (' { "%s", %s, %s, %s, %s, &%s, %s },\n'):format( - name, - args[1], - args[2], - base, - fast, - func, - data - ) - ) -end -hashpipe:write(' { NULL, 0, 0, BASE_NONE, false, NULL, { .null = NULL } },\n') -hashpipe:write('};\n\n') -hashpipe:write(hashfun) -hashpipe:close() diff --git a/src/nvim/generators/gen_events.lua b/src/nvim/generators/gen_events.lua deleted file mode 100644 index 8c87815a74..0000000000 --- a/src/nvim/generators/gen_events.lua +++ /dev/null @@ -1,42 +0,0 @@ -local fileio_enum_file = arg[1] -local names_file = arg[2] - -local auevents = require('auevents') -local events = auevents.events - -local enum_tgt = io.open(fileio_enum_file, 'w') -local names_tgt = io.open(names_file, 'w') - -enum_tgt:write([[ -// IWYU pragma: private, include "nvim/autocmd_defs.h" - -typedef enum auto_event {]]) -names_tgt:write([[ -static const struct event_name { - size_t len; - char *name; - int event; -} event_names[] = {]]) - -local aliases = 0 -for i, event in ipairs(events) do - enum_tgt:write(('\n EVENT_%s = %u,'):format(event[1]:upper(), i + aliases - 1)) - -- Events with positive keys aren't allowed in 'eventignorewin'. - local event_int = ('%sEVENT_%s'):format(event[3] and '-' or '', event[1]:upper()) - names_tgt:write(('\n {%u, "%s", %s},'):format(#event[1], event[1], event_int)) - for _, alias in ipairs(event[2]) do - aliases = aliases + 1 - names_tgt:write(('\n {%u, "%s", %s},'):format(#alias, alias, event_int)) - enum_tgt:write(('\n EVENT_%s = %u,'):format(alias:upper(), i + aliases - 1)) - end - if i == #events then -- Last item. - enum_tgt:write(('\n NUM_EVENTS = %u,'):format(i + aliases)) - end -end - -names_tgt:write('\n {0, NULL, (event_T)0},\n};\n') -names_tgt:write('\nstatic AutoCmdVec autocmds[NUM_EVENTS] = { 0 };\n') -names_tgt:close() - -enum_tgt:write('\n} event_T;\n') -enum_tgt:close() diff --git a/src/nvim/generators/gen_ex_cmds.lua b/src/nvim/generators/gen_ex_cmds.lua deleted file mode 100644 index e8d1aac182..0000000000 --- a/src/nvim/generators/gen_ex_cmds.lua +++ /dev/null @@ -1,194 +0,0 @@ -local includedir = arg[1] -local autodir = arg[2] - --- Will generate files ex_cmds_enum.generated.h with cmdidx_T enum --- and ex_cmds_defs.generated.h with main Ex commands definitions. - -local enumfname = includedir .. '/ex_cmds_enum.generated.h' -local defsfname = autodir .. '/ex_cmds_defs.generated.h' - -local enumfile = io.open(enumfname, 'w') -local defsfile = io.open(defsfname, 'w') - -local bit = require 'bit' -local ex_cmds = require('ex_cmds') -local defs = ex_cmds.cmds -local flags = ex_cmds.flags - -local byte_a = string.byte('a') -local byte_z = string.byte('z') -local a_to_z = byte_z - byte_a + 1 - --- Table giving the index of the first command in cmdnames[] to lookup --- based on the first letter of a command. -local cmdidxs1_out = string.format( - [[ -static const uint16_t cmdidxs1[%u] = { -]], - a_to_z -) --- Table giving the index of the first command in cmdnames[] to lookup --- based on the first 2 letters of a command. --- Values in cmdidxs2[c1][c2] are relative to cmdidxs1[c1] so that they --- fit in a byte. -local cmdidxs2_out = string.format( - [[ -static const uint8_t cmdidxs2[%u][%u] = { - /* a b c d e f g h i j k l m n o p q r s t u v w x y z */ -]], - a_to_z, - a_to_z -) - -enumfile:write([[ -// IWYU pragma: private, include "nvim/ex_cmds_defs.h" - -typedef enum CMD_index { -]]) -defsfile:write(string.format( - [[ -#include "nvim/arglist.h" -#include "nvim/autocmd.h" -#include "nvim/buffer.h" -#include "nvim/cmdhist.h" -#include "nvim/debugger.h" -#include "nvim/diff.h" -#include "nvim/digraph.h" -#include "nvim/eval.h" -#include "nvim/eval/userfunc.h" -#include "nvim/eval/vars.h" -#include "nvim/ex_cmds.h" -#include "nvim/ex_cmds2.h" -#include "nvim/ex_docmd.h" -#include "nvim/ex_eval.h" -#include "nvim/ex_session.h" -#include "nvim/help.h" -#include "nvim/indent.h" -#include "nvim/lua/executor.h" -#include "nvim/lua/secure.h" -#include "nvim/mapping.h" -#include "nvim/mark.h" -#include "nvim/match.h" -#include "nvim/menu.h" -#include "nvim/message.h" -#include "nvim/ops.h" -#include "nvim/option.h" -#include "nvim/os/lang.h" -#include "nvim/profile.h" -#include "nvim/quickfix.h" -#include "nvim/runtime.h" -#include "nvim/sign.h" -#include "nvim/spell.h" -#include "nvim/spellfile.h" -#include "nvim/syntax.h" -#include "nvim/undo.h" -#include "nvim/usercmd.h" -#include "nvim/version.h" - -static const int command_count = %u; -static CommandDefinition cmdnames[%u] = { -]], - #defs, - #defs -)) -local cmds, cmdidxs1, cmdidxs2 = {}, {}, {} -for _, cmd in ipairs(defs) do - if bit.band(cmd.flags, flags.RANGE) == flags.RANGE then - assert( - cmd.addr_type ~= 'ADDR_NONE', - string.format('ex_cmds.lua:%s: Using RANGE with ADDR_NONE\n', cmd.command) - ) - else - assert( - cmd.addr_type == 'ADDR_NONE', - string.format('ex_cmds.lua:%s: Missing ADDR_NONE\n', cmd.command) - ) - end - if bit.band(cmd.flags, flags.DFLALL) == flags.DFLALL then - assert( - cmd.addr_type ~= 'ADDR_OTHER' and cmd.addr_type ~= 'ADDR_NONE', - string.format('ex_cmds.lua:%s: Missing misplaced DFLALL\n', cmd.command) - ) - end - if bit.band(cmd.flags, flags.PREVIEW) == flags.PREVIEW then - assert( - cmd.preview_func ~= nil, - string.format('ex_cmds.lua:%s: Missing preview_func\n', cmd.command) - ) - end - local enumname = cmd.enum or ('CMD_' .. cmd.command) - local byte_cmd = cmd.command:sub(1, 1):byte() - if byte_a <= byte_cmd and byte_cmd <= byte_z then - table.insert(cmds, cmd.command) - end - local preview_func - if cmd.preview_func then - preview_func = string.format('&%s', cmd.preview_func) - else - preview_func = 'NULL' - end - enumfile:write(' ' .. enumname .. ',\n') - defsfile:write(string.format( - [[ - [%s] = { - .cmd_name = "%s", - .cmd_func = (ex_func_T)&%s, - .cmd_preview_func = %s, - .cmd_argt = %uL, - .cmd_addr_type = %s - }, -]], - enumname, - cmd.command, - cmd.func, - preview_func, - cmd.flags, - cmd.addr_type - )) -end -for i = #cmds, 1, -1 do - local cmd = cmds[i] - -- First and second characters of the command - local c1 = cmd:sub(1, 1) - cmdidxs1[c1] = i - 1 - if cmd:len() >= 2 then - local c2 = cmd:sub(2, 2) - local byte_c2 = string.byte(c2) - if byte_a <= byte_c2 and byte_c2 <= byte_z then - if not cmdidxs2[c1] then - cmdidxs2[c1] = {} - end - cmdidxs2[c1][c2] = i - 1 - end - end -end -for i = byte_a, byte_z do - local c1 = string.char(i) - cmdidxs1_out = cmdidxs1_out .. ' /* ' .. c1 .. ' */ ' .. cmdidxs1[c1] .. ',\n' - cmdidxs2_out = cmdidxs2_out .. ' /* ' .. c1 .. ' */ {' - for j = byte_a, byte_z do - local c2 = string.char(j) - cmdidxs2_out = cmdidxs2_out - .. ((cmdidxs2[c1] and cmdidxs2[c1][c2]) and string.format( - '%3d', - cmdidxs2[c1][c2] - cmdidxs1[c1] - ) or ' 0') - .. ',' - end - cmdidxs2_out = cmdidxs2_out .. ' },\n' -end -enumfile:write([[ - CMD_SIZE, - CMD_USER = -1, - CMD_USER_BUF = -2 -} cmdidx_T; -]]) -defsfile:write(string.format( - [[ -}; -%s}; -%s}; -]], - cmdidxs1_out, - cmdidxs2_out -)) diff --git a/src/nvim/generators/gen_options.lua b/src/nvim/generators/gen_options.lua deleted file mode 100644 index e5dba90925..0000000000 --- a/src/nvim/generators/gen_options.lua +++ /dev/null @@ -1,535 +0,0 @@ ---- @module 'nvim.options' -local options = require('options') -local options_meta = options.options -local cstr = options.cstr -local valid_scopes = options.valid_scopes - ---- @param o vim.option_meta ---- @return string -local function get_values_var(o) - return ('opt_%s_values'):format(o.abbreviation or o.full_name) -end - ---- @param s string ---- @return string -local function lowercase_to_titlecase(s) - return table.concat(vim.tbl_map(function(word) --- @param word string - return word:sub(1, 1):upper() .. word:sub(2) - end, vim.split(s, '[-_]'))) -end - ---- @param scope string ---- @param option_name string ---- @return string -local function get_scope_option(scope, option_name) - return ('k%sOpt%s'):format(lowercase_to_titlecase(scope), lowercase_to_titlecase(option_name)) -end - -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) - --- @type string[] - local flags = { '0' } - - --- @param f string - local function add_flag(f) - table.insert(flags, f) - end - - if o.list then - add_flag(list_flags[o.list]) - end - - for _, r_flag in ipairs(o.redraw or {}) do - add_flag(redraw_flags[r_flag]) - end - - if o.expand then - add_flag('kOptFlagExpand') - if o.expand == 'nodefault' then - add_flag('kOptFlagNoDefExp') - end - end - - for _, flag_desc in ipairs({ - { 'nodefault', 'NoDefault' }, - { 'no_mkrc', 'NoMkrc' }, - { 'secure' }, - { 'gettext' }, - { '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_suffix = flag_desc[1], flag_desc[2] - if o[key_name] then - local def_name = 'kOptFlag' .. (flag_suffix or lowercase_to_titlecase(key_name)) - add_flag(def_name) - end - end - - return table.concat(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_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 s string ---- @return string -local function static_cstr_as_string(s) - return ('{ .data = %s, .size = sizeof(%s) - 1 }'):format(s, s) -end - ---- @param v vim.option_value|function ---- @return string -local function get_opt_val(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 - --- @cast v string - 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 function get_defaults(d, n) - if d == nil then - error("option '" .. n .. "' should have a default value") - end - return get_opt_val(d) -end - ---- @param i integer ---- @param o vim.option_meta ---- @param write fun(...: string) -local function dump_option(i, o, write) - write(' [', ('%u'):format(i - 1) .. ']={') - write(' .fullname=', cstr(o.full_name)) - if o.abbreviation then - write(' .shortname=', cstr(o.abbreviation)) - end - write(' .type=', opt_type_enum(o.type)) - write(' .flags=', get_flags(o)) - write(' .scope_flags=', get_scope_flags(o)) - write(' .scope_idx=', get_scope_idx(o)) - write(' .values=', (o.values and get_values_var(o) or 'NULL')) - write(' .values_len=', (o.values and #o.values or '0')) - write(' .flags_var=', (o.flags_varname and ('&%s'):format(o.flags_varname) or 'NULL')) - if o.enable_if then - write(('#if defined(%s)'):format(o.enable_if)) - end - - local is_window_local = #o.scope == 1 and o.scope[1] == 'win' - - if is_window_local then - write(' .var=NULL') - elseif o.varname then - write(' .var=&', o.varname) - elseif o.immutable then - -- Immutable options can directly point to the default value. - write((' .var=&options[%u].def_val.data'):format(i - 1)) - else - error('Option must be immutable or have a variable.') - end - - write(' .immutable=', (o.immutable and 'true' or 'false')) - write(' .opt_did_set_cb=', o.cb or 'NULL') - write(' .opt_expand_cb=', o.expand_cb or 'NULL') - - if o.enable_if then - write('#else') - -- Hidden option directly points to default value. - write((' .var=&options[%u].def_val.data'):format(i - 1)) - -- Option is always immutable on the false branch of `enable_if`. - write(' .immutable=true') - write('#endif') - end - - if not o.defaults then - write(' .def_val=NIL_OPTVAL') - elseif o.defaults.condition then - write(('#if defined(%s)'):format(o.defaults.condition)) - write(' .def_val=', get_defaults(o.defaults.if_true, o.full_name)) - if o.defaults.if_false then - write('#else') - write(' .def_val=', get_defaults(o.defaults.if_false, o.full_name)) - end - write('#endif') - else - write(' .def_val=', get_defaults(o.defaults.if_true, o.full_name)) - end - - write(' },') -end - ---- @param prefix string ---- @param values vim.option_valid_values -local function preorder_traversal(prefix, values) - local out = {} --- @type string[] - - local function add(s) - table.insert(out, s) - end - - add('') - add(('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 - add((' "%s",'):format(value)) - else - assert(type(value) == 'table' and type(value[1]) == 'string' and type(value[2]) == 'table') - add((' "%s",'):format(value[1])) - table.insert(children, value) - end - end - - add(' NULL') - add('});') - - for _, value in pairs(children) do - -- Remove trailing colon from the added prefix to prevent syntax errors. - add(preorder_traversal(prefix .. '_' .. value[1]:gsub(':$', ''), value[2])) - end - - return table.concat(out, '\n') -end - ---- @param o vim.option_meta ---- @return string -local function gen_opt_enum(o) - local out = {} --- @type string[] - - local function add(s) - table.insert(out, s) - end - - add('') - add('typedef enum {') - - local opt_name = lowercase_to_titlecase(o.abbreviation or o.full_name) - --- @type table<string,integer> - local enum_values - - if type(o.flags) == 'table' then - enum_values = o.flags --[[ @as table<string,integer> ]] - else - enum_values = {} - for i, flag_name in ipairs(o.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 - add( - (' kOpt%sFlag%s = 0x%02x,'):format( - opt_name, - lowercase_to_titlecase(flag_name:gsub(':$', '')), - enum_values[flag_name] - ) - ) - end - - add(('} Opt%sFlags;'):format(opt_name)) - - return table.concat(out, '\n') -end - ---- @param output_file string ---- @return table<string,string> options_index Map of option name to option index -local function gen_enums(output_file) - --- Options for each scope. - --- @type table<string, vim.option_meta[]> - local scope_options = {} - for _, scope in ipairs(valid_scopes) do - scope_options[scope] = {} - end - - local fd = assert(io.open(output_file, 'w')) - - --- @param s string - local function write(s) - fd:write(s) - fd:write('\n') - end - - -- Generate options enum file - write('// IWYU pragma: private, include "nvim/option_defs.h"') - write('') - - --- 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. - write('typedef enum {') - write(' kOptInvalid = -1,') - - for i, o in ipairs(options_meta) do - local enum_val_name = 'kOpt' .. lowercase_to_titlecase(o.full_name) - write((' %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 - - local alias = o.alias or {} --[[@as string[] ]] - for _, v in ipairs(alias) do - option_index[v] = enum_val_name - end - - for _, scope in ipairs(o.scope) do - table.insert(scope_options[scope], o) - end - end - - write(' // Option count') - write('#define kOptCount ' .. tostring(#options_meta)) - write('} OptIndex;') - - -- Generate option index enum for each scope - for _, scope in ipairs(valid_scopes) do - write('') - - local scope_name = lowercase_to_titlecase(scope) - write('typedef enum {') - write((' %s = -1,'):format(get_scope_option(scope, 'Invalid'))) - - for idx, option in ipairs(scope_options[scope]) do - write((' %s = %u,'):format(get_scope_option(scope, option.full_name), idx - 1)) - end - - write((' // %s option count'):format(scope_name)) - write(('#define %s %d'):format(get_scope_option(scope, 'Count'), #scope_options[scope])) - write(('} %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 - write('') - write(('EXTERN const OptIndex %s_opt_idx[] INIT( = {'):format(scope)) - for _, option in ipairs(scope_options[scope]) do - local idx = option_index[option.full_name] - write((' [%s] = %s,'):format(get_scope_option(scope, option.full_name), idx)) - end - write('});') - end - - fd:close() - - return option_index -end - ---- @param output_file string ---- @param option_index table<string,string> -local function gen_map(output_file, option_index) - -- 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 - ) - - local fd = assert(io.open(output_file, 'w')) - - --- @param s string - local function write(s) - fd:write(s) - fd:write('\n') - end - - write('static const struct { const char *name; OptIndex opt_idx; } option_hash_elems[] = {') - - for _, name in ipairs(neworder) do - assert(option_index[name] ~= nil) - write((' { .name = "%s", .opt_idx = %s },'):format(name, option_index[name])) - end - - write('};') - write('') - write('static ' .. hashfun) - - fd:close() -end - ---- @param output_file string -local function gen_vars(output_file) - local fd = assert(io.open(output_file, 'w')) - - --- @param s string - local function write(s) - fd:write(s) - fd:write('\n') - end - - write('// IWYU pragma: private, include "nvim/option_vars.h"') - - -- Generate enums for option flags. - for _, o in ipairs(options_meta) do - if o.flags and (type(o.flags) == 'table' or o.values) then - write(gen_opt_enum(o)) - end - end - - -- Generate valid values for each option. - for _, option in ipairs(options_meta) do - -- Since option values can be nested, we need to do preorder traversal to generate the values. - if option.values then - local values_var = ('opt_%s'):format(option.abbreviation or option.full_name) - write(preorder_traversal(values_var, option.values)) - end - end - - fd:close() -end - ---- @param output_file string -local function gen_options(output_file) - local fd = assert(io.open(output_file, 'w')) - - --- @param ... string - local function write(...) - local s = table.concat({ ... }, '') - fd:write(s) - if s:match('^ %.') then - fd:write(',') - end - fd:write('\n') - end - - -- Generate options[] array. - write([[ - #include "nvim/ex_docmd.h" - #include "nvim/ex_getln.h" - #include "nvim/insexpand.h" - #include "nvim/mapping.h" - #include "nvim/ops.h" - #include "nvim/option.h" - #include "nvim/optionstr.h" - #include "nvim/quickfix.h" - #include "nvim/runtime.h" - #include "nvim/tag.h" - #include "nvim/window.h" - - static vimoption_T options[] = {]]) - - for i, o in ipairs(options_meta) do - dump_option(i, o, write) - end - - write('};') - - fd:close() -end - -local function main() - local options_file = arg[1] - local options_enum_file = arg[2] - local options_map_file = arg[3] - local option_vars_file = arg[4] - - local option_index = gen_enums(options_enum_file) - gen_map(options_map_file, option_index) - gen_vars(option_vars_file) - gen_options(options_file) -end - -main() diff --git a/src/nvim/generators/gen_vimvim.lua b/src/nvim/generators/gen_vimvim.lua deleted file mode 100644 index 3817735a55..0000000000 --- a/src/nvim/generators/gen_vimvim.lua +++ /dev/null @@ -1,156 +0,0 @@ -local mpack = vim.mpack - -local syntax_file = arg[1] -local funcs_file = arg[2] - -local lld = {} -local syn_fd = io.open(syntax_file, 'w') -lld.line_length = 0 -local function w(s) - syn_fd:write(s) - if s:find('\n') then - lld.line_length = #(s:gsub('.*\n', '')) - else - lld.line_length = lld.line_length + #s - end -end - -local options = require('options') -local auevents = require('auevents') -local ex_cmds = require('ex_cmds') - -local function cmd_kw(prev_cmd, cmd) - if not prev_cmd then - return cmd:sub(1, 1) .. '[' .. cmd:sub(2) .. ']' - else - local shift = 1 - while cmd:sub(shift, shift) == prev_cmd:sub(shift, shift) do - shift = shift + 1 - end - if cmd:sub(1, shift) == 'def' then - shift = shift + 1 - end - if shift >= #cmd then - return cmd - else - return cmd:sub(1, shift) .. '[' .. cmd:sub(shift + 1) .. ']' - end - end -end - --- Exclude these from the vimCommand keyword list, they are handled specially --- in syntax/vim.vim (vimAugroupKey, vimAutoCmd, vimGlobal, vimSubst). #9327 -local function is_special_cased_cmd(cmd) - return ( - cmd == 'augroup' - or cmd == 'autocmd' - or cmd == 'doautocmd' - or cmd == 'doautoall' - or cmd == 'global' - or cmd == 'substitute' - ) -end - -local vimcmd_start = 'syn keyword vimCommand contained ' -local vimcmd_end = ' nextgroup=vimBang' -w(vimcmd_start) - -local prev_cmd = nil -for _, cmd_desc in ipairs(ex_cmds.cmds) do - if lld.line_length > 850 then - w(vimcmd_end .. '\n' .. vimcmd_start) - end - local cmd = cmd_desc.command - if cmd:match('%w') and cmd ~= 'z' and not is_special_cased_cmd(cmd) then - w(' ' .. cmd_kw(prev_cmd, cmd)) - end - if cmd == 'delete' then - -- Add special abbreviations of :delete - w(' ' .. cmd_kw('d', 'dl')) - w(' ' .. cmd_kw('del', 'dell')) - w(' ' .. cmd_kw('dele', 'delel')) - w(' ' .. cmd_kw('delet', 'deletl')) - w(' ' .. cmd_kw('delete', 'deletel')) - w(' ' .. cmd_kw('d', 'dp')) - w(' ' .. cmd_kw('de', 'dep')) - w(' ' .. cmd_kw('del', 'delp')) - w(' ' .. cmd_kw('dele', 'delep')) - w(' ' .. cmd_kw('delet', 'deletp')) - w(' ' .. cmd_kw('delete', 'deletep')) - end - prev_cmd = cmd -end - -w(vimcmd_end .. '\n') - -local vimopt_start = 'syn keyword vimOption contained ' -local vimopt_end = ' skipwhite nextgroup=vimSetEqual,vimSetMod' -w('\n' .. vimopt_start) - -for _, opt_desc in ipairs(options.options) do - if not opt_desc.immutable then - if lld.line_length > 850 then - w(vimopt_end .. '\n' .. vimopt_start) - end - w(' ' .. opt_desc.full_name) - if opt_desc.abbreviation then - w(' ' .. opt_desc.abbreviation) - end - if opt_desc.type == 'boolean' then - w(' inv' .. opt_desc.full_name) - w(' no' .. opt_desc.full_name) - if opt_desc.abbreviation then - w(' inv' .. opt_desc.abbreviation) - w(' no' .. opt_desc.abbreviation) - end - end - end -end - -w(vimopt_end .. '\n') - -w('\nsyn case ignore') -local vimau_start = 'syn keyword vimAutoEvent contained ' -w('\n\n' .. vimau_start) - -for _, au in ipairs(auevents.events) do - if not auevents.nvim_specific[au[1]] then - if lld.line_length > 850 then - w('\n' .. vimau_start) - end - w(' ' .. au[1]) - for _, alias in ipairs(au[2]) do - if lld.line_length > 850 then - w('\n' .. vimau_start) - end - -- au[1] is aliased to alias - w(' ' .. alias) - end - end -end - -local nvimau_start = 'syn keyword nvimAutoEvent contained ' -w('\n\n' .. nvimau_start) - -for au, _ in vim.spairs(auevents.nvim_specific) do - if lld.line_length > 850 then - w('\n' .. nvimau_start) - end - w(' ' .. au) -end - -w('\n\nsyn case match') -local vimfun_start = 'syn keyword vimFuncName contained ' -w('\n\n' .. vimfun_start) -local funcs = mpack.decode(io.open(funcs_file, 'rb'):read('*all')) -for _, name in ipairs(funcs) do - if name then - if lld.line_length > 850 then - w('\n' .. vimfun_start) - end - w(' ' .. name) - end -end - -w('\n') -syn_fd:close() diff --git a/src/nvim/generators/hashy.lua b/src/nvim/generators/hashy.lua deleted file mode 100644 index 74b7655324..0000000000 --- a/src/nvim/generators/hashy.lua +++ /dev/null @@ -1,145 +0,0 @@ --- HASHY McHASHFACE - -local M = {} -_G.d = M - -local function setdefault(table, key) - local val = table[key] - if val == nil then - val = {} - table[key] = val - end - return val -end - -function M.build_pos_hash(strings) - local len_buckets = {} - local maxlen = 0 - for _, s in ipairs(strings) do - table.insert(setdefault(len_buckets, #s), s) - if #s > maxlen then - maxlen = #s - end - end - - local len_pos_buckets = {} - local worst_buck_size = 0 - - for len = 1, maxlen do - local strs = len_buckets[len] - if strs then - -- the best position so far generates `best_bucket` - -- with `minsize` worst case collisions - local bestpos, minsize, best_bucket = nil, #strs * 2, nil - for pos = 1, len do - local try_bucket = {} - for _, str in ipairs(strs) do - local poschar = string.sub(str, pos, pos) - table.insert(setdefault(try_bucket, poschar), str) - end - local maxsize = 1 - for _, pos_strs in pairs(try_bucket) do - maxsize = math.max(maxsize, #pos_strs) - end - if maxsize < minsize then - bestpos = pos - minsize = maxsize - best_bucket = try_bucket - end - end - len_pos_buckets[len] = { bestpos, best_bucket } - worst_buck_size = math.max(worst_buck_size, minsize) - end - end - return len_pos_buckets, maxlen, worst_buck_size -end - -function M.switcher(put, tab, maxlen, worst_buck_size) - local neworder = {} --- @type string[] - put ' switch (len) {\n' - local bucky = worst_buck_size > 1 - for len = 1, maxlen do - local vals = tab[len] - if vals then - put(' case ' .. len .. ': ') - local pos, posbuck = unpack(vals) - local keys = vim.tbl_keys(posbuck) - if #keys > 1 then - table.sort(keys) - put('switch (str[' .. (pos - 1) .. ']) {\n') - for _, c in ipairs(keys) do - local buck = posbuck[c] - local startidx = #neworder - vim.list_extend(neworder, buck) - local endidx = #neworder - put(" case '" .. c .. "': ") - if len == 1 then - put('return ' .. startidx .. ';\n') - else - put('low = ' .. startidx .. '; ') - if bucky then - put('high = ' .. endidx .. '; ') - end - put 'break;\n' - end - end - put ' default: break;\n' - put ' }\n ' - else - local startidx = #neworder - table.insert(neworder, posbuck[keys[1]][1]) - local endidx = #neworder - put('low = ' .. startidx .. '; ') - if bucky then - put('high = ' .. endidx .. '; ') - end - end - put 'break;\n' - end - end - put ' default: break;\n' - put ' }\n' - return neworder -end - -function M.hashy_hash(name, strings, access) - local stats = {} - local put = function(str) - table.insert(stats, str) - end - local len_pos_buckets, maxlen, worst_buck_size = M.build_pos_hash(strings) - put('int ' .. name .. '_hash(const char *str, size_t len)\n{\n') - if maxlen == 1 then - put('\n') -- nothing - elseif worst_buck_size > 1 then - put(' int low = 0, high = 0;\n') - else - put(' int low = -1;\n') - end - local neworder = M.switcher(put, len_pos_buckets, maxlen, worst_buck_size) - if maxlen == 1 then - put([[ - return -1; -]]) - elseif worst_buck_size > 1 then - put([[ - for (int i = low; i < high; i++) { - if (!memcmp(str, ]] .. access('i') .. [[, len)) { - return i; - } - } - return -1; -]]) - else - put([[ - if (low < 0 || memcmp(str, ]] .. access('low') .. [[, len)) { - return -1; - } - return low; -]]) - end - put '}\n\n' - return neworder, table.concat(stats) -end - -return M diff --git a/src/nvim/generators/nvim_version.lua.in b/src/nvim/generators/nvim_version.lua.in deleted file mode 100644 index c29141fc68..0000000000 --- a/src/nvim/generators/nvim_version.lua.in +++ /dev/null @@ -1,9 +0,0 @@ -return { - {"major", ${NVIM_VERSION_MAJOR}}, - {"minor", ${NVIM_VERSION_MINOR}}, - {"patch", ${NVIM_VERSION_PATCH}}, - {"prerelease", "${NVIM_VERSION_PRERELEASE}" ~= ""}, - {"api_level", ${NVIM_API_LEVEL}}, - {"api_compatible", ${NVIM_API_LEVEL_COMPAT}}, - {"api_prerelease", ${NVIM_API_PRERELEASE}}, -} diff --git a/src/nvim/generators/preload.lua b/src/nvim/generators/preload.lua deleted file mode 100644 index e14671074c..0000000000 --- a/src/nvim/generators/preload.lua +++ /dev/null @@ -1,13 +0,0 @@ -local srcdir = table.remove(arg, 1) -local nlualib = table.remove(arg, 1) -local gendir = table.remove(arg, 1) -package.path = srcdir .. '/src/nvim/?.lua;' .. srcdir .. '/runtime/lua/?.lua;' .. package.path -package.path = gendir .. '/?.lua;' .. package.path -_G.vim = require 'vim.shared' -_G.vim.inspect = require 'vim.inspect' -package.cpath = package.cpath .. ';' .. nlualib -require 'nlua0' -vim.NIL = vim.mpack.NIL -- WOW BOB WOW - -arg[0] = table.remove(arg, 1) -return loadfile(arg[0])() |