aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/api/ui.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/api/ui.c')
-rw-r--r--src/nvim/api/ui.c499
1 files changed, 207 insertions, 292 deletions
diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c
index 836a68546c..692e3f95fc 100644
--- a/src/nvim/api/ui.c
+++ b/src/nvim/api/ui.c
@@ -12,27 +12,34 @@
#include "nvim/api/private/helpers.h"
#include "nvim/api/private/validate.h"
#include "nvim/api/ui.h"
+#include "nvim/assert_defs.h"
#include "nvim/autocmd.h"
+#include "nvim/autocmd_defs.h"
#include "nvim/channel.h"
+#include "nvim/channel_defs.h"
#include "nvim/eval.h"
+#include "nvim/event/defs.h"
#include "nvim/event/loop.h"
+#include "nvim/event/multiqueue.h"
#include "nvim/event/wstream.h"
-#include "nvim/func_attr.h"
#include "nvim/globals.h"
#include "nvim/grid.h"
+#include "nvim/grid_defs.h"
#include "nvim/highlight.h"
#include "nvim/macros_defs.h"
#include "nvim/main.h"
#include "nvim/map_defs.h"
#include "nvim/mbyte.h"
#include "nvim/memory.h"
+#include "nvim/memory_defs.h"
#include "nvim/msgpack_rpc/channel.h"
-#include "nvim/msgpack_rpc/helpers.h"
+#include "nvim/msgpack_rpc/channel_defs.h"
+#include "nvim/msgpack_rpc/packer.h"
#include "nvim/option.h"
#include "nvim/types_defs.h"
#include "nvim/ui.h"
-#define BUF_POS(data) ((size_t)((data)->buf_wptr - (data)->buf))
+#define BUF_POS(ui) ((size_t)((ui)->packer.ptr - (ui)->packer.startptr))
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "api/ui.c.generated.h"
@@ -41,55 +48,6 @@
static PMap(uint64_t) connected_uis = MAP_INIT;
-#define mpack_w(b, byte) *(*b)++ = (char)(byte);
-static void mpack_w2(char **b, uint32_t v)
-{
- *(*b)++ = (char)((v >> 8) & 0xff);
- *(*b)++ = (char)(v & 0xff);
-}
-
-static void mpack_w4(char **b, uint32_t v)
-{
- *(*b)++ = (char)((v >> 24) & 0xff);
- *(*b)++ = (char)((v >> 16) & 0xff);
- *(*b)++ = (char)((v >> 8) & 0xff);
- *(*b)++ = (char)(v & 0xff);
-}
-
-static void mpack_uint(char **buf, uint32_t val)
-{
- if (val > 0xffff) {
- mpack_w(buf, 0xce);
- mpack_w4(buf, val);
- } else if (val > 0xff) {
- mpack_w(buf, 0xcd);
- mpack_w2(buf, val);
- } else if (val > 0x7f) {
- mpack_w(buf, 0xcc);
- mpack_w(buf, val);
- } else {
- mpack_w(buf, val);
- }
-}
-
-static void mpack_bool(char **buf, bool val)
-{
- mpack_w(buf, 0xc2 | (val ? 1 : 0));
-}
-
-static void mpack_array(char **buf, uint32_t len)
-{
- if (len < 0x10) {
- mpack_w(buf, 0x90 | len);
- } else if (len < 0x10000) {
- mpack_w(buf, 0xdc);
- mpack_w2(buf, len);
- } else {
- mpack_w(buf, 0xdd);
- mpack_w4(buf, len);
- }
-}
-
static char *mpack_array_dyn16(char **buf)
{
mpack_w(buf, 0xdc);
@@ -98,30 +56,44 @@ static char *mpack_array_dyn16(char **buf)
return pos;
}
-static void mpack_str(char **buf, const char *str)
+static void mpack_str_small(char **buf, const char *str, size_t len)
{
- assert(sizeof(schar_T) - 1 < 0x20);
- size_t len = strlen(str);
+ assert(len < 0x20);
mpack_w(buf, 0xa0 | len);
memcpy(*buf, str, len);
*buf += len;
}
+static void remote_ui_destroy(RemoteUI *ui)
+ FUNC_ATTR_NONNULL_ALL
+{
+ kv_destroy(ui->call_buf);
+ xfree(ui->packer.startptr);
+ XFREE_CLEAR(ui->term_name);
+ xfree(ui);
+}
+
void remote_ui_disconnect(uint64_t channel_id)
{
- UI *ui = pmap_get(uint64_t)(&connected_uis, channel_id);
+ RemoteUI *ui = pmap_get(uint64_t)(&connected_uis, channel_id);
if (!ui) {
return;
}
- UIData *data = ui->data;
- kv_destroy(data->call_buf);
pmap_del(uint64_t)(&connected_uis, channel_id, NULL);
ui_detach_impl(ui, channel_id);
+ remote_ui_destroy(ui);
+}
- // Destroy `ui`.
- XFREE_CLEAR(ui->term_name);
- xfree(ui);
+#ifdef EXITFREE
+void remote_ui_free_all_mem(void)
+{
+ RemoteUI *ui;
+ map_foreach_value(&connected_uis, ui, {
+ remote_ui_destroy(ui);
+ });
+ map_destroy(uint64_t, &connected_uis);
}
+#endif
/// Wait until ui has connected on stdio channel if only_stdio
/// is true, otherwise any channel.
@@ -145,7 +117,7 @@ void remote_ui_wait_for_attach(bool only_stdio)
/// Activates UI events on the channel.
///
-/// Entry point of all UI clients. Allows |\-\-embed| to continue startup.
+/// Entry point of all UI clients. Allows |--embed| to continue startup.
/// Implies that the client is ready to show the UI. Adds the client to the
/// list of UIs. |nvim_list_uis()|
///
@@ -173,7 +145,7 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height, Dictiona
"Expected width > 0 and height > 0");
return;
}
- UI *ui = xcalloc(1, sizeof(UI));
+ RemoteUI *ui = xcalloc(1, sizeof(RemoteUI));
ui->width = (int)width;
ui->height = (int)height;
ui->pum_row = -1.0;
@@ -200,22 +172,26 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height, Dictiona
ui->ui_ext[kUICmdline] = true;
}
- UIData *data = ui->data;
- data->channel_id = channel_id;
- data->cur_event = NULL;
- data->hl_id = 0;
- data->client_col = -1;
- data->nevents_pos = NULL;
- data->nevents = 0;
- data->flushed_events = false;
- data->ncalls_pos = NULL;
- data->ncalls = 0;
- data->ncells_pending = 0;
- data->buf_wptr = data->buf;
- data->temp_buf = NULL;
- data->wildmenu_active = false;
- data->call_buf = (Array)ARRAY_DICT_INIT;
- kv_ensure_space(data->call_buf, 16);
+ ui->channel_id = channel_id;
+ ui->cur_event = NULL;
+ ui->hl_id = 0;
+ ui->client_col = -1;
+ ui->nevents_pos = NULL;
+ ui->nevents = 0;
+ ui->flushed_events = false;
+ ui->ncalls_pos = NULL;
+ ui->ncalls = 0;
+ ui->ncells_pending = 0;
+ ui->packer = (PackerBuffer) {
+ .startptr = NULL,
+ .ptr = NULL,
+ .endptr = NULL,
+ .packer_flush = ui_flush_callback,
+ .anydata = ui,
+ };
+ ui->wildmenu_active = false;
+ ui->call_buf = (Array)ARRAY_DICT_INIT;
+ kv_ensure_space(ui->call_buf, 16);
pmap_put(uint64_t)(&connected_uis, channel_id, ui);
ui_attach_impl(ui, channel_id);
@@ -227,10 +203,9 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height, Dictiona
void ui_attach(uint64_t channel_id, Integer width, Integer height, Boolean enable_rgb, Error *err)
FUNC_API_DEPRECATED_SINCE(1)
{
- Dictionary opts = ARRAY_DICT_INIT;
- PUT(opts, "rgb", BOOLEAN_OBJ(enable_rgb));
+ MAXSIZE_TEMP_DICT(opts, 1);
+ PUT_C(opts, "rgb", BOOLEAN_OBJ(enable_rgb));
nvim_ui_attach(channel_id, width, height, opts, err);
- api_free_dictionary(opts);
}
/// Tells the nvim server if focus was gained or lost by the GUI
@@ -268,7 +243,7 @@ void nvim_ui_detach(uint64_t channel_id, Error *err)
}
// TODO(bfredl): use me to detach a specific ui from the server
-void remote_ui_stop(UI *ui)
+void remote_ui_stop(RemoteUI *ui)
{
}
@@ -287,7 +262,7 @@ void nvim_ui_try_resize(uint64_t channel_id, Integer width, Integer height, Erro
return;
}
- UI *ui = pmap_get(uint64_t)(&connected_uis, channel_id);
+ RemoteUI *ui = pmap_get(uint64_t)(&connected_uis, channel_id);
ui->width = (int)width;
ui->height = (int)height;
ui_refresh();
@@ -301,12 +276,12 @@ void nvim_ui_set_option(uint64_t channel_id, String name, Object value, Error *e
"UI not attached to channel: %" PRId64, channel_id);
return;
}
- UI *ui = pmap_get(uint64_t)(&connected_uis, channel_id);
+ RemoteUI *ui = pmap_get(uint64_t)(&connected_uis, channel_id);
ui_set_option(ui, false, name, value, error);
}
-static void ui_set_option(UI *ui, bool init, String name, Object value, Error *err)
+static void ui_set_option(RemoteUI *ui, bool init, String name, Object value, Error *err)
{
if (strequal(name.data, "override")) {
VALIDATE_T("override", kObjectTypeBoolean, value.type, {
@@ -435,7 +410,7 @@ void nvim_ui_try_resize_grid(uint64_t channel_id, Integer grid, Integer width, I
}
/// Tells Nvim the number of elements displaying in the popupmenu, to decide
-/// <PageUp> and <PageDown> movement.
+/// [<PageUp>] and [<PageDown>] movement.
///
/// @param channel_id
/// @param height Popupmenu height, must be greater than zero.
@@ -454,7 +429,7 @@ void nvim_ui_pum_set_height(uint64_t channel_id, Integer height, Error *err)
return;
}
- UI *ui = pmap_get(uint64_t)(&connected_uis, channel_id);
+ RemoteUI *ui = pmap_get(uint64_t)(&connected_uis, channel_id);
if (!ui->ui_ext[kUIPopupmenu]) {
api_set_error(err, kErrorTypeValidation,
"It must support the ext_popupmenu option");
@@ -490,7 +465,7 @@ void nvim_ui_pum_set_bounds(uint64_t channel_id, Float width, Float height, Floa
return;
}
- UI *ui = pmap_get(uint64_t)(&connected_uis, channel_id);
+ RemoteUI *ui = pmap_get(uint64_t)(&connected_uis, channel_id);
if (!ui->ui_ext[kUIPopupmenu]) {
api_set_error(err, kErrorTypeValidation,
"UI must support the ext_popupmenu option");
@@ -522,7 +497,7 @@ void nvim_ui_pum_set_bounds(uint64_t channel_id, Float width, Float height, Floa
///
/// @param channel_id
/// @param event Event name
-/// @param payload Event payload
+/// @param value Event payload
/// @param[out] err Error details, if any.
void nvim_ui_term_event(uint64_t channel_id, String event, Object value, Error *err)
FUNC_API_SINCE(12) FUNC_API_REMOTE_ONLY
@@ -539,126 +514,75 @@ void nvim_ui_term_event(uint64_t channel_id, String event, Object value, Error *
}
}
-static void flush_event(UIData *data)
+static void flush_event(RemoteUI *ui)
{
- if (data->cur_event) {
- mpack_w2(&data->ncalls_pos, data->ncalls);
- data->cur_event = NULL;
- }
- if (!data->nevents_pos) {
- assert(BUF_POS(data) == 0);
- char **buf = &data->buf_wptr;
- // [2, "redraw", [...]]
- mpack_array(buf, 3);
- mpack_uint(buf, 2);
- mpack_str(buf, "redraw");
- data->nevents_pos = mpack_array_dyn16(buf);
+ if (ui->cur_event) {
+ mpack_w2(&ui->ncalls_pos, 1 + ui->ncalls);
+ ui->cur_event = NULL;
+ ui->ncalls_pos = NULL;
+ ui->ncalls = 0;
}
}
-static inline int write_cb(void *vdata, const char *buf, size_t len)
+static void ui_alloc_buf(RemoteUI *ui)
{
- UIData *data = (UIData *)vdata;
- if (!buf) {
- return 0;
- }
-
- data->pack_totlen += len;
- if (!data->temp_buf && UI_BUF_SIZE - BUF_POS(data) < len) {
- data->buf_overflow = true;
- return 0;
- }
-
- memcpy(data->buf_wptr, buf, len);
- data->buf_wptr += len;
-
- return 0;
+ ui->packer.startptr = alloc_block();
+ ui->packer.ptr = ui->packer.startptr;
+ ui->packer.endptr = ui->packer.startptr + UI_BUF_SIZE;
}
-static bool prepare_call(UI *ui, const char *name)
+static void prepare_call(RemoteUI *ui, const char *name)
{
- UIData *data = ui->data;
+ if (ui->packer.startptr && BUF_POS(ui) > UI_BUF_SIZE - EVENT_BUF_SIZE) {
+ ui_flush_buf(ui);
+ }
- if (BUF_POS(data) > UI_BUF_SIZE - EVENT_BUF_SIZE) {
- remote_ui_flush_buf(ui);
+ if (ui->packer.startptr == NULL) {
+ ui_alloc_buf(ui);
}
// To optimize data transfer(especially for "grid_line"), we bundle adjacent
// calls to same method together, so only add a new call entry if the last
// method call is different from "name"
- if (!data->cur_event || !strequal(data->cur_event, name)) {
- flush_event(data);
- data->cur_event = name;
- char **buf = &data->buf_wptr;
- data->ncalls_pos = mpack_array_dyn16(buf);
- mpack_str(buf, name);
- data->nevents++;
- data->ncalls = 1;
- return true;
+ if (!ui->cur_event || !strequal(ui->cur_event, name)) {
+ char **buf = &ui->packer.ptr;
+ if (!ui->nevents_pos) {
+ // [2, "redraw", [...]]
+ mpack_array(buf, 3);
+ mpack_uint(buf, 2);
+ mpack_str_small(buf, S_LEN("redraw"));
+ ui->nevents_pos = mpack_array_dyn16(buf);
+ assert(ui->cur_event == NULL);
+ }
+ flush_event(ui);
+ ui->cur_event = name;
+ ui->ncalls_pos = mpack_array_dyn16(buf);
+ mpack_str_small(buf, name, strlen(name));
+ ui->nevents++;
+ ui->ncalls = 1;
+ } else {
+ ui->ncalls++;
}
-
- return false;
}
-/// Pushes data into UI.UIData, to be consumed later by remote_ui_flush().
-static void push_call(UI *ui, const char *name, Array args)
+/// Pushes data into RemoteUI, to be consumed later by remote_ui_flush().
+static void push_call(RemoteUI *ui, const char *name, Array args)
{
- UIData *data = ui->data;
- bool pending = data->nevents_pos;
- char *buf_pos_save = data->buf_wptr;
-
- bool new_event = prepare_call(ui, name);
-
- msgpack_packer pac;
- data->pack_totlen = 0;
- data->buf_overflow = false;
- msgpack_packer_init(&pac, data, write_cb);
- msgpack_rpc_from_array(args, &pac);
- if (data->buf_overflow) {
- data->buf_wptr = buf_pos_save;
- if (new_event) {
- data->cur_event = NULL;
- data->nevents--;
- }
- if (pending) {
- remote_ui_flush_buf(ui);
- }
+ prepare_call(ui, name);
+ mpack_object_array(args, &ui->packer);
+}
- if (data->pack_totlen > UI_BUF_SIZE - strlen(name) - 20) {
- // TODO(bfredl): manually testable by setting UI_BUF_SIZE to 1024 (mode_info_set)
- data->temp_buf = xmalloc(20 + strlen(name) + data->pack_totlen);
- data->buf_wptr = data->temp_buf;
- char **buf = &data->buf_wptr;
- mpack_array(buf, 3);
- mpack_uint(buf, 2);
- mpack_str(buf, "redraw");
- mpack_array(buf, 1);
- mpack_array(buf, 2);
- mpack_str(buf, name);
- } else {
- prepare_call(ui, name);
- }
- data->pack_totlen = 0;
- data->buf_overflow = false;
- msgpack_rpc_from_array(args, &pac);
-
- if (data->temp_buf) {
- size_t size = (size_t)(data->buf_wptr - data->temp_buf);
- WBuffer *buf = wstream_new_buffer(data->temp_buf, size, 1, xfree);
- rpc_write_raw(data->channel_id, buf);
- data->temp_buf = NULL;
- data->buf_wptr = data->buf;
- data->nevents_pos = NULL;
- }
- }
- data->ncalls++;
+static void ui_flush_callback(PackerBuffer *packer)
+{
+ RemoteUI *ui = packer->anydata;
+ ui_flush_buf(ui);
+ ui_alloc_buf(ui);
}
-void remote_ui_grid_clear(UI *ui, Integer grid)
+void remote_ui_grid_clear(RemoteUI *ui, Integer grid)
{
- UIData *data = ui->data;
- Array args = data->call_buf;
+ Array args = ui->call_buf;
if (ui->ui_ext[kUILinegrid]) {
ADD_C(args, INTEGER_OBJ(grid));
}
@@ -666,14 +590,13 @@ void remote_ui_grid_clear(UI *ui, Integer grid)
push_call(ui, name, args);
}
-void remote_ui_grid_resize(UI *ui, Integer grid, Integer width, Integer height)
+void remote_ui_grid_resize(RemoteUI *ui, Integer grid, Integer width, Integer height)
{
- UIData *data = ui->data;
- Array args = data->call_buf;
+ Array args = ui->call_buf;
if (ui->ui_ext[kUILinegrid]) {
ADD_C(args, INTEGER_OBJ(grid));
} else {
- data->client_col = -1; // force cursor update
+ ui->client_col = -1; // force cursor update
}
ADD_C(args, INTEGER_OBJ(width));
ADD_C(args, INTEGER_OBJ(height));
@@ -681,12 +604,11 @@ void remote_ui_grid_resize(UI *ui, Integer grid, Integer width, Integer height)
push_call(ui, name, args);
}
-void remote_ui_grid_scroll(UI *ui, Integer grid, Integer top, Integer bot, Integer left,
+void remote_ui_grid_scroll(RemoteUI *ui, Integer grid, Integer top, Integer bot, Integer left,
Integer right, Integer rows, Integer cols)
{
- UIData *data = ui->data;
if (ui->ui_ext[kUILinegrid]) {
- Array args = data->call_buf;
+ Array args = ui->call_buf;
ADD_C(args, INTEGER_OBJ(grid));
ADD_C(args, INTEGER_OBJ(top));
ADD_C(args, INTEGER_OBJ(bot));
@@ -696,20 +618,20 @@ void remote_ui_grid_scroll(UI *ui, Integer grid, Integer top, Integer bot, Integ
ADD_C(args, INTEGER_OBJ(cols));
push_call(ui, "grid_scroll", args);
} else {
- Array args = data->call_buf;
+ Array args = ui->call_buf;
ADD_C(args, INTEGER_OBJ(top));
ADD_C(args, INTEGER_OBJ(bot - 1));
ADD_C(args, INTEGER_OBJ(left));
ADD_C(args, INTEGER_OBJ(right - 1));
push_call(ui, "set_scroll_region", args);
- args = data->call_buf;
+ args = ui->call_buf;
ADD_C(args, INTEGER_OBJ(rows));
push_call(ui, "scroll", args);
// some clients have "clear" being affected by scroll region,
// so reset it.
- args = data->call_buf;
+ args = ui->call_buf;
ADD_C(args, INTEGER_OBJ(0));
ADD_C(args, INTEGER_OBJ(ui->height - 1));
ADD_C(args, INTEGER_OBJ(0));
@@ -718,14 +640,13 @@ void remote_ui_grid_scroll(UI *ui, Integer grid, Integer top, Integer bot, Integ
}
}
-void remote_ui_default_colors_set(UI *ui, Integer rgb_fg, Integer rgb_bg, Integer rgb_sp,
+void remote_ui_default_colors_set(RemoteUI *ui, Integer rgb_fg, Integer rgb_bg, Integer rgb_sp,
Integer cterm_fg, Integer cterm_bg)
{
if (!ui->ui_ext[kUITermColors]) {
HL_SET_DEFAULT_COLORS(rgb_fg, rgb_bg, rgb_sp);
}
- UIData *data = ui->data;
- Array args = data->call_buf;
+ Array args = ui->call_buf;
ADD_C(args, INTEGER_OBJ(rgb_fg));
ADD_C(args, INTEGER_OBJ(rgb_bg));
ADD_C(args, INTEGER_OBJ(rgb_sp));
@@ -735,34 +656,41 @@ void remote_ui_default_colors_set(UI *ui, Integer rgb_fg, Integer rgb_bg, Intege
// Deprecated
if (!ui->ui_ext[kUILinegrid]) {
- args = data->call_buf;
+ args = ui->call_buf;
ADD_C(args, INTEGER_OBJ(ui->rgb ? rgb_fg : cterm_fg - 1));
push_call(ui, "update_fg", args);
- args = data->call_buf;
+ args = ui->call_buf;
ADD_C(args, INTEGER_OBJ(ui->rgb ? rgb_bg : cterm_bg - 1));
push_call(ui, "update_bg", args);
- args = data->call_buf;
+ args = ui->call_buf;
ADD_C(args, INTEGER_OBJ(ui->rgb ? rgb_sp : -1));
push_call(ui, "update_sp", args);
}
}
-void remote_ui_hl_attr_define(UI *ui, Integer id, HlAttrs rgb_attrs, HlAttrs cterm_attrs,
+void remote_ui_hl_attr_define(RemoteUI *ui, Integer id, HlAttrs rgb_attrs, HlAttrs cterm_attrs,
Array info)
{
if (!ui->ui_ext[kUILinegrid]) {
return;
}
- UIData *data = ui->data;
- Array args = data->call_buf;
+ Array args = ui->call_buf;
ADD_C(args, INTEGER_OBJ(id));
MAXSIZE_TEMP_DICT(rgb, HLATTRS_DICT_SIZE);
MAXSIZE_TEMP_DICT(cterm, HLATTRS_DICT_SIZE);
hlattrs2dict(&rgb, NULL, rgb_attrs, true, false);
hlattrs2dict(&cterm, NULL, rgb_attrs, false, false);
+
+ // URLs are not added in hlattrs2dict since they are used only by UIs and not by the highlight
+ // system. So we add them here.
+ if (rgb_attrs.url >= 0) {
+ const char *url = hl_get_url((uint32_t)rgb_attrs.url);
+ PUT_C(rgb, "url", CSTR_AS_OBJ(url));
+ }
+
ADD_C(args, DICTIONARY_OBJ(rgb));
ADD_C(args, DICTIONARY_OBJ(cterm));
@@ -775,15 +703,14 @@ void remote_ui_hl_attr_define(UI *ui, Integer id, HlAttrs rgb_attrs, HlAttrs cte
push_call(ui, "hl_attr_define", args);
}
-void remote_ui_highlight_set(UI *ui, int id)
+void remote_ui_highlight_set(RemoteUI *ui, int id)
{
- UIData *data = ui->data;
- Array args = data->call_buf;
+ Array args = ui->call_buf;
- if (data->hl_id == id) {
+ if (ui->hl_id == id) {
return;
}
- data->hl_id = id;
+ ui->hl_id = id;
MAXSIZE_TEMP_DICT(dict, HLATTRS_DICT_SIZE);
hlattrs2dict(&dict, NULL, syn_attr2entry(id), ui->rgb, false);
ADD_C(args, DICTIONARY_OBJ(dict));
@@ -791,57 +718,55 @@ void remote_ui_highlight_set(UI *ui, int id)
}
/// "true" cursor used only for input focus
-void remote_ui_grid_cursor_goto(UI *ui, Integer grid, Integer row, Integer col)
+void remote_ui_grid_cursor_goto(RemoteUI *ui, Integer grid, Integer row, Integer col)
{
if (ui->ui_ext[kUILinegrid]) {
- UIData *data = ui->data;
- Array args = data->call_buf;
+ Array args = ui->call_buf;
ADD_C(args, INTEGER_OBJ(grid));
ADD_C(args, INTEGER_OBJ(row));
ADD_C(args, INTEGER_OBJ(col));
push_call(ui, "grid_cursor_goto", args);
} else {
- UIData *data = ui->data;
- data->cursor_row = row;
- data->cursor_col = col;
+ ui->cursor_row = row;
+ ui->cursor_col = col;
remote_ui_cursor_goto(ui, row, col);
}
}
/// emulated cursor used both for drawing and for input focus
-void remote_ui_cursor_goto(UI *ui, Integer row, Integer col)
+void remote_ui_cursor_goto(RemoteUI *ui, Integer row, Integer col)
{
- UIData *data = ui->data;
- if (data->client_row == row && data->client_col == col) {
+ if (ui->client_row == row && ui->client_col == col) {
return;
}
- data->client_row = row;
- data->client_col = col;
- Array args = data->call_buf;
+ ui->client_row = row;
+ ui->client_col = col;
+ Array args = ui->call_buf;
ADD_C(args, INTEGER_OBJ(row));
ADD_C(args, INTEGER_OBJ(col));
push_call(ui, "cursor_goto", args);
}
-void remote_ui_put(UI *ui, const char *cell)
+void remote_ui_put(RemoteUI *ui, const char *cell)
{
- UIData *data = ui->data;
- data->client_col++;
- Array args = data->call_buf;
- ADD_C(args, CSTR_AS_OBJ((char *)cell));
+ ui->client_col++;
+ Array args = ui->call_buf;
+ ADD_C(args, CSTR_AS_OBJ(cell));
push_call(ui, "put", args);
}
-void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Integer endcol,
+void remote_ui_raw_line(RemoteUI *ui, Integer grid, Integer row, Integer startcol, Integer endcol,
Integer clearcol, Integer clearattr, LineFlags flags, const schar_T *chunk,
const sattr_T *attrs)
{
- UIData *data = ui->data;
+ // If MAX_SCHAR_SIZE is made larger, we need to refactor implementation below
+ // to not only use FIXSTR (only up to 0x20 bytes)
+ STATIC_ASSERT(MAX_SCHAR_SIZE - 1 < 0x20, "SCHAR doesn't fit in fixstr");
+
if (ui->ui_ext[kUILinegrid]) {
prepare_call(ui, "grid_line");
- data->ncalls++;
- char **buf = &data->buf_wptr;
+ char **buf = &ui->packer.ptr;
mpack_array(buf, 5);
mpack_uint(buf, (uint32_t)grid);
mpack_uint(buf, (uint32_t)row);
@@ -856,7 +781,7 @@ void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Int
for (size_t i = 0; i < ncells; i++) {
repeat++;
if (i == ncells - 1 || attrs[i] != attrs[i + 1] || chunk[i] != chunk[i + 1]) {
- if (UI_BUF_SIZE - BUF_POS(data) < 2 * (1 + 2 + sizeof(schar_T) + 5 + 5) + 1) {
+ if (UI_BUF_SIZE - BUF_POS(ui) < 2 * (1 + 2 + sizeof(schar_T) + 5 + 5) + 1) {
// close to overflowing the redraw buffer. finish this event,
// flush, and start a new "grid_line" event at the current position.
// For simplicity leave place for the final "clear" element
@@ -865,10 +790,9 @@ void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Int
// We only ever set the wrap field on the final "grid_line" event for the line.
mpack_bool(buf, false);
- remote_ui_flush_buf(ui);
+ ui_flush_buf(ui);
prepare_call(ui, "grid_line");
- data->ncalls++;
mpack_array(buf, 5);
mpack_uint(buf, (uint32_t)grid);
mpack_uint(buf, (uint32_t)row);
@@ -880,16 +804,16 @@ void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Int
uint32_t csize = (repeat > 1) ? 3 : ((attrs[i] != last_hl) ? 2 : 1);
nelem++;
mpack_array(buf, csize);
- char sc_buf[MAX_SCHAR_SIZE];
- schar_get(sc_buf, chunk[i]);
- mpack_str(buf, sc_buf);
+ char *size_byte = (*buf)++;
+ size_t len = schar_get_adv(buf, chunk[i]);
+ *size_byte = (char)(0xa0 | len);
if (csize >= 2) {
mpack_uint(buf, (uint32_t)attrs[i]);
if (csize >= 3) {
mpack_uint(buf, repeat);
}
}
- data->ncells_pending += MIN(repeat, 2);
+ ui->ncells_pending += MIN(repeat, 2);
last_hl = attrs[i];
repeat = 0;
was_space = chunk[i] == schar_from_ascii(' ');
@@ -899,18 +823,18 @@ void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Int
// no more cells to clear, so there is no ambiguity about what to clear.
if (endcol < clearcol || was_space) {
nelem++;
- data->ncells_pending += 1;
+ ui->ncells_pending += 1;
mpack_array(buf, 3);
- mpack_str(buf, " ");
+ mpack_str_small(buf, S_LEN(" "));
mpack_uint(buf, (uint32_t)clearattr);
mpack_uint(buf, (uint32_t)(clearcol - endcol));
}
mpack_w2(&lenpos, nelem);
mpack_bool(buf, flags & kLineFlagWrap);
- if (data->ncells_pending > 500) {
+ if (ui->ncells_pending > 500) {
// pass off cells to UI to let it start processing them
- remote_ui_flush_buf(ui);
+ ui_flush_buf(ui);
}
} else {
for (int i = 0; i < endcol - startcol; i++) {
@@ -920,7 +844,7 @@ void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Int
schar_get(sc_buf, chunk[i]);
remote_ui_put(ui, sc_buf);
if (utf_ambiguous_width(utf_ptr2char(sc_buf))) {
- data->client_col = -1; // force cursor update
+ ui->client_col = -1; // force cursor update
}
}
if (endcol < clearcol) {
@@ -944,49 +868,47 @@ void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Int
///
/// This might happen multiple times before the actual ui_flush, if the
/// total redraw size is large!
-void remote_ui_flush_buf(UI *ui)
+static void ui_flush_buf(RemoteUI *ui)
{
- UIData *data = ui->data;
- if (!data->nevents_pos) {
+ if (!ui->packer.startptr || !BUF_POS(ui)) {
return;
}
- if (data->cur_event) {
- flush_event(data);
+
+ flush_event(ui);
+ if (ui->nevents_pos != NULL) {
+ mpack_w2(&ui->nevents_pos, ui->nevents);
+ ui->nevents = 0;
+ ui->nevents_pos = NULL;
}
- mpack_w2(&data->nevents_pos, data->nevents);
- data->nevents = 0;
- data->nevents_pos = NULL;
-
- // TODO(bfredl): elide copy by a length one free-list like the arena
- size_t size = BUF_POS(data);
- WBuffer *buf = wstream_new_buffer(xmemdup(data->buf, size), size, 1, xfree);
- rpc_write_raw(data->channel_id, buf);
- data->buf_wptr = data->buf;
- // we have sent events to the client, but possibly not yet the final "flush"
- // event.
- data->flushed_events = true;
-
- data->ncells_pending = 0;
+
+ WBuffer *buf = wstream_new_buffer(ui->packer.startptr, BUF_POS(ui), 1, free_block);
+ rpc_write_raw(ui->channel_id, buf);
+
+ ui->packer.startptr = NULL;
+ ui->packer.ptr = NULL;
+
+ // we have sent events to the client, but possibly not yet the final "flush" event.
+ ui->flushed_events = true;
+ ui->ncells_pending = 0;
}
/// An intentional flush (vsync) when Nvim is finished redrawing the screen
///
/// Clients can know this happened by a final "flush" event at the end of the
/// "redraw" batch.
-void remote_ui_flush(UI *ui)
+void remote_ui_flush(RemoteUI *ui)
{
- UIData *data = ui->data;
- if (data->nevents > 0 || data->flushed_events) {
+ if (ui->nevents > 0 || ui->flushed_events) {
if (!ui->ui_ext[kUILinegrid]) {
- remote_ui_cursor_goto(ui, data->cursor_row, data->cursor_col);
+ remote_ui_cursor_goto(ui, ui->cursor_row, ui->cursor_col);
}
push_call(ui, "flush", (Array)ARRAY_DICT_INIT);
- remote_ui_flush_buf(ui);
- data->flushed_events = false;
+ ui_flush_buf(ui);
+ ui->flushed_events = false;
}
}
-static Array translate_contents(UI *ui, Array contents, Arena *arena)
+static Array translate_contents(RemoteUI *ui, Array contents, Arena *arena)
{
Array new_contents = arena_array(arena, contents.size);
for (size_t i = 0; i < contents.size; i++) {
@@ -996,32 +918,31 @@ static Array translate_contents(UI *ui, Array contents, Arena *arena)
if (attr) {
Dictionary rgb_attrs = arena_dict(arena, HLATTRS_DICT_SIZE);
hlattrs2dict(&rgb_attrs, NULL, syn_attr2entry(attr), ui->rgb, false);
- ADD(new_item, DICTIONARY_OBJ(rgb_attrs));
+ ADD_C(new_item, DICTIONARY_OBJ(rgb_attrs));
} else {
- ADD(new_item, DICTIONARY_OBJ((Dictionary)ARRAY_DICT_INIT));
+ ADD_C(new_item, DICTIONARY_OBJ((Dictionary)ARRAY_DICT_INIT));
}
- ADD(new_item, item.items[1]);
- ADD(new_contents, ARRAY_OBJ(new_item));
+ ADD_C(new_item, item.items[1]);
+ ADD_C(new_contents, ARRAY_OBJ(new_item));
}
return new_contents;
}
-static Array translate_firstarg(UI *ui, Array args, Arena *arena)
+static Array translate_firstarg(RemoteUI *ui, Array args, Arena *arena)
{
Array new_args = arena_array(arena, args.size);
Array contents = args.items[0].data.array;
ADD_C(new_args, ARRAY_OBJ(translate_contents(ui, contents, arena)));
for (size_t i = 1; i < args.size; i++) {
- ADD(new_args, args.items[i]);
+ ADD_C(new_args, args.items[i]);
}
return new_args;
}
-void remote_ui_event(UI *ui, char *name, Array args)
+void remote_ui_event(RemoteUI *ui, char *name, Array args)
{
Arena arena = ARENA_EMPTY;
- UIData *data = ui->data;
if (!ui->ui_ext[kUILinegrid]) {
// the representation of highlights in cmdline changed, translate back
// never consumes args
@@ -1030,7 +951,7 @@ void remote_ui_event(UI *ui, char *name, Array args)
push_call(ui, name, new_args);
goto free_ret;
} else if (strequal(name, "cmdline_block_show")) {
- Array new_args = data->call_buf;
+ Array new_args = ui->call_buf;
Array block = args.items[0].data.array;
Array new_block = arena_array(&arena, block.size);
for (size_t i = 0; i < block.size; i++) {
@@ -1049,10 +970,10 @@ void remote_ui_event(UI *ui, char *name, Array args)
// Back-compat: translate popupmenu_xx to legacy wildmenu_xx.
if (ui->ui_ext[kUIWildmenu]) {
if (strequal(name, "popupmenu_show")) {
- data->wildmenu_active = (args.items[4].data.integer == -1)
- || !ui->ui_ext[kUIPopupmenu];
- if (data->wildmenu_active) {
- Array new_args = data->call_buf;
+ ui->wildmenu_active = (args.items[4].data.integer == -1)
+ || !ui->ui_ext[kUIPopupmenu];
+ if (ui->wildmenu_active) {
+ Array new_args = ui->call_buf;
Array items = args.items[0].data.array;
Array new_items = arena_array(&arena, items.size);
for (size_t i = 0; i < items.size; i++) {
@@ -1061,18 +982,18 @@ void remote_ui_event(UI *ui, char *name, Array args)
ADD_C(new_args, ARRAY_OBJ(new_items));
push_call(ui, "wildmenu_show", new_args);
if (args.items[1].data.integer != -1) {
- Array new_args2 = data->call_buf;
+ Array new_args2 = ui->call_buf;
ADD_C(new_args2, args.items[1]);
push_call(ui, "wildmenu_select", new_args2);
}
goto free_ret;
}
} else if (strequal(name, "popupmenu_select")) {
- if (data->wildmenu_active) {
+ if (ui->wildmenu_active) {
name = "wildmenu_select";
}
} else if (strequal(name, "popupmenu_hide")) {
- if (data->wildmenu_active) {
+ if (ui->wildmenu_active) {
name = "wildmenu_hide";
}
}
@@ -1084,9 +1005,3 @@ void remote_ui_event(UI *ui, char *name, Array args)
free_ret:
arena_mem_free(arena_finish(&arena));
}
-
-void remote_ui_inspect(UI *ui, Dictionary *info)
-{
- UIData *data = ui->data;
- PUT(*info, "chan", INTEGER_OBJ((Integer)data->channel_id));
-}