diff options
author | bfredl <bjorn.linse@gmail.com> | 2022-03-16 16:05:40 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-03-16 16:05:40 +0100 |
commit | 4e5e0076cb643b52d762f226b27f22c8fb837567 (patch) | |
tree | 572699fc6ed68c92a8fab6b8f41be15423899f1f /src/nvim/ui_client.c | |
parent | fa79a016bc894d3f89eddc7744868d2dd5458d51 (diff) | |
parent | f01d203b70f426c1538813b3bacb4483e914ab44 (diff) | |
download | rneovim-4e5e0076cb643b52d762f226b27f22c8fb837567.tar.gz rneovim-4e5e0076cb643b52d762f226b27f22c8fb837567.tar.bz2 rneovim-4e5e0076cb643b52d762f226b27f22c8fb837567.zip |
Merge pull request #17708 from bfredl/ui_client
feat(ui): UI client episode II: event handlers
Diffstat (limited to 'src/nvim/ui_client.c')
-rw-r--r-- | src/nvim/ui_client.c | 162 |
1 files changed, 153 insertions, 9 deletions
diff --git a/src/nvim/ui_client.c b/src/nvim/ui_client.c index 4a435aac4d..4fad3e0709 100644 --- a/src/nvim/ui_client.c +++ b/src/nvim/ui_client.c @@ -6,40 +6,55 @@ #include <assert.h> #include "nvim/vim.h" +#include "nvim/log.h" +#include "nvim/map.h" #include "nvim/ui_client.h" #include "nvim/api/private/helpers.h" #include "nvim/msgpack_rpc/channel.h" #include "nvim/api/private/dispatch.h" #include "nvim/ui.h" +#include "nvim/highlight.h" +#include "nvim/screen.h" + +static Map(String, UIClientHandler) ui_client_handlers = MAP_INIT; + +// 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; - int width = 80; - int height = 25; + int width = Columns; + int height = Rows; Dictionary opts = ARRAY_DICT_INIT; PUT(opts, "rgb", BOOLEAN_OBJ(true)); PUT(opts, "ext_linegrid", BOOLEAN_OBJ(true)); PUT(opts, "ext_termcolors", BOOLEAN_OBJ(true)); - // TODO(bfredl): use the size of the client UI ADD(args, INTEGER_OBJ((int)width)); ADD(args, INTEGER_OBJ((int)height)); 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; } /// Handler for "redraw" events sent by the NVIM server /// -/// This is just a stub. The mentioned functionality will be implemented. -/// -/// This function will be called by handle_request (in msgpack_rpc/channle.c) +/// This function will be called by handle_request (in msgpack_rpc/channel.c) /// The individual ui_events sent by the server are individually handled -/// by their respective handlers defined in ui_events_redraw.generated.h +/// by their respective handlers defined in ui_events_client.generated.h /// /// @note The "flush" event is called only once and only after handling all /// the other events @@ -50,10 +65,21 @@ Object ui_client_handle_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; - char *method_name = call.items[0].data.string.data; + String name = call.items[0].data.string; + + UIClientHandler handler = map_get(String, UIClientHandler)(&ui_client_handlers, name); + if (!handler) { + ELOG("No ui client handler for %s", name.size ? name.data : "<empty>"); + continue; + } - fprintf(stderr, "%s: %zu\n", method_name, call.size-1); + // 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); + } } + return NIL; } @@ -68,3 +94,121 @@ void ui_client_execute(uint64_t chan) getout(0); } + +static HlAttrs ui_client_dict2hlattrs(Dictionary d, bool rgb) +{ + Error err = ERROR_INIT; + Dict(highlight) dict = { 0 }; + if (!api_dict_to_keydict(&dict, KeyDict_highlight_get_field, d, &err)) { + // TODO(bfredl): log "err" + return HLATTRS_INIT; + } + 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 + || args.items[0].type != kObjectTypeInteger + || args.items[1].type != kObjectTypeInteger + || args.items[2].type != kObjectTypeInteger) { + ELOG("Error handling ui event 'grid_resize'"); + return; + } + + Integer grid = args.items[0].data.integer; + Integer width = args.items[1].data.integer; + Integer height = args.items[2].data.integer; + ui_call_grid_resize(grid, width, height); + + if (buf_size < (size_t)width) { + xfree(buf_char); + xfree(buf_attr); + buf_size = (size_t)width; + buf_char = xmalloc(buf_size * sizeof(schar_T)); + buf_attr = xmalloc(buf_size * sizeof(sattr_T)); + } +} + +void ui_client_event_grid_line(Array args) +{ + if (args.size < 4 + || args.items[0].type != kObjectTypeInteger + || args.items[1].type != kObjectTypeInteger + || args.items[2].type != kObjectTypeInteger + || args.items[3].type != kObjectTypeArray) { + goto error; + } + + Integer grid = args.items[0].data.integer; + Integer row = args.items[1].data.integer; + Integer startcol = args.items[2].data.integer; + Array cells = args.items[3].data.array; + + Integer endcol, clearcol; + // TODO(hlpr98): Accomodate other LineFlags when included in grid_line + LineFlags lineflags = 0; + endcol = startcol; + + size_t j = 0; + int cur_attr = 0; + int clear_attr = 0; + int clear_width = 0; + for (size_t i = 0; i < cells.size; i++) { + if (cells.items[i].type != kObjectTypeArray) { + goto error; + } + Array cell = cells.items[i].data.array; + + if (cell.size < 1 || cell.items[0].type != kObjectTypeString) { + goto error; + } + String sstring = cell.items[0].data.string; + + char *schar = sstring.data; + int repeat = 1; + if (cell.size >= 2) { + if (cell.items[1].type != kObjectTypeInteger + || cell.items[1].data.integer < 0) { + goto error; + } + cur_attr = (int)cell.items[1].data.integer; + } + + if (cell.size >= 3) { + if (cell.items[2].type != kObjectTypeInteger + || cell.items[2].data.integer < 0) { + goto error; + } + repeat = (int)cell.items[2].data.integer; + } + + if (i == cells.size - 1 && sstring.size == 1 && sstring.data[0] == ' ' && repeat > 1) { + clear_width = repeat; + break; + } + + for (int r = 0; r < repeat; r++) { + if (j >= buf_size) { + goto error; // _YIKES_ + } + STRLCPY(buf_char[j], schar, sizeof(schar_T)); + buf_attr[j++] = cur_attr; + } + } + + endcol = startcol + (int)j; + clearcol = endcol + clear_width; + clear_attr = cur_attr; + + ui_call_raw_line(grid, row, startcol, endcol, clearcol, clear_attr, lineflags, + (const schar_T *)buf_char, (const sattr_T *)buf_attr); + return; + +error: + ELOG("Error handling ui event 'grid_line'"); +} |