aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/generators
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/generators')
-rw-r--r--src/nvim/generators/c_grammar.lua13
-rw-r--r--src/nvim/generators/gen_api_dispatch.lua258
-rw-r--r--[-rwxr-xr-x]src/nvim/generators/gen_api_ui_events.lua21
-rw-r--r--[-rwxr-xr-x]src/nvim/generators/gen_declarations.lua28
-rw-r--r--src/nvim/generators/gen_eval.lua53
-rw-r--r--src/nvim/generators/gen_events.lua36
-rw-r--r--src/nvim/generators/gen_ex_cmds.lua29
-rw-r--r--src/nvim/generators/gen_keysets.lua80
-rw-r--r--src/nvim/generators/gen_options.lua61
-rw-r--r--src/nvim/generators/gen_vimvim.lua147
-rw-r--r--src/nvim/generators/preload.lua10
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])()