diff options
Diffstat (limited to 'src/nvim/generators')
-rw-r--r-- | src/nvim/generators/c_grammar.lua | 13 | ||||
-rw-r--r-- | src/nvim/generators/gen_api_dispatch.lua | 258 | ||||
-rw-r--r--[-rwxr-xr-x] | src/nvim/generators/gen_api_ui_events.lua | 21 | ||||
-rw-r--r--[-rwxr-xr-x] | src/nvim/generators/gen_declarations.lua | 28 | ||||
-rw-r--r-- | src/nvim/generators/gen_eval.lua | 53 | ||||
-rw-r--r-- | src/nvim/generators/gen_events.lua | 36 | ||||
-rw-r--r-- | src/nvim/generators/gen_ex_cmds.lua | 29 | ||||
-rw-r--r-- | src/nvim/generators/gen_keysets.lua | 80 | ||||
-rw-r--r-- | src/nvim/generators/gen_options.lua | 61 | ||||
-rw-r--r-- | src/nvim/generators/gen_vimvim.lua | 147 | ||||
-rw-r--r-- | src/nvim/generators/preload.lua | 10 |
11 files changed, 463 insertions, 273 deletions
diff --git a/src/nvim/generators/c_grammar.lua b/src/nvim/generators/c_grammar.lua index 3e89b60b4a..f33da452ff 100644 --- a/src/nvim/generators/c_grammar.lua +++ b/src/nvim/generators/c_grammar.lua @@ -1,4 +1,4 @@ -local lpeg = require('lpeg') +local lpeg = vim.lpeg -- lpeg grammar for building api metadata from a set of header files. It -- ignores comments and preprocessor commands and parses a very small subset @@ -47,7 +47,8 @@ local c_proto = Ct( (fill * Cg((P('FUNC_API_NOEXPORT') * Cc(true)), 'noexport') ^ -1) * (fill * Cg((P('FUNC_API_REMOTE_ONLY') * Cc(true)), 'remote_only') ^ -1) * (fill * Cg((P('FUNC_API_LUA_ONLY') * Cc(true)), 'lua_only') ^ -1) * - (fill * Cg((P('FUNC_API_CHECK_TEXTLOCK') * Cc(true)), 'check_textlock') ^ -1) * + (fill * (Cg(P('FUNC_API_TEXTLOCK_ALLOW_CMDWIN') * Cc(true), 'textlock_allow_cmdwin') + + Cg(P('FUNC_API_TEXTLOCK') * Cc(true), 'textlock')) ^ -1) * (fill * Cg((P('FUNC_API_REMOTE_IMPL') * Cc(true)), 'remote_impl') ^ -1) * (fill * Cg((P('FUNC_API_COMPOSITOR_IMPL') * Cc(true)), 'compositor_impl') ^ -1) * (fill * Cg((P('FUNC_API_CLIENT_IMPL') * Cc(true)), 'client_impl') ^ -1) * @@ -55,5 +56,11 @@ local c_proto = Ct( fill * P(';') ) -local grammar = Ct((c_proto + c_comment + c_preproc + ws) ^ 1) +local c_field = Ct(Cg(c_id, 'type') * ws * Cg(c_id, 'name') * fill * P(';') * fill) +local c_keyset = Ct( + P('typedef') * ws * P('struct') * fill * P('{') * fill * + Cg(Ct(c_field ^ 1), 'fields') * + P('}') * fill * P('Dict') * fill * P('(') * Cg(c_id, 'keyset_name') * fill * P(')') * P(';')) + +local grammar = Ct((c_proto + c_comment + c_preproc + ws + c_keyset) ^ 1) return {grammar=grammar, typed_container=typed_container} diff --git a/src/nvim/generators/gen_api_dispatch.lua b/src/nvim/generators/gen_api_dispatch.lua index 35f6bf8455..9720cca477 100644 --- a/src/nvim/generators/gen_api_dispatch.lua +++ b/src/nvim/generators/gen_api_dispatch.lua @@ -1,38 +1,23 @@ -local mpack = require('mpack') - --- we need at least 4 arguments since the last two are output files -if arg[1] == '--help' then - print('Usage: genmsgpack.lua args') - print('Args: 1: source directory') - print(' 2: dispatch output file (dispatch_wrappers.generated.h)') - print(' 3: functions metadata output file (funcs_metadata.generated.h)') - print(' 4: API metadata output file (api_metadata.mpack)') - print(' 5: lua C bindings output file (lua_api_c_bindings.generated.c)') - print(' rest: C files where API functions are defined') -end -assert(#arg >= 4) -local functions = {} +local mpack = vim.mpack -local nvimdir = arg[1] -package.path = nvimdir .. '/?.lua;' .. package.path +local hashy = require'generators.hashy' -_G.vim = loadfile(nvimdir..'/../../runtime/lua/vim/shared.lua')() -_G.vim.inspect = loadfile(nvimdir..'/../../runtime/lua/vim/inspect.lua')() +assert(#arg >= 5) +-- output h file with generated dispatch functions (dispatch_wrappers.generated.h) +local dispatch_outputf = arg[1] +-- output h file with packed metadata (funcs_metadata.generated.h) +local funcs_metadata_outputf = arg[2] +-- output metadata mpack file, for use by other build scripts (api_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 hashy = require'generators.hashy' +local functions = {} -- names of all headers relative to the source root (for inclusion in the -- generated file) local headers = {} --- output h file with generated dispatch functions -local dispatch_outputf = arg[2] --- output h file with packed metadata -local funcs_metadata_outputf = arg[3] --- output metadata mpack file, for use by other build scripts -local mpack_outputf = arg[4] -local lua_c_bindings_outputf = arg[5] - -- set of function names, used to detect duplicates local function_names = {} @@ -42,6 +27,69 @@ local function startswith(String,Start) return string.sub(String,1,string.len(Start))==Start end +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] == 'arena' then + -- return value is allocated in an arena + fn.arena_return = true + 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 + end +end + +local keysets = {} + +local function add_keyset(val) + local keys = {} + local types = {} + local is_set_name = 'is_set__' .. val.keyset_name .. '_' + local has_optional = false + for i,field in ipairs(val.fields) do + if field.type ~= 'Object' then + types[field.name] = field.type + end + if field.name ~= is_set_name and field.type ~= 'OptionalKeys' then + table.insert(keys, field.name) + 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, types=types, has_optional=has_optional}) +end + -- read each input file, parse and append to the api metadata for i = 6, #arg do local full_path = arg[i] @@ -55,39 +103,11 @@ for i = 6, #arg do local tmp = c_grammar.grammar:match(input:read('*all')) for j = 1, #tmp do - local fn = tmp[j] - local public = startswith(fn.name, "nvim_") or fn.deprecated_since - if public and not fn.noexport then - functions[#functions + 1] = tmp[j] - 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] == 'arena' then - -- return value is allocated in an arena - fn.arena_return = true - 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 + local val = tmp[j] + if val.keyset_name then + add_keyset(val) + else + add_function(val) end end input:close() @@ -187,7 +207,7 @@ end -- serialize the API metadata using msgpack and embed into the resulting -- binary for easy querying by clients local funcs_metadata_output = io.open(funcs_metadata_outputf, 'wb') -local packed = mpack.pack(exported_functions) +local packed = mpack.encode(exported_functions) local dump_bin_array = require("generators.dump_bin_array") dump_bin_array(funcs_metadata_output, 'funcs_metadata', packed) funcs_metadata_output:close() @@ -195,6 +215,7 @@ funcs_metadata_output:close() -- start building the dispatch wrapper output local output = io.open(dispatch_outputf, 'wb') +local keysets_defs = io.open(keysets_outputf, 'wb') -- =========================================================================== -- NEW API FILES MUST GO HERE. @@ -203,10 +224,11 @@ local output = io.open(dispatch_outputf, 'wb') -- so that the dispatcher can find the C functions that you are creating! -- =========================================================================== output:write([[ +#include "nvim/ex_docmd.h" +#include "nvim/ex_getln.h" #include "nvim/log.h" -#include "nvim/map.h" +#include "nvim/map_defs.h" #include "nvim/msgpack_rpc/helpers.h" -#include "nvim/vim.h" #include "nvim/api/autocmd.h" #include "nvim/api/buffer.h" @@ -224,6 +246,62 @@ output:write([[ ]]) +for _,k in ipairs(keysets) do + local c_name = {} + + for i = 1,#k.keys do + -- some keys, like "register" are c keywords and get + -- escaped with a trailing _ in the struct. + if vim.endswith(k.keys[i], "_") then + local orig = k.keys[i] + k.keys[i] = string.sub(k.keys[i],1, #(k.keys[i]) - 1) + c_name[k.keys[i]] = orig + k.types[k.keys[i]] = k.types[orig] + end + end + + 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[];\n") + + local function typename(type) + if type ~= nil then + return "kObjectType"..type + else + return "kObjectTypeNil" + 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..", "..(c_name[key] or key).."), "..typename(k.types[key])..", "..ind.."},\n") + end + output:write(' {NULL, 0, kObjectTypeNil, -1},\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]; +} + +]]) + keysets_defs:write("#define api_free_keydict_"..k.name.."(x) api_free_keydict(x, "..k.name.."_table)\n") +end + local function real_type(type) local rv = type local rmatch = string.match(type, "Dict%(([_%w]+)%)") @@ -257,9 +335,8 @@ for i = 1, #functions do output:write('Object handle_'..fn.name..'(uint64_t channel_id, Array args, Arena* arena, Error *error)') output:write('\n{') - output:write('\n#if MIN_LOG_LEVEL <= LOGLVL_DBG') - output:write('\n logmsg(LOGLVL_DBG, "RPC: ", NULL, -1, true, "ch %" PRIu64 ": invoke ' - ..fn.name..'", channel_id);') + 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 @@ -337,8 +414,13 @@ for i = 1, #functions do args[#args + 1] = converted end - if fn.check_textlock then - output:write('\n if (textlock != 0) {') + 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') @@ -444,8 +526,9 @@ output:write(hashfun) output:close() +functions.keysets = keysets local mpack_output = io.open(mpack_outputf, 'wb') -mpack_output:write(mpack.pack(functions)) +mpack_output:write(mpack.encode(functions)) mpack_output:close() local function include_headers(output_handle, headers_to_include) @@ -467,15 +550,16 @@ end output = io.open(lua_c_bindings_outputf, 'wb') output:write([[ -// This is an open source non-commercial project. Dear PVS-Studio, please check -// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com #include <lua.h> #include <lualib.h> #include <lauxlib.h> +#include "nvim/ex_docmd.h" +#include "nvim/ex_getln.h" #include "nvim/func_attr.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" +#include "nvim/api/private/dispatch.h" #include "nvim/lua/converter.h" #include "nvim/lua/executor.h" #include "nvim/memory.h" @@ -493,6 +577,7 @@ local function process_function(fn) static int %s(lua_State *lstate) { Error err = ERROR_INIT; + char *err_param = 0; if (lua_gettop(lstate) != %i) { api_set_error(&err, kErrorTypeValidation, "Expected %i argument%s"); goto exit_0; @@ -512,9 +597,16 @@ local function process_function(fn) ]], fn.name)) end - if fn.check_textlock then + if fn.textlock then write_shifted_output(output, [[ - if (textlock != 0) { + 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(output, [[ + if (textlock != 0 || expr_map_locked()) { api_set_error(&err, kErrorTypeException, "%s", e_textlock); goto exit_0; } @@ -533,19 +625,22 @@ local function process_function(fn) extra = "true, " end local errshift = 0 + local seterr = '' if string.match(param_type, '^KeyDict_') then write_shifted_output(output, string.format([[ - %s %s = { 0 }; nlua_pop_keydict(lstate, &%s, %s_get_field, %s&err);]], param_type, cparam, cparam, param_type, extra)) + %s %s = { 0 }; nlua_pop_keydict(lstate, &%s, %s_get_field, &err_param, &err);]], param_type, cparam, cparam, param_type)) cparam = '&'..cparam errshift = 1 -- free incomplete dict on error else write_shifted_output(output, string.format([[ const %s %s = nlua_pop_%s(lstate, %s&err);]], param[1], cparam, param_type, extra)) + seterr = [[ + err_param = "]]..param[2]..[[";]] end write_shifted_output(output, string.format([[ - if (ERROR_SET(&err)) { + if (ERROR_SET(&err)) {]]..seterr..[[ goto exit_%u; } @@ -589,9 +684,14 @@ local function process_function(fn) exit_0: 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, 2); + lua_concat(lstate, err_param ? 5 : 2); return lua_error(lstate); } ]] @@ -620,9 +720,10 @@ local function process_function(fn) } ]], return_type)) else + local special = (fn.since ~= nil and fn.since < 11) write_shifted_output(output, string.format([[ - nlua_push_%s(lstate, ret, true); - ]], return_type)) + nlua_push_%s(lstate, ret, %s); + ]], return_type, tostring(special))) end write_shifted_output(output, string.format([[ @@ -670,3 +771,4 @@ output:write([[ ]]) 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 index 827097f69d..e2af5f8d44 100755..100644 --- a/src/nvim/generators/gen_api_ui_events.lua +++ b/src/nvim/generators/gen_api_ui_events.lua @@ -1,19 +1,15 @@ -local mpack = require('mpack') +local mpack = vim.mpack -local nvimdir = arg[1] -package.path = nvimdir .. '/?.lua;' .. package.path - -assert(#arg == 6) -local input = io.open(arg[2], 'rb') -local call_output = io.open(arg[3], 'wb') -local remote_output = io.open(arg[4], 'wb') -local metadata_output = io.open(arg[5], 'wb') -local client_output = io.open(arg[6], 'wb') +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')) -_G.vim = loadfile(nvimdir..'/../../runtime/lua/vim/shared.lua')() local hashy = require'generators.hashy' local function write_signature(output, ev, prefix, notype) @@ -120,7 +116,6 @@ for i = 1, #events do if ev.remote_only then call_output:write(' Array args = call_buf;\n') write_arglist(call_output, ev) - call_output:write(' UI_LOG('..ev.name..');\n') call_output:write(' ui_call_event("'..ev.name..'", args);\n') elseif ev.compositor_impl then call_output:write(' ui_comp_'..ev.name) @@ -195,7 +190,7 @@ for _,ev in ipairs(events) do end end -local packed = mpack.pack(exported_events) +local packed = mpack.encode(exported_events) local dump_bin_array = require("generators.dump_bin_array") dump_bin_array(metadata_output, 'ui_events_metadata', packed) metadata_output:close() diff --git a/src/nvim/generators/gen_declarations.lua b/src/nvim/generators/gen_declarations.lua index 4097ff7dc5..f9e9c6b0a8 100755..100644 --- a/src/nvim/generators/gen_declarations.lua +++ b/src/nvim/generators/gen_declarations.lua @@ -1,12 +1,9 @@ -#!/usr/bin/lua - local fname = arg[1] local static_fname = arg[2] local non_static_fname = arg[3] local preproc_fname = arg[4] - -local lpeg = require('lpeg') +local lpeg = vim.lpeg local fold = function (func, ...) local result = nil @@ -174,7 +171,7 @@ 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. +functions found in definitions.i are needed and to generate an IWYU comment. Additionally uses the following environment variables: @@ -227,6 +224,18 @@ local non_static = header .. [[ local static = header +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 ~= nil then + header_f:close() + non_static = ([[ +// IWYU pragma: private, include "%s" +]]):format(header_fname:gsub('.*/src/nvim/', 'nvim/')) .. non_static + end +end + local filepattern = '^#%a* (%d+) "([^"]-)/?([^"/]+)"' local init = 1 @@ -244,12 +253,7 @@ while init ~= nil do curfile = file is_needed_file = (curfile == neededfile) declline = tonumber(line) - 1 - local curdir_start = dir:find('src/nvim/') - if curdir_start ~= nil then - curdir = dir:sub(curdir_start + #('src/nvim/')) - else - curdir = dir - end + curdir = dir:gsub('.*/src/nvim/', '') else declline = declline - 1 end @@ -311,7 +315,7 @@ F = io.open(static_fname, 'w') F:write(static) F:close() --- Before generating the non-static headers, check if the current file(if +-- Before generating the non-static headers, check if the current file (if -- exists) is different from the new one. If they are the same, we won't touch -- the current version to avoid triggering an unnecessary rebuilds of modules -- that depend on this one diff --git a/src/nvim/generators/gen_eval.lua b/src/nvim/generators/gen_eval.lua index baed6a74c2..7b272c337e 100644 --- a/src/nvim/generators/gen_eval.lua +++ b/src/nvim/generators/gen_eval.lua @@ -1,37 +1,23 @@ -local mpack = require('mpack') +local mpack = vim.mpack -local nvimsrcdir = arg[1] -local shared_file = arg[2] -local autodir = arg[3] -local metadata_file = arg[4] -local funcs_file = arg[5] - -_G.vim = loadfile(shared_file)() - -if nvimsrcdir == '--help' then - print([[ -Usage: - lua gen_eval.lua src/nvim build/src/nvim/auto - -Will generate build/src/nvim/auto/funcs.generated.h with definition of functions -static const array. -]]) - os.exit(0) -end - -package.path = nvimsrcdir .. '/?.lua;' .. package.path +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 = io.open(funcsfname, 'wb') +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/funcs.h" #include "nvim/eval/typval.h" @@ -46,11 +32,16 @@ hashpipe:write([[ #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" ]]) @@ -62,7 +53,7 @@ for _, func in pairs(funcs) do end end -local metadata = mpack.unpack(io.open(metadata_file, 'rb'):read("*all")) +local metadata = mpack.decode(io.open(metadata_file, 'rb'):read("*all")) for _,fun in ipairs(metadata) do if fun.eval then funcs[fun.name] = { @@ -73,16 +64,22 @@ for _,fun in ipairs(metadata) do end end -local func_names = vim.tbl_keys(funcs) +local func_names = vim.tbl_filter(function(name) + return name:match('__%d*$') == nil +end, vim.tbl_keys(funcs)) + table.sort(func_names) -local funcsdata = io.open(funcs_file, 'w') -funcsdata:write(mpack.pack(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 @@ -93,12 +90,12 @@ for _, name in ipairs(neworder) do end local base = def.base or "BASE_NONE" local func = def.func or ('f_' .. name) - local data = def.data or "{ .nullptr = NULL }" + 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, { .nullptr = NULL } },\n') +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 index 8db7f22452..4763a2f463 100644 --- a/src/nvim/generators/gen_events.lua +++ b/src/nvim/generators/gen_events.lua @@ -1,13 +1,5 @@ -if arg[1] == '--help' then - print('Usage: gen_events.lua src/nvim enum_file event_names_file') - os.exit(0) -end - -local nvimsrcdir = arg[1] -local fileio_enum_file = arg[2] -local names_file = arg[3] - -package.path = nvimsrcdir .. '/?.lua;' .. package.path +local fileio_enum_file = arg[1] +local names_file = arg[2] local auevents = require('auevents') local events = auevents.events @@ -16,7 +8,10 @@ local aliases = auevents.aliases local enum_tgt = io.open(fileio_enum_file, 'w') local names_tgt = io.open(names_file, 'w') -enum_tgt:write('typedef enum auto_event {') +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; @@ -43,27 +38,24 @@ names_tgt:write('\n {0, NULL, (event_T)0},') enum_tgt:write('\n} event_T;\n') names_tgt:write('\n};\n') -local gen_autopat_events = function(name) - names_tgt:write(string.format('\nstatic AutoPat *%s[NUM_EVENTS] = {\n ', name)) +do + names_tgt:write('\nstatic AutoCmdVec autocmds[NUM_EVENTS] = {\n ') local line_len = 1 for _ = 1,((#events) - 1) do - line_len = line_len + #(' NULL,') + line_len = line_len + #(' KV_INITIAL_VALUE,') if line_len > 80 then names_tgt:write('\n ') - line_len = 1 + #(' NULL,') + line_len = 1 + #(' KV_INITIAL_VALUE,') end - names_tgt:write(' NULL,') + names_tgt:write(' KV_INITIAL_VALUE,') end - if line_len + #(' NULL') > 80 then - names_tgt:write('\n NULL') + if line_len + #(' KV_INITIAL_VALUE') > 80 then + names_tgt:write('\n KV_INITIAL_VALUE') else - names_tgt:write(' NULL') + names_tgt:write(' KV_INITIAL_VALUE') end names_tgt:write('\n};\n') end -gen_autopat_events("first_autopat") -gen_autopat_events("last_autopat") - enum_tgt:close() names_tgt:close() diff --git a/src/nvim/generators/gen_ex_cmds.lua b/src/nvim/generators/gen_ex_cmds.lua index 0c1051b04e..ae8c952648 100644 --- a/src/nvim/generators/gen_ex_cmds.lua +++ b/src/nvim/generators/gen_ex_cmds.lua @@ -1,20 +1,8 @@ -local nvimsrcdir = arg[1] -local includedir = arg[2] -local autodir = arg[3] +local includedir = arg[1] +local autodir = arg[2] -if nvimsrcdir == '--help' then - print ([[ -Usage: - lua genex_cmds.lua src/nvim build/include build/src/nvim/auto - -Will generate files build/include/ex_cmds_enum.generated.h with cmdidx_T -enum and build/src/nvim/auto/ex_cmds_defs.generated.h with main Ex commands -definitions. -]]) - os.exit(0) -end - -package.path = nvimsrcdir .. '/?.lua;' .. package.path +-- 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' @@ -41,11 +29,13 @@ static const uint16_t cmdidxs1[%u] = { -- Values in cmdidxs2[c1][c2] are relative to cmdidxs1[c1] so that they -- fit in a byte. local cmdidxs2_out = string.format([[ -static const char_u cmdidxs2[%u][%u] = { +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([[ @@ -66,8 +56,8 @@ defsfile:write(string.format([[ #include "nvim/ex_session.h" #include "nvim/help.h" #include "nvim/indent.h" -#include "nvim/locale.h" #include "nvim/lua/executor.h" +#include "nvim/lua/secure.h" #include "nvim/mapping.h" #include "nvim/mark.h" #include "nvim/match.h" @@ -75,6 +65,7 @@ defsfile:write(string.format([[ #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" @@ -113,7 +104,7 @@ for _, cmd in ipairs(defs) do end local preview_func if cmd.preview_func then - preview_func = string.format("(ex_preview_func_T)&%s", cmd.preview_func) + preview_func = string.format("&%s", cmd.preview_func) else preview_func = "NULL" end diff --git a/src/nvim/generators/gen_keysets.lua b/src/nvim/generators/gen_keysets.lua deleted file mode 100644 index b1c1f3e2d8..0000000000 --- a/src/nvim/generators/gen_keysets.lua +++ /dev/null @@ -1,80 +0,0 @@ -local nvimsrcdir = arg[1] -local shared_file = arg[2] -local funcs_file = arg[3] -local defs_file = arg[4] - -_G.vim = loadfile(shared_file)() - -if nvimsrcdir == '--help' then - print([[ -Usage: - lua gen_keyset.lua TODOFIXUPDATETHIS - -Will generate build/src/nvim/auto/keyset.generated.h with definition of functions -static const array. -]]) - os.exit(0) -end - - -package.path = nvimsrcdir .. '/?.lua;' .. package.path -local hashy = require'generators.hashy' - -local funcspipe = io.open(funcs_file, 'wb') -local defspipe = io.open(defs_file, 'wb') - -local keysets = require'api.keysets' - -local keywords = { - register = true; - default = true; -} - -local function sanitize(key) - if keywords[key] then - return key .. "_" - end - return key -end - -for _, v in ipairs(keysets) do - local name = v[1] - local keys = v[2] - local neworder, hashfun = hashy.hashy_hash(name, keys, function (idx) - return name.."_table["..idx.."].str" - end) - - defspipe:write("typedef struct {\n") - for _, key in ipairs(neworder) do - defspipe:write(" Object "..sanitize(key)..";\n") - end - defspipe:write("} KeyDict_"..name..";\n\n") - - defspipe:write("extern KeySetLink "..name.."_table[];\n") - - funcspipe:write("KeySetLink "..name.."_table[] = {\n") - for _, key in ipairs(neworder) do - funcspipe:write(' {"'..key..'", offsetof(KeyDict_'..name..", "..sanitize(key)..")},\n") - end - funcspipe:write(' {NULL, 0},\n') - funcspipe:write("};\n\n") - - funcspipe:write(hashfun) - - funcspipe:write([[ -Object *KeyDict_]]..name..[[_get_field(void *retval, const char *str, size_t len) -{ - int hash = ]]..name..[[_hash(str, len); - if (hash == -1) { - return NULL; - } - - return (Object *)((char *)retval + ]]..name..[[_table[hash].ptr_off); -} - -]]) - defspipe:write("#define api_free_keydict_"..name.."(x) api_free_keydict(x, "..name.."_table)\n") -end - -funcspipe:close() -defspipe:close() diff --git a/src/nvim/generators/gen_options.lua b/src/nvim/generators/gen_options.lua index edb7dae159..26ade2745d 100644 --- a/src/nvim/generators/gen_options.lua +++ b/src/nvim/generators/gen_options.lua @@ -1,14 +1,6 @@ -if arg[1] == '--help' then - print('Usage: genoptions.lua src/nvim options_file') - os.exit(0) -end - -local nvimsrcdir = arg[1] -local options_file = arg[2] - -package.path = nvimsrcdir .. '/?.lua;' .. package.path +local options_file = arg[1] -local opt_fd = io.open(options_file, 'w') +local opt_fd = assert(io.open(options_file, 'w')) local w = function(s) if s:match('^ %.') then @@ -18,6 +10,7 @@ local w = function(s) end end +--- @module 'nvim.options' local options = require('options') local cstr = options.cstr @@ -42,11 +35,16 @@ local redraw_flags={ 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', } -local get_flags = function(o) +--- @param o vim.option_meta +--- @return string +local function get_flags(o) + --- @type string[] local ret = {type_flags[o.type]} local add_flag = function(f) ret[1] = ret[1] .. '|' .. f @@ -89,8 +87,10 @@ local get_flags = function(o) return ret[1] end -local get_cond -get_cond = function(c, base_string) +--- @param c string|string[] +--- @param base_string? string +--- @return string +local function get_cond(c, base_string) local cond_string = base_string or '#if ' if type(c) == 'table' then cond_string = cond_string .. get_cond(c[1], '') @@ -112,11 +112,11 @@ local value_dumpers = { string=cstr, boolean=function(v) return v and 'true' or 'false' end, number=function(v) return ('%iL'):format(v) end, - ['nil']=function(_) return '0L' end, + ['nil']=function(_) return '0' end, } local get_value = function(v) - return '(char *) ' .. value_dumpers[type(v)](v) + return '(void *) ' .. value_dumpers[type(v)](v) end local get_defaults = function(d,n) @@ -126,9 +126,12 @@ local get_defaults = function(d,n) return get_value(d) end +--- @type {[1]:string,[2]:string}[] local defines = {} -local dump_option = function(i, o) +--- @param i integer +--- @param o vim.option_meta +local function dump_option(i, o) w(' [' .. ('%u'):format(i - 1) .. ']={') w(' .fullname=' .. cstr(o.full_name)) if o.abbreviation then @@ -139,10 +142,14 @@ local dump_option = function(i, o) w(get_cond(o.enable_if)) end if o.varname then - w(' .var=(char_u *)&' .. o.varname) + w(' .var=&' .. o.varname) + -- Immutable options should directly point to the default value + elseif o.immutable then + w((' .var=&options[%u].def_val'):format(i - 1)) elseif #o.scope == 1 and o.scope[1] == 'window' then w(' .var=VAR_WIN') end + w(' .immutable=' .. (o.immutable and 'true' or 'false')) if #o.scope == 1 and o.scope[1] == 'global' then w(' .indir=PV_NONE') else @@ -162,6 +169,12 @@ local dump_option = function(i, o) 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 + if o.expand_cb then + w(' .opt_expand_cb=' .. o.expand_cb) + end if o.enable_if then w('#else') w(' .var=NULL') @@ -184,7 +197,19 @@ local dump_option = function(i, o) w(' },') end -w('static vimoption_T options[] = {') +w([[ +#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.options) do dump_option(i, o) end diff --git a/src/nvim/generators/gen_vimvim.lua b/src/nvim/generators/gen_vimvim.lua new file mode 100644 index 0000000000..29355d3cda --- /dev/null +++ b/src/nvim/generators/gen_vimvim.lua @@ -0,0 +1,147 @@ +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 ' +w(vimcmd_start) +local prev_cmd = nil +for _, cmd_desc in ipairs(ex_cmds.cmds) do + if lld.line_length > 850 then + w('\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 + +local vimopt_start = 'syn keyword vimOption contained ' +w('\n\n' .. vimopt_start) + +for _, opt_desc in ipairs(options.options) do + if not opt_desc.varname or opt_desc.varname:sub(1, 7) ~= 'p_force' then + if lld.line_length > 850 then + w('\n' .. vimopt_start) + end + w(' ' .. opt_desc.full_name) + if opt_desc.abbreviation then + w(' ' .. opt_desc.abbreviation) + end + if opt_desc.type == 'bool' 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('\n\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] then + if lld.line_length > 850 then + w('\n' .. vimau_start) + end + w(' ' .. au) + end +end +for _, au in pairs(auevents.aliases) do + if lld.line_length > 850 then + w('\n' .. vimau_start) + end + -- au[1] is aliased to au[2] + w(' ' .. au[1]) +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/preload.lua b/src/nvim/generators/preload.lua new file mode 100644 index 0000000000..4b7fde2c39 --- /dev/null +++ b/src/nvim/generators/preload.lua @@ -0,0 +1,10 @@ +local srcdir = table.remove(arg, 1) +local nlualib = table.remove(arg, 1) +package.path = srcdir .. '/src/nvim/?.lua;' ..srcdir .. '/runtime/lua/?.lua;' .. package.path +_G.vim = require'vim.shared' +_G.vim.inspect = require 'vim.inspect' +package.cpath = package.cpath .. ';' .. nlualib +require 'nlua0' + +arg[0] = table.remove(arg, 1) +return loadfile(arg[0])() |