mirror of
https://github.com/neovim/neovim.git
synced 2025-09-17 16:58:17 +00:00
refactor(api): use hashy hash for looking up api method and event names
This avoids generating khash tables at runtime, and is consistent with how evalfuncs lookup work.
This commit is contained in:
@@ -32,37 +32,22 @@
|
||||
#include "nvim/api/window.h"
|
||||
#include "nvim/ui_client.h"
|
||||
|
||||
static Map(String, MsgpackRpcRequestHandler) methods = MAP_INIT;
|
||||
|
||||
static void msgpack_rpc_add_method_handler(String method, MsgpackRpcRequestHandler handler)
|
||||
{
|
||||
map_put(String, MsgpackRpcRequestHandler)(&methods, method, handler);
|
||||
}
|
||||
|
||||
void msgpack_rpc_add_redraw(void)
|
||||
{
|
||||
msgpack_rpc_add_method_handler(STATIC_CSTR_AS_STRING("redraw"),
|
||||
(MsgpackRpcRequestHandler) { .fn = ui_client_handle_redraw,
|
||||
.fast = true });
|
||||
}
|
||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||
# include "api/private/dispatch_wrappers.generated.h"
|
||||
#endif
|
||||
|
||||
/// @param name API method name
|
||||
/// @param name_len name size (includes terminating NUL)
|
||||
MsgpackRpcRequestHandler msgpack_rpc_get_handler_for(const char *name, size_t name_len,
|
||||
Error *error)
|
||||
{
|
||||
String m = { .data = (char *)name, .size = name_len };
|
||||
MsgpackRpcRequestHandler rv =
|
||||
map_get(String, MsgpackRpcRequestHandler)(&methods, m);
|
||||
int hash = msgpack_rpc_get_handler_for_hash(name, name_len);
|
||||
|
||||
if (!rv.fn) {
|
||||
if (hash < 0) {
|
||||
api_set_error(error, kErrorTypeException, "Invalid method: %.*s",
|
||||
m.size > 0 ? (int)m.size : (int)sizeof("<empty>"),
|
||||
m.size > 0 ? m.data : "<empty>");
|
||||
name_len > 0 ? (int)name_len : (int)sizeof("<empty>"),
|
||||
name_len > 0 ? name : "<empty>");
|
||||
return (MsgpackRpcRequestHandler){ 0 };
|
||||
}
|
||||
return rv;
|
||||
return method_handlers[hash];
|
||||
}
|
||||
|
||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||
# include "api/private/dispatch_wrappers.generated.h"
|
||||
#endif
|
||||
|
@@ -10,6 +10,7 @@ typedef Object (*ApiDispatchWrapper)(uint64_t channel_id,
|
||||
/// The rpc_method_handlers table, used in msgpack_rpc_dispatch(), stores
|
||||
/// functions of this type.
|
||||
typedef struct {
|
||||
const char *name;
|
||||
ApiDispatchWrapper fn;
|
||||
bool fast; // Function is safe to be executed immediately while running the
|
||||
// uv loop (the loop is run very frequently due to breakcheck).
|
||||
|
@@ -16,6 +16,10 @@ local functions = {}
|
||||
local nvimdir = arg[1]
|
||||
package.path = nvimdir .. '/?.lua;' .. package.path
|
||||
|
||||
_G.vim = loadfile(nvimdir..'/../../runtime/lua/vim/shared.lua')()
|
||||
|
||||
local hashy = require'generators.hashy'
|
||||
|
||||
-- names of all headers relative to the source root (for inclusion in the
|
||||
-- generated file)
|
||||
local headers = {}
|
||||
@@ -339,24 +343,27 @@ for i = 1, #functions do
|
||||
end
|
||||
end
|
||||
|
||||
-- Generate a function that initializes method names with handler functions
|
||||
output:write([[
|
||||
void msgpack_rpc_init_method_table(void)
|
||||
{
|
||||
]])
|
||||
|
||||
for i = 1, #functions do
|
||||
local fn = functions[i]
|
||||
local remote_fns = {}
|
||||
for _,fn in ipairs(functions) do
|
||||
if fn.remote then
|
||||
output:write(' msgpack_rpc_add_method_handler('..
|
||||
'(String) {.data = "'..fn.name..'", '..
|
||||
'.size = sizeof("'..fn.name..'") - 1}, '..
|
||||
'(MsgpackRpcRequestHandler) {.fn = handle_'.. (fn.impl_name or fn.name)..
|
||||
', .fast = '..tostring(fn.fast)..'});\n')
|
||||
remote_fns[fn.name] = fn
|
||||
end
|
||||
end
|
||||
remote_fns.redraw = {impl_name="ui_client_redraw", fast=true}
|
||||
|
||||
local hashorder, hashfun = hashy.hashy_hash("msgpack_rpc_get_handler_for", vim.tbl_keys(remote_fns), function (idx)
|
||||
return "method_handlers["..idx.."].name"
|
||||
end)
|
||||
|
||||
output:write("static const MsgpackRpcRequestHandler method_handlers[] = {\n")
|
||||
for _, name in ipairs(hashorder) do
|
||||
local fn = remote_fns[name]
|
||||
output:write(' { .name = "'..name..'", .fn = handle_'.. (fn.impl_name or fn.name)..
|
||||
', .fast = '..tostring(fn.fast)..'},\n')
|
||||
end
|
||||
output:write("};\n\n")
|
||||
output:write(hashfun)
|
||||
|
||||
output:write('\n}\n\n')
|
||||
output:close()
|
||||
|
||||
local mpack_output = io.open(mpack_outputf, 'wb')
|
||||
|
@@ -15,6 +15,9 @@ local client_output = io.open(arg[8], '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)
|
||||
output:write('('..prefix)
|
||||
if prefix == "" and #ev.parameters == 0 then
|
||||
@@ -213,24 +216,25 @@ for i = 1, #events do
|
||||
end
|
||||
end
|
||||
|
||||
-- Generate the map_init method for client handlers
|
||||
client_output:write([[
|
||||
void ui_client_methods_table_init(void)
|
||||
{
|
||||
|
||||
]])
|
||||
|
||||
for i = 1, #events do
|
||||
local fn = events[i]
|
||||
if (not fn.noexport) and ((not fn.remote_only) or fn.client_impl) then
|
||||
client_output:write(' add_ui_client_event_handler('..
|
||||
'(String) {.data = "'..fn.name..'", '..
|
||||
'.size = sizeof("'..fn.name..'") - 1}, '..
|
||||
'(UIClientHandler) ui_client_event_'..fn.name..');\n')
|
||||
local client_events = {}
|
||||
for _,ev in ipairs(events) do
|
||||
if (not ev.noexport) and ((not ev.remote_only) or ev.client_impl) then
|
||||
client_events[ev.name] = ev
|
||||
end
|
||||
end
|
||||
|
||||
client_output:write('\n}\n\n')
|
||||
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)
|
||||
|
||||
proto_output:close()
|
||||
call_output:close()
|
||||
|
@@ -121,7 +121,6 @@ void event_init(void)
|
||||
resize_events = multiqueue_new_child(main_loop.events);
|
||||
|
||||
// early msgpack-rpc initialization
|
||||
msgpack_rpc_init_method_table();
|
||||
msgpack_rpc_helpers_init();
|
||||
input_init();
|
||||
signal_init();
|
||||
|
@@ -14,7 +14,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "nvim/api/private/dispatch.h"
|
||||
#include "nvim/lib/khash.h"
|
||||
#include "nvim/map.h"
|
||||
#include "nvim/map_defs.h"
|
||||
@@ -171,13 +170,10 @@ MAP_IMPL(uint64_t, ssize_t, SSIZE_INITIALIZER)
|
||||
MAP_IMPL(uint64_t, uint64_t, DEFAULT_INITIALIZER)
|
||||
MAP_IMPL(uint32_t, uint32_t, DEFAULT_INITIALIZER)
|
||||
MAP_IMPL(handle_T, ptr_t, DEFAULT_INITIALIZER)
|
||||
#define MSGPACK_HANDLER_INITIALIZER { .fn = NULL, .fast = false }
|
||||
MAP_IMPL(String, MsgpackRpcRequestHandler, MSGPACK_HANDLER_INITIALIZER)
|
||||
MAP_IMPL(HlEntry, int, DEFAULT_INITIALIZER)
|
||||
MAP_IMPL(String, handle_T, 0)
|
||||
MAP_IMPL(String, int, DEFAULT_INITIALIZER)
|
||||
MAP_IMPL(int, String, DEFAULT_INITIALIZER)
|
||||
MAP_IMPL(String, UIClientHandler, NULL)
|
||||
|
||||
MAP_IMPL(ColorKey, ColorItem, COLOR_ITEM_INITIALIZER)
|
||||
|
||||
|
@@ -4,7 +4,6 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "nvim/api/private/defs.h"
|
||||
#include "nvim/api/private/dispatch.h"
|
||||
#include "nvim/extmark_defs.h"
|
||||
#include "nvim/highlight_defs.h"
|
||||
#include "nvim/map_defs.h"
|
||||
@@ -44,12 +43,10 @@ MAP_DECLS(uint64_t, uint64_t)
|
||||
MAP_DECLS(uint32_t, uint32_t)
|
||||
|
||||
MAP_DECLS(handle_T, ptr_t)
|
||||
MAP_DECLS(String, MsgpackRpcRequestHandler)
|
||||
MAP_DECLS(HlEntry, int)
|
||||
MAP_DECLS(String, handle_T)
|
||||
MAP_DECLS(String, int)
|
||||
MAP_DECLS(int, String)
|
||||
MAP_DECLS(String, UIClientHandler)
|
||||
|
||||
MAP_DECLS(ColorKey, ColorItem)
|
||||
|
||||
|
@@ -6,6 +6,7 @@
|
||||
#include <uv.h>
|
||||
|
||||
#include "nvim/api/private/defs.h"
|
||||
#include "nvim/api/private/dispatch.h"
|
||||
#include "nvim/event/process.h"
|
||||
#include "nvim/event/socket.h"
|
||||
#include "nvim/vim.h"
|
||||
|
@@ -16,18 +16,17 @@
|
||||
#include "nvim/ui_client.h"
|
||||
#include "nvim/vim.h"
|
||||
|
||||
static Map(String, UIClientHandler) ui_client_handlers = MAP_INIT;
|
||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||
# include "ui_client.c.generated.h"
|
||||
|
||||
# include "ui_events_client.generated.h"
|
||||
#endif
|
||||
|
||||
// Temporary buffer for converting a single grid_line event
|
||||
static size_t buf_size = 0;
|
||||
static schar_T *buf_char = NULL;
|
||||
static sattr_T *buf_attr = NULL;
|
||||
|
||||
static void add_ui_client_event_handler(String method, UIClientHandler handler)
|
||||
{
|
||||
map_put(String, UIClientHandler)(&ui_client_handlers, method, handler);
|
||||
}
|
||||
|
||||
void ui_client_init(uint64_t chan)
|
||||
{
|
||||
Array args = ARRAY_DICT_INIT;
|
||||
@@ -44,9 +43,6 @@ void ui_client_init(uint64_t chan)
|
||||
ADD(args, DICTIONARY_OBJ(opts));
|
||||
|
||||
rpc_send_event(chan, "nvim_ui_attach", args);
|
||||
msgpack_rpc_add_redraw(); // GAME!
|
||||
// TODO(bfredl): use a keyset instead
|
||||
ui_client_methods_table_init();
|
||||
ui_client_channel_id = chan;
|
||||
}
|
||||
|
||||
@@ -61,22 +57,23 @@ void ui_client_init(uint64_t chan)
|
||||
/// @param channel_id: The id of the rpc channel
|
||||
/// @param uidata: The dense array containing the ui_events sent by the server
|
||||
/// @param[out] err Error details, if any
|
||||
Object ui_client_handle_redraw(uint64_t channel_id, Array args, Error *error)
|
||||
Object handle_ui_client_redraw(uint64_t channel_id, Array args, Error *error)
|
||||
{
|
||||
for (size_t i = 0; i < args.size; i++) {
|
||||
Array call = args.items[i].data.array;
|
||||
String name = call.items[0].data.string;
|
||||
|
||||
UIClientHandler handler = map_get(String, UIClientHandler)(&ui_client_handlers, name);
|
||||
if (!handler) {
|
||||
int hash = ui_client_handler_hash(name.data, name.size);
|
||||
if (hash < 0) {
|
||||
ELOG("No ui client handler for %s", name.size ? name.data : "<empty>");
|
||||
continue;
|
||||
}
|
||||
UIClientHandler handler = event_handlers[hash];
|
||||
|
||||
// fprintf(stderr, "%s: %zu\n", name.data, call.size-1);
|
||||
DLOG("Invoke ui client handler for %s", name.data);
|
||||
for (size_t j = 1; j < call.size; j++) {
|
||||
handler(call.items[j].data.array);
|
||||
handler.fn(call.items[j].data.array);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,10 +105,6 @@ static HlAttrs ui_client_dict2hlattrs(Dictionary d, bool rgb)
|
||||
return dict2hlattrs(&dict, true, NULL, &err);
|
||||
}
|
||||
|
||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||
# include "ui_events_client.generated.h"
|
||||
#endif
|
||||
|
||||
void ui_client_event_grid_resize(Array args)
|
||||
{
|
||||
if (args.size < 3
|
||||
|
@@ -3,7 +3,10 @@
|
||||
|
||||
#include "nvim/api/private/defs.h"
|
||||
|
||||
typedef void (*UIClientHandler)(Array args);
|
||||
typedef struct {
|
||||
const char *name;
|
||||
void (*fn)(Array args);
|
||||
} UIClientHandler;
|
||||
|
||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||
# include "ui_client.h.generated.h"
|
||||
|
Reference in New Issue
Block a user