diff options
author | bfredl <bjorn.linse@gmail.com> | 2022-12-30 22:17:01 +0100 |
---|---|---|
committer | bfredl <bjorn.linse@gmail.com> | 2023-01-05 09:48:26 +0100 |
commit | 47ba78f89a1f0bba8168b4408bc55a3024d5ab97 (patch) | |
tree | 79a1d81956d87986467e4da70b4f9ad53b079040 /src/nvim/ui.c | |
parent | ae64772a88125153a438a0e9e43d5f6bcb4eeb28 (diff) | |
download | rneovim-47ba78f89a1f0bba8168b4408bc55a3024d5ab97.tar.gz rneovim-47ba78f89a1f0bba8168b4408bc55a3024d5ab97.tar.bz2 rneovim-47ba78f89a1f0bba8168b4408bc55a3024d5ab97.zip |
refactor(ui): devirtualize the ui layer
- The defined interface for the UI is only the RPC protocol. The original
UI interface as an array of function pointers fill no function.
- On the server, all the UI:s are all RPC channels.
- ui.c is only used on the server.
- The compositor is a preprocessing step for single-grid UI:s
- on the client, ui_client and tui talk directly to each other
- we still do module separation, as ui_client.c could form the basis
of a libnvim client module later.
Items for later PR:s
- vim.ui_attach is still an unhappy child, reconsider based on plugin experience.
- the flags in ui_events.in.h are still a mess. Can be simplified now.
- UX for remote attachment needs more work.
- startup for client can be simplified further (think of the millisecs we can save)
Diffstat (limited to 'src/nvim/ui.c')
-rw-r--r-- | src/nvim/ui.c | 168 |
1 files changed, 109 insertions, 59 deletions
diff --git a/src/nvim/ui.c b/src/nvim/ui.c index 0cb48a9cf4..7d7aaa9903 100644 --- a/src/nvim/ui.c +++ b/src/nvim/ui.c @@ -11,6 +11,7 @@ #include "auto/config.h" #include "klib/kvec.h" #include "nvim/api/private/helpers.h" +#include "nvim/api/ui.h" #include "nvim/ascii.h" #include "nvim/autocmd.h" #include "nvim/buffer_defs.h" @@ -25,6 +26,7 @@ #include "nvim/highlight.h" #include "nvim/highlight_defs.h" #include "nvim/log.h" +#include "nvim/lua/executor.h" #include "nvim/main.h" #include "nvim/memory.h" #include "nvim/message.h" @@ -55,6 +57,9 @@ static bool pending_mode_info_update = false; static bool pending_mode_update = false; static handle_T cursor_grid_handle = DEFAULT_GRID_HANDLE; +static PMap(uint32_t) ui_event_cbs = MAP_INIT; +bool ui_cb_ext[kUIExtCount]; ///< Internalized UI capabilities. + static bool has_mouse = false; static int pending_has_mouse = -1; @@ -96,8 +101,8 @@ static char uilog_last_event[1024] = { 0 }; bool any_call = false; \ for (size_t i = 0; i < ui_count; i++) { \ UI *ui = uis[i]; \ - if (ui->funname && (cond)) { \ - ui->funname(__VA_ARGS__); \ + if ((cond)) { \ + remote_ui_##funname(__VA_ARGS__); \ any_call = true; \ } \ } \ @@ -122,36 +127,25 @@ void ui_init(void) kv_ensure_space(call_buf, 16); } -static UI *builtin_ui = NULL; - #ifdef EXITFREE void ui_free_all_mem(void) { kv_destroy(call_buf); - if (builtin_ui) { - tui_free_all_mem(builtin_ui); - builtin_ui = NULL; - } -} -#endif -void ui_builtin_start(void) -{ - builtin_ui = tui_start(); -} - -UI *ui_get_by_index(int idx) -{ - assert(idx < 16); - return uis[idx]; + UIEventCallback *event_cb; + map_foreach_value(&ui_event_cbs, event_cb, { + free_ui_event_callback(event_cb); + }) + pmap_destroy(uint32_t)(&ui_event_cbs); } +#endif bool ui_rgb_attached(void) { if (!headless_mode && p_tgc) { return true; } - for (size_t i = 1; i < ui_count; i++) { + for (size_t i = 0; i < ui_count; i++) { if (uis[i]->rgb) { return true; } @@ -162,7 +156,7 @@ bool ui_rgb_attached(void) /// Returns true if any UI requested `override=true`. bool ui_override(void) { - for (size_t i = 1; i < ui_count; i++) { + for (size_t i = 0; i < ui_count; i++) { if (uis[i]->override) { return true; } @@ -172,11 +166,15 @@ bool ui_override(void) bool ui_active(void) { - return ui_count > 1; + return ui_count > 0; } void ui_refresh(void) { + if (ui_client_channel_id) { + abort(); + } + if (!ui_active()) { return; } @@ -192,16 +190,13 @@ void ui_refresh(void) ext_widgets[i] = true; } - UI *compositor = uis[0]; - bool inclusive = ui_override(); - for (size_t i = 1; i < ui_count; i++) { + for (size_t i = 0; i < ui_count; i++) { UI *ui = uis[i]; width = MIN(ui->width, width); height = MIN(ui->height, height); for (UIExtension j = 0; (int)j < kUIExtCount; j++) { - bool in_compositor = (ui->composed || j < kUIGlobalCount) && compositor->ui_ext[j]; - ext_widgets[j] &= (ui->ui_ext[j] || in_compositor || inclusive); + ext_widgets[j] &= (ui->ui_ext[j] || inclusive); } } @@ -209,6 +204,9 @@ void ui_refresh(void) pending_cursor_update = true; for (UIExtension i = 0; (int)i < kUIExtCount; i++) { + if (i < kUIGlobalCount) { + ext_widgets[i] |= ui_cb_ext[i]; + } ui_ext[i] = ext_widgets[i]; if (i < kUIGlobalCount) { ui_call_option_set(cstr_as_string((char *)ui_ext_names[i]), @@ -218,27 +216,10 @@ void ui_refresh(void) ui_default_colors_set(); - if (!ui_client_channel_id) { - int save_p_lz = p_lz; - p_lz = false; // convince redrawing() to return true ... - screen_resize(width, height); - p_lz = save_p_lz; - } else { - if (ui_client_attached) { - // TODO(bfredl): ui_refresh() should only be used on the server - // we are in the client process. forward the resize - MAXSIZE_TEMP_ARRAY(args, 2); - ADD_C(args, INTEGER_OBJ((int)width)); - ADD_C(args, INTEGER_OBJ((int)height)); - rpc_send_event(ui_client_channel_id, "nvim_ui_try_resize", args); - } else { - /// TODO(bfredl): Messy! The screen does not yet exist, but we need to - /// communicate its size from the TUI to the client. Clean this up - /// in The UI Devirtualization Project. - Rows = height; - Columns = width; - } - } + int save_p_lz = p_lz; + p_lz = false; // convince redrawing() to return true ... + screen_resize(width, height); + p_lz = save_p_lz; if (ext_widgets[kUIMessages]) { set_option_value("cmdheight", 0L, NULL, 0); @@ -253,7 +234,7 @@ void ui_refresh(void) int ui_pum_get_height(void) { int pum_height = 0; - for (size_t i = 1; i < ui_count; i++) { + for (size_t i = 0; i < ui_count; i++) { int ui_pum_height = uis[i]->pum_nlines; if (ui_pum_height) { pum_height = @@ -265,7 +246,7 @@ int ui_pum_get_height(void) bool ui_pum_get_pos(double *pwidth, double *pheight, double *prow, double *pcol) { - for (size_t i = 1; i < ui_count; i++) { + for (size_t i = 0; i < ui_count; i++) { if (!uis[i]->pum_pos) { continue; } @@ -372,10 +353,7 @@ void ui_attach_impl(UI *ui, uint64_t chanid) } ui_refresh(); - bool is_compositor = (ui == uis[0]); - if (!is_compositor) { - do_autocmd_uienter(chanid, true); - } + do_autocmd_uienter(chanid, true); } void ui_detach_impl(UI *ui, uint64_t chanid) @@ -420,9 +398,9 @@ void ui_set_ext_option(UI *ui, UIExtension ext, bool active) ui_refresh(); return; } - if (ui->option_set && (ui_ext_names[ext][0] != '_' || active)) { - ui->option_set(ui, cstr_as_string((char *)ui_ext_names[ext]), - BOOLEAN_OBJ(active)); + if (ui_ext_names[ext][0] != '_' || active) { + remote_ui_option_set(ui, cstr_as_string((char *)ui_ext_names[ext]), + BOOLEAN_OBJ(active)); } if (ext == kUITermColors) { ui_default_colors_set(); @@ -618,7 +596,7 @@ bool ui_has(UIExtension ext) Array ui_array(void) { Array all_uis = ARRAY_DICT_INIT; - for (size_t i = 1; i < ui_count; i++) { + for (size_t i = 0; i < ui_count; i++) { UI *ui = uis[i]; Dictionary info = ARRAY_DICT_INIT; PUT(info, "width", INTEGER_OBJ(ui->width)); @@ -630,7 +608,7 @@ Array ui_array(void) PUT(info, ui_ext_names[j], BOOLEAN_OBJ(ui->ui_ext[j])); } } - ui->inspect(ui, &info); + remote_ui_inspect(ui, &info); ADD(all_uis, DICTIONARY_OBJ(info)); } return all_uis; @@ -663,3 +641,75 @@ void ui_grid_resize(handle_T grid_handle, int width, int height, Error *error) win_set_inner_size(wp, true); } } + +void ui_call_event(char *name, Array args) +{ + UIEventCallback *event_cb; + bool handled = false; + map_foreach_value(&ui_event_cbs, event_cb, { + Error err = ERROR_INIT; + Object res = nlua_call_ref(event_cb->cb, name, args, false, &err); + if (res.type == kObjectTypeBoolean && res.data.boolean == true) { + handled = true; + } + if (ERROR_SET(&err)) { + ELOG("Error while executing ui_comp_event callback: %s", err.msg); + } + api_clear_error(&err); + }) + + if (!handled) { + UI_CALL(true, event, ui, name, args); + } +} + +void ui_cb_update_ext(void) +{ + memset(ui_cb_ext, 0, ARRAY_SIZE(ui_cb_ext)); + + for (size_t i = 0; i < kUIGlobalCount; i++) { + UIEventCallback *event_cb; + + map_foreach_value(&ui_event_cbs, event_cb, { + if (event_cb->ext_widgets[i]) { + ui_cb_ext[i] = true; + break; + } + }) + } +} + +void free_ui_event_callback(UIEventCallback *event_cb) +{ + api_free_luaref(event_cb->cb); + xfree(event_cb); +} + +void ui_add_cb(uint32_t ns_id, LuaRef cb, bool *ext_widgets) +{ + UIEventCallback *event_cb = xcalloc(1, sizeof(UIEventCallback)); + event_cb->cb = cb; + memcpy(event_cb->ext_widgets, ext_widgets, ARRAY_SIZE(event_cb->ext_widgets)); + if (event_cb->ext_widgets[kUIMessages]) { + event_cb->ext_widgets[kUICmdline] = true; + } + + UIEventCallback **item = (UIEventCallback **)pmap_ref(uint32_t)(&ui_event_cbs, ns_id, true); + if (*item) { + free_ui_event_callback(*item); + } + *item = event_cb; + + ui_cb_update_ext(); + ui_refresh(); +} + +void ui_remove_cb(uint32_t ns_id) +{ + if (pmap_has(uint32_t)(&ui_event_cbs, ns_id)) { + free_ui_event_callback(pmap_get(uint32_t)(&ui_event_cbs, ns_id)); + pmap_del(uint32_t)(&ui_event_cbs, ns_id); + } + ui_cb_update_ext(); + ui_refresh(); +} |