aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbfredl <bjorn.linse@gmail.com>2022-12-30 22:17:01 +0100
committerbfredl <bjorn.linse@gmail.com>2023-01-05 09:48:26 +0100
commit47ba78f89a1f0bba8168b4408bc55a3024d5ab97 (patch)
tree79a1d81956d87986467e4da70b4f9ad53b079040
parentae64772a88125153a438a0e9e43d5f6bcb4eeb28 (diff)
downloadrneovim-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)
-rwxr-xr-xsrc/nvim/CMakeLists.txt5
-rw-r--r--src/nvim/api/ui.c108
-rw-r--r--src/nvim/api/ui.h2
-rw-r--r--src/nvim/api/ui_events.in.h17
-rw-r--r--src/nvim/generators/c_grammar.lua2
-rwxr-xr-xsrc/nvim/generators/gen_api_ui_events.lua31
-rw-r--r--src/nvim/highlight.c23
-rw-r--r--src/nvim/lua/executor.c4
-rw-r--r--src/nvim/main.c8
-rw-r--r--src/nvim/memory.c1
-rw-r--r--src/nvim/tui/tui.c1469
-rw-r--r--src/nvim/ui.c168
-rw-r--r--src/nvim/ui.h43
-rw-r--r--src/nvim/ui_client.c41
-rw-r--r--src/nvim/ui_client.h2
-rw-r--r--src/nvim/ui_compositor.c133
16 files changed, 946 insertions, 1111 deletions
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt
index 6b92d0caa8..8ac52d8b72 100755
--- a/src/nvim/CMakeLists.txt
+++ b/src/nvim/CMakeLists.txt
@@ -36,7 +36,6 @@ set(HEADER_GENERATOR ${GENERATOR_DIR}/gen_declarations.lua)
set(GENERATED_INCLUDES_DIR ${PROJECT_BINARY_DIR}/include)
set(GENERATED_API_DISPATCH ${GENERATED_DIR}/api/private/dispatch_wrappers.generated.h)
set(GENERATED_FUNCS_METADATA ${GENERATED_DIR}/api/private/funcs_metadata.generated.h)
-set(GENERATED_UI_EVENTS ${GENERATED_DIR}/ui_events.generated.h)
set(GENERATED_UI_EVENTS_CALL ${GENERATED_DIR}/ui_events_call.generated.h)
set(GENERATED_UI_EVENTS_REMOTE ${GENERATED_DIR}/ui_events_remote.generated.h)
set(GENERATED_UI_EVENTS_CLIENT ${GENERATED_DIR}/ui_events_client.generated.h)
@@ -310,14 +309,12 @@ list(APPEND NVIM_GENERATED_SOURCES
)
add_custom_command(
- OUTPUT ${GENERATED_UI_EVENTS}
- ${GENERATED_UI_EVENTS_CALL}
+ OUTPUT ${GENERATED_UI_EVENTS_CALL}
${GENERATED_UI_EVENTS_REMOTE}
${GENERATED_UI_EVENTS_METADATA}
${GENERATED_UI_EVENTS_CLIENT}
COMMAND ${LUA_PRG} ${API_UI_EVENTS_GENERATOR} ${CMAKE_CURRENT_LIST_DIR}
${CMAKE_CURRENT_LIST_DIR}/api/ui_events.in.h
- ${GENERATED_UI_EVENTS}
${GENERATED_UI_EVENTS_CALL}
${GENERATED_UI_EVENTS_REMOTE}
${GENERATED_UI_EVENTS_METADATA}
diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c
index e4134133ac..32b294c0ce 100644
--- a/src/nvim/api/ui.c
+++ b/src/nvim/api/ui.c
@@ -29,41 +29,6 @@
#include "nvim/vim.h"
#include "nvim/window.h"
-typedef struct {
- uint64_t channel_id;
-
-#define UI_BUF_SIZE 4096 ///< total buffer size for pending msgpack data.
- /// guaranteed size available for each new event (so packing of simple events
- /// and the header of grid_line will never fail)
-#define EVENT_BUF_SIZE 256
- char buf[UI_BUF_SIZE]; ///< buffer of packed but not yet sent msgpack data
- char *buf_wptr; ///< write head of buffer
- const char *cur_event; ///< name of current event (might get multiple arglists)
- Array call_buf; ///< buffer for constructing a single arg list (max 16 elements!)
-
- // state for write_cb, while packing a single arglist to msgpack. This
- // might fail due to buffer overflow.
- size_t pack_totlen;
- bool buf_overflow;
- char *temp_buf;
-
- // We start packing the two outermost msgpack arrays before knowing the total
- // number of elements. Thus track the location where array size will need
- // to be written in the msgpack buffer, once the specific array is finished.
- char *nevents_pos;
- char *ncalls_pos;
- uint32_t nevents; ///< number of distinct events (top-level args to "redraw"
- uint32_t ncalls; ///< number of calls made to the current event (plus one for the name!)
- bool flushed_events; ///< events where sent to client without "flush" event
-
- int hl_id; // Current highlight for legacy put event.
- Integer cursor_row, cursor_col; // Intended visible cursor position.
-
- // Position of legacy cursor, used both for drawing and visible user cursor.
- Integer client_row, client_col;
- bool wildmenu_active;
-} UIData;
-
#define BUF_POS(data) ((size_t)((data)->buf_wptr - (data)->buf))
#ifdef INCLUDE_GENERATED_DECLARATIONS
@@ -143,8 +108,6 @@ void remote_ui_disconnect(uint64_t channel_id)
UIData *data = ui->data;
kv_destroy(data->call_buf);
pmap_del(uint64_t)(&connected_uis, channel_id);
- xfree(data);
- ui->data = NULL; // Flag UI as "stopped".
ui_detach_impl(ui, channel_id);
xfree(ui);
}
@@ -204,32 +167,6 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height, Dictiona
ui->pum_col = -1.0;
ui->rgb = true;
ui->override = false;
- ui->grid_resize = remote_ui_grid_resize;
- ui->grid_clear = remote_ui_grid_clear;
- ui->grid_cursor_goto = remote_ui_grid_cursor_goto;
- ui->mode_info_set = remote_ui_mode_info_set;
- ui->update_menu = remote_ui_update_menu;
- ui->busy_start = remote_ui_busy_start;
- ui->busy_stop = remote_ui_busy_stop;
- ui->mouse_on = remote_ui_mouse_on;
- ui->mouse_off = remote_ui_mouse_off;
- ui->mode_change = remote_ui_mode_change;
- ui->grid_scroll = remote_ui_grid_scroll;
- ui->hl_attr_define = remote_ui_hl_attr_define;
- ui->hl_group_set = remote_ui_hl_group_set;
- ui->raw_line = remote_ui_raw_line;
- ui->bell = remote_ui_bell;
- ui->visual_bell = remote_ui_visual_bell;
- ui->default_colors_set = remote_ui_default_colors_set;
- ui->flush = remote_ui_flush;
- ui->suspend = remote_ui_suspend;
- ui->set_title = remote_ui_set_title;
- ui->set_icon = remote_ui_set_icon;
- ui->option_set = remote_ui_option_set;
- ui->msg_set_pos = remote_ui_msg_set_pos;
- ui->event = remote_ui_event;
- ui->inspect = remote_ui_inspect;
- ui->win_viewport = remote_ui_win_viewport;
CLEAR_FIELD(ui->ui_ext);
@@ -252,7 +189,7 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height, Dictiona
ui->ui_ext[kUICmdline] = true;
}
- UIData *data = xmalloc(sizeof(UIData));
+ UIData *data = ui->data;
data->channel_id = channel_id;
data->cur_event = NULL;
data->hl_id = 0;
@@ -267,7 +204,6 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height, Dictiona
data->wildmenu_active = false;
data->call_buf = (Array)ARRAY_DICT_INIT;
kv_ensure_space(data->call_buf, 16);
- ui->data = data;
pmap_put(uint64_t)(&connected_uis, channel_id, ui);
ui_attach_impl(ui, channel_id);
@@ -313,6 +249,10 @@ void nvim_ui_detach(uint64_t channel_id, Error *err)
remote_ui_disconnect(channel_id);
}
+// TODO(bfredl): use me to detach a specifc ui from the server
+void remote_ui_stop(UI *ui)
+{}
+
void nvim_ui_try_resize(uint64_t channel_id, Integer width, Integer height, Error *err)
FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY
{
@@ -684,7 +624,7 @@ static void push_call(UI *ui, const char *name, Array args)
data->ncalls++;
}
-static void remote_ui_grid_clear(UI *ui, Integer grid)
+void remote_ui_grid_clear(UI *ui, Integer grid)
{
UIData *data = ui->data;
Array args = data->call_buf;
@@ -695,7 +635,7 @@ static void remote_ui_grid_clear(UI *ui, Integer grid)
push_call(ui, name, args);
}
-static void remote_ui_grid_resize(UI *ui, Integer grid, Integer width, Integer height)
+void remote_ui_grid_resize(UI *ui, Integer grid, Integer width, Integer height)
{
UIData *data = ui->data;
Array args = data->call_buf;
@@ -708,8 +648,8 @@ static void remote_ui_grid_resize(UI *ui, Integer grid, Integer width, Integer h
push_call(ui, name, args);
}
-static void remote_ui_grid_scroll(UI *ui, Integer grid, Integer top, Integer bot, Integer left,
- Integer right, Integer rows, Integer cols)
+void remote_ui_grid_scroll(UI *ui, Integer grid, Integer top, Integer bot, Integer left,
+ Integer right, Integer rows, Integer cols)
{
UIData *data = ui->data;
if (ui->ui_ext[kUILinegrid]) {
@@ -745,8 +685,8 @@ static void remote_ui_grid_scroll(UI *ui, Integer grid, Integer top, Integer bot
}
}
-static void remote_ui_default_colors_set(UI *ui, Integer rgb_fg, Integer rgb_bg, Integer rgb_sp,
- Integer cterm_fg, Integer cterm_bg)
+void remote_ui_default_colors_set(UI *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);
@@ -776,8 +716,8 @@ static void remote_ui_default_colors_set(UI *ui, Integer rgb_fg, Integer rgb_bg,
}
}
-static void remote_ui_hl_attr_define(UI *ui, Integer id, HlAttrs rgb_attrs, HlAttrs cterm_attrs,
- Array info)
+void remote_ui_hl_attr_define(UI *ui, Integer id, HlAttrs rgb_attrs, HlAttrs cterm_attrs,
+ Array info)
{
if (!ui->ui_ext[kUILinegrid]) {
return;
@@ -802,7 +742,7 @@ static void remote_ui_hl_attr_define(UI *ui, Integer id, HlAttrs rgb_attrs, HlAt
push_call(ui, "hl_attr_define", args);
}
-static void remote_ui_highlight_set(UI *ui, int id)
+void remote_ui_highlight_set(UI *ui, int id)
{
UIData *data = ui->data;
Array args = data->call_buf;
@@ -818,7 +758,7 @@ static void remote_ui_highlight_set(UI *ui, int id)
}
/// "true" cursor used only for input focus
-static void remote_ui_grid_cursor_goto(UI *ui, Integer grid, Integer row, Integer col)
+void remote_ui_grid_cursor_goto(UI *ui, Integer grid, Integer row, Integer col)
{
if (ui->ui_ext[kUILinegrid]) {
UIData *data = ui->data;
@@ -836,7 +776,7 @@ static void remote_ui_grid_cursor_goto(UI *ui, Integer grid, Integer row, Intege
}
/// emulated cursor used both for drawing and for input focus
-static void remote_ui_cursor_goto(UI *ui, Integer row, Integer col)
+void remote_ui_cursor_goto(UI *ui, Integer row, Integer col)
{
UIData *data = ui->data;
if (data->client_row == row && data->client_col == col) {
@@ -850,7 +790,7 @@ static void remote_ui_cursor_goto(UI *ui, Integer row, Integer col)
push_call(ui, "cursor_goto", args);
}
-static void remote_ui_put(UI *ui, const char *cell)
+void remote_ui_put(UI *ui, const char *cell)
{
UIData *data = ui->data;
data->client_col++;
@@ -859,9 +799,9 @@ static void remote_ui_put(UI *ui, const char *cell)
push_call(ui, "put", args);
}
-static void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Integer endcol,
- Integer clearcol, Integer clearattr, LineFlags flags,
- const schar_T *chunk, const sattr_T *attrs)
+void remote_ui_raw_line(UI *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 (ui->ui_ext[kUILinegrid]) {
@@ -953,7 +893,7 @@ static void remote_ui_raw_line(UI *ui, Integer grid, Integer row, Integer startc
///
/// This might happen multiple times before the actual ui_flush, if the
/// total redraw size is large!
-static void remote_ui_flush_buf(UI *ui)
+void remote_ui_flush_buf(UI *ui)
{
UIData *data = ui->data;
if (!data->nevents_pos) {
@@ -980,7 +920,7 @@ static void remote_ui_flush_buf(UI *ui)
///
/// Clients can know this happened by a final "flush" event at the end of the
/// "redraw" batch.
-static void remote_ui_flush(UI *ui)
+void remote_ui_flush(UI *ui)
{
UIData *data = ui->data;
if (data->nevents > 0 || data->flushed_events) {
@@ -1025,7 +965,7 @@ static Array translate_firstarg(UI *ui, Array args, Arena *arena)
return new_args;
}
-static void remote_ui_event(UI *ui, char *name, Array args)
+void remote_ui_event(UI *ui, char *name, Array args)
{
Arena arena = ARENA_EMPTY;
UIData *data = ui->data;
@@ -1092,7 +1032,7 @@ free_ret:
arena_mem_free(arena_finish(&arena));
}
-static void remote_ui_inspect(UI *ui, Dictionary *info)
+void remote_ui_inspect(UI *ui, Dictionary *info)
{
UIData *data = ui->data;
PUT(*info, "chan", INTEGER_OBJ((Integer)data->channel_id));
diff --git a/src/nvim/api/ui.h b/src/nvim/api/ui.h
index bc70406acb..b3fe0fa2bb 100644
--- a/src/nvim/api/ui.h
+++ b/src/nvim/api/ui.h
@@ -5,8 +5,10 @@
#include "nvim/api/private/defs.h"
#include "nvim/map.h"
+#include "nvim/ui.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "api/ui.h.generated.h"
+# include "ui_events_remote.h.generated.h"
#endif
#endif // NVIM_API_UI_H
diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h
index d5c79272b7..a08e8dbfeb 100644
--- a/src/nvim/api/ui_events.in.h
+++ b/src/nvim/api/ui_events.in.h
@@ -37,7 +37,7 @@ void set_title(String title)
void set_icon(String icon)
FUNC_API_SINCE(3);
void screenshot(String path)
- FUNC_API_SINCE(7) FUNC_API_REMOTE_IMPL;
+ FUNC_API_SINCE(7);
void option_set(String name, Object value)
FUNC_API_SINCE(4);
// Stop event is not exported as such, represented by EOF in the msgpack stream.
@@ -75,7 +75,7 @@ void default_colors_set(Integer rgb_fg, Integer rgb_bg, Integer rgb_sp, Integer
void hl_attr_define(Integer id, HlAttrs rgb_attrs, HlAttrs cterm_attrs, Array info)
FUNC_API_SINCE(5) FUNC_API_REMOTE_IMPL;
void hl_group_set(String name, Integer id)
- FUNC_API_SINCE(6);
+ FUNC_API_SINCE(6) FUNC_API_CLIENT_IGNORE;
void grid_resize(Integer grid, Integer width, Integer height)
FUNC_API_SINCE(5) FUNC_API_REMOTE_IMPL FUNC_API_COMPOSITOR_IMPL FUNC_API_CLIENT_IMPL;
void grid_clear(Integer grid)
@@ -97,9 +97,6 @@ void raw_line(Integer grid, Integer row, Integer startcol, Integer endcol, Integ
Integer clearattr, LineFlags flags, const schar_T *chunk, const sattr_T *attrs)
FUNC_API_NOEXPORT FUNC_API_COMPOSITOR_IMPL;
-void event(char *name, Array args)
- FUNC_API_NOEXPORT FUNC_API_COMPOSITOR_IMPL;
-
void win_pos(Integer grid, Window win, Integer startrow, Integer startcol, Integer width,
Integer height)
FUNC_API_SINCE(6) FUNC_API_REMOTE_ONLY;
@@ -114,11 +111,11 @@ void win_close(Integer grid)
FUNC_API_SINCE(6) FUNC_API_REMOTE_ONLY;
void msg_set_pos(Integer grid, Integer row, Boolean scrolled, String sep_char)
- FUNC_API_SINCE(6) FUNC_API_COMPOSITOR_IMPL;
+ FUNC_API_SINCE(6) FUNC_API_COMPOSITOR_IMPL FUNC_API_CLIENT_IGNORE;
void win_viewport(Integer grid, Window win, Integer topline, Integer botline, Integer curline,
Integer curcol, Integer line_count)
- FUNC_API_SINCE(7) FUNC_API_BRIDGE_IMPL;
+ FUNC_API_SINCE(7) FUNC_API_CLIENT_IGNORE;
void win_extmark(Integer grid, Window win, Integer ns_id, Integer mark_id, Integer row, Integer col)
FUNC_API_SINCE(10) FUNC_API_REMOTE_ONLY;
@@ -150,11 +147,11 @@ void cmdline_block_hide(void)
FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY;
void wildmenu_show(Array items)
- FUNC_API_SINCE(3) FUNC_API_REMOTE_IMPL;
+ FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY;
void wildmenu_select(Integer selected)
- FUNC_API_SINCE(3) FUNC_API_REMOTE_IMPL;
+ FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY;
void wildmenu_hide(void)
- FUNC_API_SINCE(3) FUNC_API_REMOTE_IMPL;
+ FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY;
void msg_show(String kind, Array content, Boolean replace_last)
FUNC_API_SINCE(6) FUNC_API_REMOTE_ONLY;
diff --git a/src/nvim/generators/c_grammar.lua b/src/nvim/generators/c_grammar.lua
index 3ea5904338..3e89b60b4a 100644
--- a/src/nvim/generators/c_grammar.lua
+++ b/src/nvim/generators/c_grammar.lua
@@ -49,9 +49,9 @@ local c_proto = Ct(
(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_REMOTE_IMPL') * Cc(true)), 'remote_impl') ^ -1) *
- (fill * Cg((P('FUNC_API_BRIDGE_IMPL') * Cc(true)), 'bridge_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) *
+ (fill * Cg((P('FUNC_API_CLIENT_IGNORE') * Cc(true)), 'client_ignore') ^ -1) *
fill * P(';')
)
diff --git a/src/nvim/generators/gen_api_ui_events.lua b/src/nvim/generators/gen_api_ui_events.lua
index c9a2e3ff66..827097f69d 100755
--- a/src/nvim/generators/gen_api_ui_events.lua
+++ b/src/nvim/generators/gen_api_ui_events.lua
@@ -3,13 +3,12 @@ local mpack = require('mpack')
local nvimdir = arg[1]
package.path = nvimdir .. '/?.lua;' .. package.path
-assert(#arg == 7)
+assert(#arg == 6)
local input = io.open(arg[2], 'rb')
-local proto_output = io.open(arg[3], 'wb')
-local call_output = io.open(arg[4], 'wb')
-local remote_output = io.open(arg[5], 'wb')
-local metadata_output = io.open(arg[6], 'wb')
-local client_output = io.open(arg[7], 'wb')
+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')
local c_grammar = require('generators.c_grammar')
local events = c_grammar.grammar:match(input:read('*all'))
@@ -81,12 +80,9 @@ local function call_ui_event_method(output, ev)
end
end
- output:write(' ui_call_'..ev.name..'(')
+ output:write(' tui_'..ev.name..'(tui')
for j = 1, #ev.parameters do
- output:write('arg_'..j)
- if j ~= #ev.parameters then
- output:write(', ')
- end
+ output:write(', arg_'..j)
end
output:write(');\n')
@@ -104,12 +100,9 @@ for i = 1, #events do
ev.since = tonumber(ev.since)
if not ev.remote_only then
- proto_output:write(' void (*'..ev.name..')')
- write_signature(proto_output, ev, 'UI *ui')
- proto_output:write(';\n')
if not ev.remote_impl and not ev.noexport then
- remote_output:write('static void remote_ui_'..ev.name)
+ remote_output:write('void remote_ui_'..ev.name)
write_signature(remote_output, ev, 'UI *ui')
remote_output:write('\n{\n')
remote_output:write(' UIData *data = ui->data;\n')
@@ -130,6 +123,9 @@ for i = 1, #events do
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)
+ write_signature(call_output, ev, '', true)
+ call_output:write(";\n")
call_output:write(' UI_CALL')
write_signature(call_output, ev, '!ui->composed, '..ev.name..', ui', true)
call_output:write(";\n")
@@ -151,14 +147,14 @@ for i = 1, #events do
call_output:write("}\n\n")
end
- if (not ev.remote_only) and (not ev.noexport) and (not ev.client_impl) then
+ if (not ev.remote_only) and (not ev.noexport) and (not ev.client_impl) and (not ev.client_ignore) then
call_ui_event_method(client_output, ev)
end
end
local client_events = {}
for _,ev in ipairs(events) do
- if (not ev.noexport) and ((not ev.remote_only) or ev.client_impl) then
+ if (not ev.noexport) and ((not ev.remote_only) or ev.client_impl) and (not ev.client_ignore) then
client_events[ev.name] = ev
end
end
@@ -176,7 +172,6 @@ end
client_output:write('\n};\n\n')
client_output:write(hashfun)
-proto_output:close()
call_output:close()
remote_output:close()
client_output:close()
diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c
index 2c55e840f1..c3a259c87d 100644
--- a/src/nvim/highlight.c
+++ b/src/nvim/highlight.c
@@ -12,6 +12,7 @@
#include "lauxlib.h"
#include "nvim/api/private/defs.h"
#include "nvim/api/private/helpers.h"
+#include "nvim/api/ui.h"
#include "nvim/decoration_provider.h"
#include "nvim/drawscreen.h"
#include "nvim/gettext.h"
@@ -128,19 +129,15 @@ static int get_attr_entry(HlEntry entry)
/// When a UI connects, we need to send it the table of highlights used so far.
void ui_send_all_hls(UI *ui)
{
- if (ui->hl_attr_define) {
- for (size_t i = 1; i < kv_size(attr_entries); i++) {
- Array inspect = hl_inspect((int)i);
- ui->hl_attr_define(ui, (Integer)i, kv_A(attr_entries, i).attr,
- kv_A(attr_entries, i).attr, inspect);
- api_free_array(inspect);
- }
- }
- if (ui->hl_group_set) {
- for (size_t hlf = 0; hlf < HLF_COUNT; hlf++) {
- ui->hl_group_set(ui, cstr_as_string((char *)hlf_names[hlf]),
- highlight_attr[hlf]);
- }
+ for (size_t i = 1; i < kv_size(attr_entries); i++) {
+ Array inspect = hl_inspect((int)i);
+ remote_ui_hl_attr_define(ui, (Integer)i, kv_A(attr_entries, i).attr,
+ kv_A(attr_entries, i).attr, inspect);
+ api_free_array(inspect);
+ }
+ for (size_t hlf = 0; hlf < HLF_COUNT; hlf++) {
+ remote_ui_hl_group_set(ui, cstr_as_string((char *)hlf_names[hlf]),
+ highlight_attr[hlf]);
}
}
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index d4e7f3fb2c..34b572f884 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -653,7 +653,7 @@ ok:
}
LuaRef ui_event_cb = nlua_ref_global(lstate, 3);
- ui_comp_add_cb(ns_id, ui_event_cb, ext_widgets);
+ ui_add_cb(ns_id, ui_event_cb, ext_widgets);
return 0;
}
@@ -667,7 +667,7 @@ static int nlua_ui_detach(lua_State *lstate)
return luaL_error(lstate, "invalid ns_id");
}
- ui_comp_remove_cb(ns_id);
+ ui_remove_cb(ns_id);
return 0;
}
diff --git a/src/nvim/main.c b/src/nvim/main.c
index b5207f9cf6..b0da7f4500 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -627,11 +627,13 @@ void os_exit(int r)
{
exiting = true;
- if (!ui_client_channel_id) {
+ if (ui_client_channel_id) {
+ ui_client_stop();
+ } else {
ui_flush();
+ ui_call_stop();
+ ml_close_all(true); // remove all memfiles
}
- ui_call_stop();
- ml_close_all(true); // remove all memfiles
if (!event_teardown() && r == 0) {
r = 1; // Exit with error if main_loop did not teardown gracefully.
diff --git a/src/nvim/memory.c b/src/nvim/memory.c
index a65f45c012..aa8314b23d 100644
--- a/src/nvim/memory.c
+++ b/src/nvim/memory.c
@@ -834,7 +834,6 @@ void free_all_mem(void)
decor_free_all_mem();
ui_free_all_mem();
- ui_comp_free_all_mem();
nlua_free_all_mem();
// should be last, in case earlier free functions deallocates arenas
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index 066567a87f..162f54b6c1 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -1,7 +1,7 @@
// 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
-// Terminal UI functions. Invoked (by UI_CALL) on the UI process.
+// Terminal UI functions. Invoked (by ui_client.c) on the UI process.
#include <assert.h>
#include <signal.h>
@@ -89,7 +89,6 @@ typedef struct {
} Rect;
struct TUIData {
- UI *ui;
Loop *loop;
unibi_var_t params[9];
char buf[OUTBUF_SIZE];
@@ -158,6 +157,9 @@ struct TUIData {
} unibi_ext;
char *space_buf;
bool stopped;
+ int width;
+ int height;
+ bool rgb;
};
static int got_winch = 0;
@@ -166,144 +168,113 @@ static bool cursor_style_enabled = false;
# include "tui/tui.c.generated.h"
#endif
-UI *tui_start(void)
-{
- UI *ui = xcalloc(1, sizeof(UI)); // Freed by tui_data_destroy().
- ui->stop = tui_stop;
- ui->grid_resize = tui_grid_resize;
- ui->grid_clear = tui_grid_clear;
- ui->grid_cursor_goto = tui_grid_cursor_goto;
- ui->mode_info_set = tui_mode_info_set;
- ui->update_menu = tui_update_menu;
- ui->busy_start = tui_busy_start;
- ui->busy_stop = tui_busy_stop;
- ui->mouse_on = tui_mouse_on;
- ui->mouse_off = tui_mouse_off;
- ui->mode_change = tui_mode_change;
- ui->grid_scroll = tui_grid_scroll;
- ui->hl_attr_define = tui_hl_attr_define;
- ui->bell = tui_bell;
- ui->visual_bell = tui_visual_bell;
- ui->default_colors_set = tui_default_colors_set;
- ui->flush = tui_flush;
- ui->suspend = tui_suspend;
- ui->set_title = tui_set_title;
- ui->set_icon = tui_set_icon;
- ui->screenshot = tui_screenshot;
- ui->option_set = tui_option_set;
- ui->raw_line = tui_raw_line;
-
- CLEAR_FIELD(ui->ui_ext);
- ui->ui_ext[kUILinegrid] = true;
- ui->ui_ext[kUITermColors] = true;
-
- TUIData *data = xcalloc(1, sizeof(TUIData));
- ui->data = data;
- data->ui = ui;
- data->is_starting = true;
- data->screenshot = NULL;
- data->stopped = false;
- data->loop = &main_loop;
- kv_init(data->invalid_regions);
- signal_watcher_init(data->loop, &data->winch_handle, ui);
+TUIData *tui_start(int *width, int *height, char **term)
+{
+ TUIData *tui = xcalloc(1, sizeof(TUIData));
+ tui->is_starting = true;
+ tui->screenshot = NULL;
+ tui->stopped = false;
+ tui->loop = &main_loop;
+ kv_init(tui->invalid_regions);
+ signal_watcher_init(tui->loop, &tui->winch_handle, tui);
// TODO(bfredl): zero hl is empty, send this explicitly?
- kv_push(data->attrs, HLATTRS_INIT);
+ kv_push(tui->attrs, HLATTRS_INIT);
- data->input.tk_ti_hook_fn = tui_tk_ti_getstr;
- tinput_init(&data->input, &main_loop);
- ugrid_init(&data->grid);
- tui_terminal_start(ui);
+ tui->input.tk_ti_hook_fn = tui_tk_ti_getstr;
+ tinput_init(&tui->input, &main_loop);
+ ugrid_init(&tui->grid);
+ tui_terminal_start(tui);
- uv_timer_init(&data->loop->uv, &data->startup_delay_timer);
- data->startup_delay_timer.data = ui;
- uv_timer_start(&data->startup_delay_timer, after_startup_cb,
+ uv_timer_init(&tui->loop->uv, &tui->startup_delay_timer);
+ tui->startup_delay_timer.data = tui;
+ uv_timer_start(&tui->startup_delay_timer, after_startup_cb,
100, 0);
- ui_attach_impl(ui, 0);
-
- return ui;
+ loop_poll_events(&main_loop, 1);
+ *width = tui->width;
+ *height = tui->height;
+ *term = tui->term;
+ return tui;
}
-void tui_enable_extkeys(TUIData *data)
+void tui_enable_extkeys(TUIData *tui)
{
- TermInput input = data->input;
- unibi_term *ut = data->ut;
- UI *ui = data->ui;
+ TermInput input = tui->input;
+ unibi_term *ut = tui->ut;
switch (input.extkeys_type) {
case kExtkeysCSIu:
- data->unibi_ext.enable_extended_keys = (int)unibi_add_ext_str(ut, "ext.enable_extended_keys",
- "\x1b[>1u");
- data->unibi_ext.disable_extended_keys = (int)unibi_add_ext_str(ut, "ext.disable_extended_keys",
- "\x1b[<1u");
+ tui->unibi_ext.enable_extended_keys = (int)unibi_add_ext_str(ut, "ext.enable_extended_keys",
+ "\x1b[>1u");
+ tui->unibi_ext.disable_extended_keys = (int)unibi_add_ext_str(ut, "ext.disable_extended_keys",
+ "\x1b[<1u");
break;
case kExtkeysXterm:
- data->unibi_ext.enable_extended_keys = (int)unibi_add_ext_str(ut, "ext.enable_extended_keys",
- "\x1b[>4;2m");
- data->unibi_ext.disable_extended_keys = (int)unibi_add_ext_str(ut, "ext.disable_extended_keys",
- "\x1b[>4;0m");
+ tui->unibi_ext.enable_extended_keys = (int)unibi_add_ext_str(ut, "ext.enable_extended_keys",
+ "\x1b[>4;2m");
+ tui->unibi_ext.disable_extended_keys = (int)unibi_add_ext_str(ut, "ext.disable_extended_keys",
+ "\x1b[>4;0m");
break;
default:
break;
}
- unibi_out_ext(ui, data->unibi_ext.enable_extended_keys);
+ unibi_out_ext(tui, tui->unibi_ext.enable_extended_keys);
}
-static size_t unibi_pre_fmt_str(TUIData *data, unsigned int unibi_index, char *buf, size_t len)
+static size_t unibi_pre_fmt_str(TUIData *tui, unsigned int unibi_index, char *buf, size_t len)
{
- const char *str = unibi_get_str(data->ut, unibi_index);
+ const char *str = unibi_get_str(tui->ut, unibi_index);
if (!str) {
return 0U;
}
- return unibi_run(str, data->params, buf, len);
-}
-
-static void terminfo_start(UI *ui)
-{
- TUIData *data = ui->data;
- data->scroll_region_is_full_screen = true;
- data->bufpos = 0;
- data->default_attr = false;
- data->can_clear_attr = false;
- data->is_invisible = true;
- data->want_invisible = false;
- data->busy = false;
- data->cork = false;
- data->overflow = false;
- data->set_cursor_color_as_str = false;
- data->cursor_color_changed = false;
- data->showing_mode = SHAPE_IDX_N;
- data->unibi_ext.enable_mouse = -1;
- data->unibi_ext.disable_mouse = -1;
- data->unibi_ext.enable_mouse_move = -1;
- data->unibi_ext.disable_mouse_move = -1;
- data->unibi_ext.set_cursor_color = -1;
- data->unibi_ext.reset_cursor_color = -1;
- data->unibi_ext.enable_bracketed_paste = -1;
- data->unibi_ext.disable_bracketed_paste = -1;
- data->unibi_ext.enter_strikethrough_mode = -1;
- data->unibi_ext.enable_lr_margin = -1;
- data->unibi_ext.disable_lr_margin = -1;
- data->unibi_ext.enable_focus_reporting = -1;
- data->unibi_ext.disable_focus_reporting = -1;
- data->unibi_ext.resize_screen = -1;
- data->unibi_ext.reset_scroll_region = -1;
- data->unibi_ext.set_cursor_style = -1;
- data->unibi_ext.reset_cursor_style = -1;
- data->unibi_ext.get_bg = -1;
- data->unibi_ext.set_underline_color = -1;
- data->unibi_ext.enable_extended_keys = -1;
- data->unibi_ext.disable_extended_keys = -1;
- data->unibi_ext.get_extkeys = -1;
- data->out_fd = STDOUT_FILENO;
- data->out_isatty = os_isatty(data->out_fd);
- data->input.tui_data = data;
+ return unibi_run(str, tui->params, buf, len);
+}
+
+static void terminfo_start(TUIData *tui)
+{
+ tui->scroll_region_is_full_screen = true;
+ tui->bufpos = 0;
+ tui->default_attr = false;
+ tui->can_clear_attr = false;
+ tui->is_invisible = true;
+ tui->want_invisible = false;
+ tui->busy = false;
+ tui->cork = false;
+ tui->overflow = false;
+ tui->set_cursor_color_as_str = false;
+ tui->cursor_color_changed = false;
+ tui->showing_mode = SHAPE_IDX_N;
+ tui->unibi_ext.enable_mouse = -1;
+ tui->unibi_ext.disable_mouse = -1;
+ tui->unibi_ext.enable_mouse_move = -1;
+ tui->unibi_ext.disable_mouse_move = -1;
+ tui->unibi_ext.set_cursor_color = -1;
+ tui->unibi_ext.reset_cursor_color = -1;
+ tui->unibi_ext.enable_bracketed_paste = -1;
+ tui->unibi_ext.disable_bracketed_paste = -1;
+ tui->unibi_ext.enter_strikethrough_mode = -1;
+ tui->unibi_ext.enable_lr_margin = -1;
+ tui->unibi_ext.disable_lr_margin = -1;
+ tui->unibi_ext.enable_focus_reporting = -1;
+ tui->unibi_ext.disable_focus_reporting = -1;
+ tui->unibi_ext.resize_screen = -1;
+ tui->unibi_ext.reset_scroll_region = -1;
+ tui->unibi_ext.set_cursor_style = -1;
+ tui->unibi_ext.reset_cursor_style = -1;
+ tui->unibi_ext.get_bg = -1;
+ tui->unibi_ext.set_underline_color = -1;
+ tui->unibi_ext.enable_extended_keys = -1;
+ tui->unibi_ext.disable_extended_keys = -1;
+ tui->unibi_ext.get_extkeys = -1;
+ tui->out_fd = STDOUT_FILENO;
+ tui->out_isatty = os_isatty(tui->out_fd);
+ tui->input.tui_data = tui;
const char *term = os_getenv("TERM");
#ifdef MSWIN
- os_tty_guess_term(&term, data->out_fd);
+ os_tty_guess_term(&term, tui->out_fd);
os_setenv("TERM", term, 1);
// Old os_getenv() pointer is invalid after os_setenv(), fetch it again.
term = os_getenv("TERM");
@@ -311,18 +282,15 @@ static void terminfo_start(UI *ui)
// Set up unibilium/terminfo.
if (term) {
- data->ut = unibi_from_term(term);
- if (data->ut) {
- if (!ui_client_termname) {
- ui_client_termname = xstrdup(term);
- }
- if (!data->term) {
- data->term = xstrdup(term);
+ tui->ut = unibi_from_term(term);
+ if (tui->ut) {
+ if (!tui->term) {
+ tui->term = xstrdup(term);
}
}
}
- if (!data->ut) {
- data->ut = terminfo_from_builtin(term, &ui_client_termname);
+ if (!tui->ut) {
+ tui->ut = terminfo_from_builtin(term, &tui->term);
}
// None of the following work over SSH; see :help TERM .
@@ -340,59 +308,59 @@ static void terminfo_start(UI *ui)
long konsolev = konsolev_env ? strtol(konsolev_env, NULL, 10)
: (konsole ? 1 : 0);
- patch_terminfo_bugs(data, term, colorterm, vtev, konsolev, iterm_env, nsterm);
- augment_terminfo(data, term, vtev, konsolev, iterm_env, nsterm);
- data->can_change_scroll_region =
- !!unibi_get_str(data->ut, unibi_change_scroll_region);
- data->can_set_lr_margin =
- !!unibi_get_str(data->ut, unibi_set_lr_margin);
- data->can_set_left_right_margin =
- !!unibi_get_str(data->ut, unibi_set_left_margin_parm)
- && !!unibi_get_str(data->ut, unibi_set_right_margin_parm);
- data->can_scroll =
- !!unibi_get_str(data->ut, unibi_delete_line)
- && !!unibi_get_str(data->ut, unibi_parm_delete_line)
- && !!unibi_get_str(data->ut, unibi_insert_line)
- && !!unibi_get_str(data->ut, unibi_parm_insert_line);
- data->can_erase_chars = !!unibi_get_str(data->ut, unibi_erase_chars);
- data->immediate_wrap_after_last_column =
+ patch_terminfo_bugs(tui, term, colorterm, vtev, konsolev, iterm_env, nsterm);
+ augment_terminfo(tui, term, vtev, konsolev, iterm_env, nsterm);
+ tui->can_change_scroll_region =
+ !!unibi_get_str(tui->ut, unibi_change_scroll_region);
+ tui->can_set_lr_margin =
+ !!unibi_get_str(tui->ut, unibi_set_lr_margin);
+ tui->can_set_left_right_margin =
+ !!unibi_get_str(tui->ut, unibi_set_left_margin_parm)
+ && !!unibi_get_str(tui->ut, unibi_set_right_margin_parm);
+ tui->can_scroll =
+ !!unibi_get_str(tui->ut, unibi_delete_line)
+ && !!unibi_get_str(tui->ut, unibi_parm_delete_line)
+ && !!unibi_get_str(tui->ut, unibi_insert_line)
+ && !!unibi_get_str(tui->ut, unibi_parm_insert_line);
+ tui->can_erase_chars = !!unibi_get_str(tui->ut, unibi_erase_chars);
+ tui->immediate_wrap_after_last_column =
terminfo_is_term_family(term, "conemu")
|| terminfo_is_term_family(term, "cygwin")
|| terminfo_is_term_family(term, "win32con")
|| terminfo_is_term_family(term, "interix");
- data->bce = unibi_get_bool(data->ut, unibi_back_color_erase);
- data->normlen = unibi_pre_fmt_str(data, unibi_cursor_normal,
- data->norm, sizeof data->norm);
- data->invislen = unibi_pre_fmt_str(data, unibi_cursor_invisible,
- data->invis, sizeof data->invis);
+ tui->bce = unibi_get_bool(tui->ut, unibi_back_color_erase);
+ tui->normlen = unibi_pre_fmt_str(tui, unibi_cursor_normal,
+ tui->norm, sizeof tui->norm);
+ tui->invislen = unibi_pre_fmt_str(tui, unibi_cursor_invisible,
+ tui->invis, sizeof tui->invis);
// Set 't_Co' from the result of unibilium & fix_terminfo.
- t_colors = unibi_get_num(data->ut, unibi_max_colors);
+ t_colors = unibi_get_num(tui->ut, unibi_max_colors);
// Enter alternate screen, save title, and clear.
// NOTE: Do this *before* changing terminal settings. #6433
- unibi_out(ui, unibi_enter_ca_mode);
+ unibi_out(tui, unibi_enter_ca_mode);
// Save title/icon to the "stack". #4063
- unibi_out_ext(ui, data->unibi_ext.save_title);
- unibi_out(ui, unibi_keypad_xmit);
- unibi_out(ui, unibi_clear_screen);
+ unibi_out_ext(tui, tui->unibi_ext.save_title);
+ unibi_out(tui, unibi_keypad_xmit);
+ unibi_out(tui, unibi_clear_screen);
// Ask the terminal to send us the background color.
- data->input.waiting_for_bg_response = 5;
- unibi_out_ext(ui, data->unibi_ext.get_bg);
+ tui->input.waiting_for_bg_response = 5;
+ unibi_out_ext(tui, tui->unibi_ext.get_bg);
// Enable bracketed paste
- unibi_out_ext(ui, data->unibi_ext.enable_bracketed_paste);
+ unibi_out_ext(tui, tui->unibi_ext.enable_bracketed_paste);
// Query the terminal to see if it supports CSI u
- data->input.waiting_for_csiu_response = 5;
- unibi_out_ext(ui, data->unibi_ext.get_extkeys);
+ tui->input.waiting_for_csiu_response = 5;
+ unibi_out_ext(tui, tui->unibi_ext.get_extkeys);
int ret;
- uv_loop_init(&data->write_loop);
- if (data->out_isatty) {
- ret = uv_tty_init(&data->write_loop, &data->output_handle.tty, data->out_fd, 0);
+ uv_loop_init(&tui->write_loop);
+ if (tui->out_isatty) {
+ ret = uv_tty_init(&tui->write_loop, &tui->output_handle.tty, tui->out_fd, 0);
if (ret) {
ELOG("uv_tty_init failed: %s", uv_strerror(ret));
}
#ifdef MSWIN
- ret = uv_tty_set_mode(&data->output_handle.tty, UV_TTY_MODE_RAW);
+ ret = uv_tty_set_mode(&tui->output_handle.tty, UV_TTY_MODE_RAW);
if (ret) {
ELOG("uv_tty_set_mode failed: %s", uv_strerror(ret));
}
@@ -400,7 +368,7 @@ static void terminfo_start(UI *ui)
int retry_count = 10;
// A signal may cause uv_tty_set_mode() to fail (e.g., SIGCONT). Retry a
// few times. #12322
- while ((ret = uv_tty_set_mode(&data->output_handle.tty, UV_TTY_MODE_IO)) == UV_EINTR
+ while ((ret = uv_tty_set_mode(&tui->output_handle.tty, UV_TTY_MODE_IO)) == UV_EINTR
&& retry_count > 0) {
retry_count--;
}
@@ -409,145 +377,134 @@ static void terminfo_start(UI *ui)
}
#endif
} else {
- ret = uv_pipe_init(&data->write_loop, &data->output_handle.pipe, 0);
+ ret = uv_pipe_init(&tui->write_loop, &tui->output_handle.pipe, 0);
if (ret) {
ELOG("uv_pipe_init failed: %s", uv_strerror(ret));
}
- ret = uv_pipe_open(&data->output_handle.pipe, data->out_fd);
+ ret = uv_pipe_open(&tui->output_handle.pipe, tui->out_fd);
if (ret) {
ELOG("uv_pipe_open failed: %s", uv_strerror(ret));
}
}
- flush_buf(ui);
+ flush_buf(tui);
}
-static void terminfo_stop(UI *ui)
+static void terminfo_stop(TUIData *tui)
{
- TUIData *data = ui->data;
// Destroy output stuff
- tui_mode_change(ui, (String)STRING_INIT, SHAPE_IDX_N);
- tui_mouse_off(ui);
- unibi_out(ui, unibi_exit_attribute_mode);
+ tui_mode_change(tui, (String)STRING_INIT, SHAPE_IDX_N);
+ tui_mouse_off(tui);
+ unibi_out(tui, unibi_exit_attribute_mode);
// Reset cursor to normal before exiting alternate screen.
- unibi_out(ui, unibi_cursor_normal);
- unibi_out(ui, unibi_keypad_local);
+ unibi_out(tui, unibi_cursor_normal);
+ unibi_out(tui, unibi_keypad_local);
// Disable extended keys before exiting alternate screen.
- unibi_out_ext(ui, data->unibi_ext.disable_extended_keys);
- unibi_out(ui, unibi_exit_ca_mode);
+ unibi_out_ext(tui, tui->unibi_ext.disable_extended_keys);
+ unibi_out(tui, unibi_exit_ca_mode);
// Restore title/icon from the "stack". #4063
- unibi_out_ext(ui, data->unibi_ext.restore_title);
- if (data->cursor_color_changed) {
- unibi_out_ext(ui, data->unibi_ext.reset_cursor_color);
+ unibi_out_ext(tui, tui->unibi_ext.restore_title);
+ if (tui->cursor_color_changed) {
+ unibi_out_ext(tui, tui->unibi_ext.reset_cursor_color);
}
// Disable bracketed paste
- unibi_out_ext(ui, data->unibi_ext.disable_bracketed_paste);
+ unibi_out_ext(tui, tui->unibi_ext.disable_bracketed_paste);
// Disable focus reporting
- unibi_out_ext(ui, data->unibi_ext.disable_focus_reporting);
- flush_buf(ui);
+ unibi_out_ext(tui, tui->unibi_ext.disable_focus_reporting);
+ flush_buf(tui);
uv_tty_reset_mode();
- uv_close((uv_handle_t *)&data->output_handle, NULL);
- uv_run(&data->write_loop, UV_RUN_DEFAULT);
- if (uv_loop_close(&data->write_loop)) {
+ uv_close((uv_handle_t *)&tui->output_handle, NULL);
+ uv_run(&tui->write_loop, UV_RUN_DEFAULT);
+ if (uv_loop_close(&tui->write_loop)) {
abort();
}
- unibi_destroy(data->ut);
+ unibi_destroy(tui->ut);
}
-static void tui_terminal_start(UI *ui)
+static void tui_terminal_start(TUIData *tui)
{
- TUIData *data = ui->data;
- data->print_attr_id = -1;
- terminfo_start(ui);
- tui_guess_size(ui);
- signal_watcher_start(&data->winch_handle, sigwinch_cb, SIGWINCH);
- tinput_start(&data->input);
+ tui->print_attr_id = -1;
+ terminfo_start(tui);
+ tui_guess_size(tui);
+ signal_watcher_start(&tui->winch_handle, sigwinch_cb, SIGWINCH);
+ tinput_start(&tui->input);
}
static void after_startup_cb(uv_timer_t *handle)
{
- UI *ui = handle->data;
- tui_terminal_after_startup(ui);
+ TUIData *tui = handle->data;
+ tui_terminal_after_startup(tui);
}
-static void tui_terminal_after_startup(UI *ui)
+static void tui_terminal_after_startup(TUIData *tui)
FUNC_ATTR_NONNULL_ALL
{
- TUIData *data = ui->data;
-
// Emit this after Nvim startup, not during. This works around a tmux
// 2.3 bug(?) which caused slow drawing during startup. #7649
- unibi_out_ext(ui, data->unibi_ext.enable_focus_reporting);
- flush_buf(ui);
+ unibi_out_ext(tui, tui->unibi_ext.enable_focus_reporting);
+ flush_buf(tui);
}
/// stop the terminal but allow it to restart later (like after suspend)
-static void tui_terminal_stop(UI *ui)
+static void tui_terminal_stop(TUIData *tui)
{
- TUIData *data = ui->data;
- if (uv_is_closing(STRUCT_CAST(uv_handle_t, &data->output_handle))) {
+ if (uv_is_closing(STRUCT_CAST(uv_handle_t, &tui->output_handle))) {
// Race between SIGCONT (tui.c) and SIGHUP (os/signal.c)? #8075
ELOG("TUI already stopped (race?)");
- data->stopped = true;
+ tui->stopped = true;
return;
}
- tinput_stop(&data->input);
- signal_watcher_stop(&data->winch_handle);
- terminfo_stop(ui);
+ tinput_stop(&tui->input);
+ signal_watcher_stop(&tui->winch_handle);
+ terminfo_stop(tui);
}
-static void tui_stop(UI *ui)
+void tui_stop(TUIData *tui)
{
- TUIData *data = ui->data;
- tui_terminal_stop(ui);
- tinput_destroy(&data->input);
- data->stopped = true;
- signal_watcher_close(&data->winch_handle, NULL);
- uv_close((uv_handle_t *)&data->startup_delay_timer, NULL);
- ui_detach_impl(ui, 0);
+ tui_terminal_stop(tui);
+ tinput_destroy(&tui->input);
+ tui->stopped = true;
+ signal_watcher_close(&tui->winch_handle, NULL);
+ uv_close((uv_handle_t *)&tui->startup_delay_timer, NULL);
}
/// Returns true if UI `ui` is stopped.
-static bool tui_is_stopped(UI *ui)
+static bool tui_is_stopped(TUIData *tui)
{
- TUIData *data = ui->data;
- return data->stopped;
+ return tui->stopped;
}
#ifdef EXITFREE
-void tui_free_all_mem(UI *ui)
+void tui_free_all_mem(TUIData *tui)
{
- TUIData *data = ui->data;
- ugrid_free(&data->grid);
- kv_destroy(data->invalid_regions);
- kv_destroy(data->attrs);
- xfree(data->space_buf);
- xfree(data->term);
- xfree(data);
- xfree(ui);
+ ugrid_free(&tui->grid);
+ kv_destroy(tui->invalid_regions);
+ kv_destroy(tui->attrs);
+ xfree(tui->space_buf);
+ xfree(tui->term);
+ xfree(tui);
}
#endif
-static void sigwinch_cb(SignalWatcher *watcher, int signum, void *data)
+static void sigwinch_cb(SignalWatcher *watcher, int signum, void *cbdata)
{
got_winch++;
- UI *ui = data;
- if (tui_is_stopped(ui)) {
+ TUIData *tui = cbdata;
+ if (tui_is_stopped(tui)) {
return;
}
- tui_guess_size(ui);
+ tui_guess_size(tui);
}
-static bool attrs_differ(UI *ui, int id1, int id2, bool rgb)
+static bool attrs_differ(TUIData *tui, int id1, int id2, bool rgb)
{
- TUIData *data = ui->data;
if (id1 == id2) {
return false;
} else if (id1 < 0 || id2 < 0) {
return true;
}
- HlAttrs a1 = kv_A(data->attrs, (size_t)id1);
- HlAttrs a2 = kv_A(data->attrs, (size_t)id2);
+ HlAttrs a1 = kv_A(tui->attrs, (size_t)id1);
+ HlAttrs a2 = kv_A(tui->attrs, (size_t)id2);
if (rgb) {
return a1.rgb_fg_color != a2.rgb_fg_color
@@ -563,17 +520,15 @@ static bool attrs_differ(UI *ui, int id1, int id2, bool rgb)
}
}
-static void update_attrs(UI *ui, int attr_id)
+static void update_attrs(TUIData *tui, int attr_id)
{
- TUIData *data = ui->data;
-
- if (!attrs_differ(ui, attr_id, data->print_attr_id, ui->rgb)) {
- data->print_attr_id = attr_id;
+ if (!attrs_differ(tui, attr_id, tui->print_attr_id, tui->rgb)) {
+ tui->print_attr_id = attr_id;
return;
}
- data->print_attr_id = attr_id;
- HlAttrs attrs = kv_A(data->attrs, (size_t)attr_id);
- int attr = ui->rgb ? attrs.rgb_ae_attr : attrs.cterm_ae_attr;
+ tui->print_attr_id = attr_id;
+ HlAttrs attrs = kv_A(tui->attrs, (size_t)attr_id);
+ int attr = tui->rgb ? attrs.rgb_ae_attr : attrs.cterm_ae_attr;
bool bold = attr & HL_BOLD;
bool italic = attr & HL_ITALIC;
@@ -586,7 +541,7 @@ static void update_attrs(UI *ui, int attr_id)
bool underdouble;
bool underdotted;
bool underdashed;
- if (data->unibi_ext.set_underline_style != -1) {
+ if (tui->unibi_ext.set_underline_style != -1) {
underline = attr & HL_UNDERLINE;
undercurl = attr & HL_UNDERCURL;
underdouble = attr & HL_UNDERDOUBLE;
@@ -603,126 +558,125 @@ static void update_attrs(UI *ui, int attr_id)
bool has_any_underline = undercurl || underline
|| underdouble || underdotted || underdashed;
- if (unibi_get_str(data->ut, unibi_set_attributes)) {
+ if (unibi_get_str(tui->ut, unibi_set_attributes)) {
if (bold || reverse || underline || standout) {
- UNIBI_SET_NUM_VAR(data->params[0], standout);
- UNIBI_SET_NUM_VAR(data->params[1], underline);
- UNIBI_SET_NUM_VAR(data->params[2], reverse);
- UNIBI_SET_NUM_VAR(data->params[3], 0); // blink
- UNIBI_SET_NUM_VAR(data->params[4], 0); // dim
- UNIBI_SET_NUM_VAR(data->params[5], bold);
- UNIBI_SET_NUM_VAR(data->params[6], 0); // blank
- UNIBI_SET_NUM_VAR(data->params[7], 0); // protect
- UNIBI_SET_NUM_VAR(data->params[8], 0); // alternate character set
- unibi_out(ui, unibi_set_attributes);
- } else if (!data->default_attr) {
- unibi_out(ui, unibi_exit_attribute_mode);
+ UNIBI_SET_NUM_VAR(tui->params[0], standout);
+ UNIBI_SET_NUM_VAR(tui->params[1], underline);
+ UNIBI_SET_NUM_VAR(tui->params[2], reverse);
+ UNIBI_SET_NUM_VAR(tui->params[3], 0); // blink
+ UNIBI_SET_NUM_VAR(tui->params[4], 0); // dim
+ UNIBI_SET_NUM_VAR(tui->params[5], bold);
+ UNIBI_SET_NUM_VAR(tui->params[6], 0); // blank
+ UNIBI_SET_NUM_VAR(tui->params[7], 0); // protect
+ UNIBI_SET_NUM_VAR(tui->params[8], 0); // alternate character set
+ unibi_out(tui, unibi_set_attributes);
+ } else if (!tui->default_attr) {
+ unibi_out(tui, unibi_exit_attribute_mode);
}
} else {
- if (!data->default_attr) {
- unibi_out(ui, unibi_exit_attribute_mode);
+ if (!tui->default_attr) {
+ unibi_out(tui, unibi_exit_attribute_mode);
}
if (bold) {
- unibi_out(ui, unibi_enter_bold_mode);
+ unibi_out(tui, unibi_enter_bold_mode);
}
if (underline) {
- unibi_out(ui, unibi_enter_underline_mode);
+ unibi_out(tui, unibi_enter_underline_mode);
}
if (standout) {
- unibi_out(ui, unibi_enter_standout_mode);
+ unibi_out(tui, unibi_enter_standout_mode);
}
if (reverse) {
- unibi_out(ui, unibi_enter_reverse_mode);
+ unibi_out(tui, unibi_enter_reverse_mode);
}
}
if (italic) {
- unibi_out(ui, unibi_enter_italics_mode);
+ unibi_out(tui, unibi_enter_italics_mode);
}
- if (strikethrough && data->unibi_ext.enter_strikethrough_mode != -1) {
- unibi_out_ext(ui, data->unibi_ext.enter_strikethrough_mode);
+ if (strikethrough && tui->unibi_ext.enter_strikethrough_mode != -1) {
+ unibi_out_ext(tui, tui->unibi_ext.enter_strikethrough_mode);
}
- if (undercurl && data->unibi_ext.set_underline_style != -1) {
- UNIBI_SET_NUM_VAR(data->params[0], 3);
- unibi_out_ext(ui, data->unibi_ext.set_underline_style);
+ if (undercurl && tui->unibi_ext.set_underline_style != -1) {
+ UNIBI_SET_NUM_VAR(tui->params[0], 3);
+ unibi_out_ext(tui, tui->unibi_ext.set_underline_style);
}
- if (underdouble && data->unibi_ext.set_underline_style != -1) {
- UNIBI_SET_NUM_VAR(data->params[0], 2);
- unibi_out_ext(ui, data->unibi_ext.set_underline_style);
+ if (underdouble && tui->unibi_ext.set_underline_style != -1) {
+ UNIBI_SET_NUM_VAR(tui->params[0], 2);
+ unibi_out_ext(tui, tui->unibi_ext.set_underline_style);
}
- if (underdotted && data->unibi_ext.set_underline_style != -1) {
- UNIBI_SET_NUM_VAR(data->params[0], 4);
- unibi_out_ext(ui, data->unibi_ext.set_underline_style);
+ if (underdotted && tui->unibi_ext.set_underline_style != -1) {
+ UNIBI_SET_NUM_VAR(tui->params[0], 4);
+ unibi_out_ext(tui, tui->unibi_ext.set_underline_style);
}
- if (underdashed && data->unibi_ext.set_underline_style != -1) {
- UNIBI_SET_NUM_VAR(data->params[0], 5);
- unibi_out_ext(ui, data->unibi_ext.set_underline_style);
+ if (underdashed && tui->unibi_ext.set_underline_style != -1) {
+ UNIBI_SET_NUM_VAR(tui->params[0], 5);
+ unibi_out_ext(tui, tui->unibi_ext.set_underline_style);
}
- if (has_any_underline && data->unibi_ext.set_underline_color != -1) {
+ if (has_any_underline && tui->unibi_ext.set_underline_color != -1) {
int color = attrs.rgb_sp_color;
if (color != -1) {
- UNIBI_SET_NUM_VAR(data->params[0], (color >> 16) & 0xff); // red
- UNIBI_SET_NUM_VAR(data->params[1], (color >> 8) & 0xff); // green
- UNIBI_SET_NUM_VAR(data->params[2], color & 0xff); // blue
- unibi_out_ext(ui, data->unibi_ext.set_underline_color);
+ UNIBI_SET_NUM_VAR(tui->params[0], (color >> 16) & 0xff); // red
+ UNIBI_SET_NUM_VAR(tui->params[1], (color >> 8) & 0xff); // green
+ UNIBI_SET_NUM_VAR(tui->params[2], color & 0xff); // blue
+ unibi_out_ext(tui, tui->unibi_ext.set_underline_color);
}
}
int fg, bg;
- if (ui->rgb && !(attr & HL_FG_INDEXED)) {
+ if (tui->rgb && !(attr & HL_FG_INDEXED)) {
fg = ((attrs.rgb_fg_color != -1)
- ? attrs.rgb_fg_color : data->clear_attrs.rgb_fg_color);
+ ? attrs.rgb_fg_color : tui->clear_attrs.rgb_fg_color);
if (fg != -1) {
- UNIBI_SET_NUM_VAR(data->params[0], (fg >> 16) & 0xff); // red
- UNIBI_SET_NUM_VAR(data->params[1], (fg >> 8) & 0xff); // green
- UNIBI_SET_NUM_VAR(data->params[2], fg & 0xff); // blue
- unibi_out_ext(ui, data->unibi_ext.set_rgb_foreground);
+ UNIBI_SET_NUM_VAR(tui->params[0], (fg >> 16) & 0xff); // red
+ UNIBI_SET_NUM_VAR(tui->params[1], (fg >> 8) & 0xff); // green
+ UNIBI_SET_NUM_VAR(tui->params[2], fg & 0xff); // blue
+ unibi_out_ext(tui, tui->unibi_ext.set_rgb_foreground);
}
} else {
fg = (attrs.cterm_fg_color
- ? attrs.cterm_fg_color - 1 : (data->clear_attrs.cterm_fg_color - 1));
+ ? attrs.cterm_fg_color - 1 : (tui->clear_attrs.cterm_fg_color - 1));
if (fg != -1) {
- UNIBI_SET_NUM_VAR(data->params[0], fg);
- unibi_out(ui, unibi_set_a_foreground);
+ UNIBI_SET_NUM_VAR(tui->params[0], fg);
+ unibi_out(tui, unibi_set_a_foreground);
}
}
- if (ui->rgb && !(attr & HL_BG_INDEXED)) {
+ if (tui->rgb && !(attr & HL_BG_INDEXED)) {
bg = ((attrs.rgb_bg_color != -1)
- ? attrs.rgb_bg_color : data->clear_attrs.rgb_bg_color);
+ ? attrs.rgb_bg_color : tui->clear_attrs.rgb_bg_color);
if (bg != -1) {
- UNIBI_SET_NUM_VAR(data->params[0], (bg >> 16) & 0xff); // red
- UNIBI_SET_NUM_VAR(data->params[1], (bg >> 8) & 0xff); // green
- UNIBI_SET_NUM_VAR(data->params[2], bg & 0xff); // blue
- unibi_out_ext(ui, data->unibi_ext.set_rgb_background);
+ UNIBI_SET_NUM_VAR(tui->params[0], (bg >> 16) & 0xff); // red
+ UNIBI_SET_NUM_VAR(tui->params[1], (bg >> 8) & 0xff); // green
+ UNIBI_SET_NUM_VAR(tui->params[2], bg & 0xff); // blue
+ unibi_out_ext(tui, tui->unibi_ext.set_rgb_background);
}
} else {
bg = (attrs.cterm_bg_color
- ? attrs.cterm_bg_color - 1 : (data->clear_attrs.cterm_bg_color - 1));
+ ? attrs.cterm_bg_color - 1 : (tui->clear_attrs.cterm_bg_color - 1));
if (bg != -1) {
- UNIBI_SET_NUM_VAR(data->params[0], bg);
- unibi_out(ui, unibi_set_a_background);
+ UNIBI_SET_NUM_VAR(tui->params[0], bg);
+ unibi_out(tui, unibi_set_a_background);
}
}
- data->default_attr = fg == -1 && bg == -1
- && !bold && !italic && !has_any_underline && !reverse && !standout
- && !strikethrough;
+ tui->default_attr = fg == -1 && bg == -1
+ && !bold && !italic && !has_any_underline && !reverse && !standout
+ && !strikethrough;
// Non-BCE terminals can't clear with non-default background color. Some BCE
// terminals don't support attributes either, so don't rely on it. But assume
// italic and bold has no effect if there is no text.
- data->can_clear_attr = !reverse && !standout && !has_any_underline
- && !strikethrough && (data->bce || bg == -1);
+ tui->can_clear_attr = !reverse && !standout && !has_any_underline
+ && !strikethrough && (tui->bce || bg == -1);
}
-static void final_column_wrap(UI *ui)
+static void final_column_wrap(TUIData *tui)
{
- TUIData *data = ui->data;
- UGrid *grid = &data->grid;
- if (grid->row != -1 && grid->col == ui->width) {
+ UGrid *grid = &tui->grid;
+ if (grid->row != -1 && grid->col == tui->width) {
grid->col = 0;
- if (grid->row < MIN(ui->height, grid->height - 1)) {
+ if (grid->row < MIN(tui->height, grid->height - 1)) {
grid->row++;
}
}
@@ -731,33 +685,31 @@ static void final_column_wrap(UI *ui)
/// It is undocumented, but in the majority of terminals and terminal emulators
/// printing at the right margin does not cause an automatic wrap until the
/// next character is printed, holding the cursor in place until then.
-static void print_cell(UI *ui, UCell *ptr)
+static void print_cell(TUIData *tui, UCell *ptr)
{
- TUIData *data = ui->data;
- UGrid *grid = &data->grid;
- if (!data->immediate_wrap_after_last_column) {
+ UGrid *grid = &tui->grid;
+ if (!tui->immediate_wrap_after_last_column) {
// Printing the next character finally advances the cursor.
- final_column_wrap(ui);
+ final_column_wrap(tui);
}
- update_attrs(ui, ptr->attr);
- out(ui, ptr->data, strlen(ptr->data));
+ update_attrs(tui, ptr->attr);
+ out(tui, ptr->data, strlen(ptr->data));
grid->col++;
- if (data->immediate_wrap_after_last_column) {
+ if (tui->immediate_wrap_after_last_column) {
// Printing at the right margin immediately advances the cursor.
- final_column_wrap(ui);
+ final_column_wrap(tui);
}
}
-static bool cheap_to_print(UI *ui, int row, int col, int next)
+static bool cheap_to_print(TUIData *tui, int row, int col, int next)
{
- TUIData *data = ui->data;
- UGrid *grid = &data->grid;
+ UGrid *grid = &tui->grid;
UCell *cell = grid->cells[row] + col;
while (next) {
next--;
- if (attrs_differ(ui, cell->attr,
- data->print_attr_id, ui->rgb)) {
- if (data->default_attr) {
+ if (attrs_differ(tui, cell->attr,
+ tui->print_attr_id, tui->rgb)) {
+ if (tui->default_attr) {
return false;
}
}
@@ -778,15 +730,14 @@ static bool cheap_to_print(UI *ui, int row, int col, int next)
/// (ASCII 0/12) means the same thing and does not mean home. VT, CVT, and
/// TAB also stop at software-defined tabulation stops, not at a fixed set
/// of row/column positions.
-static void cursor_goto(UI *ui, int row, int col)
+static void cursor_goto(TUIData *tui, int row, int col)
{
- TUIData *data = ui->data;
- UGrid *grid = &data->grid;
+ UGrid *grid = &tui->grid;
if (row == grid->row && col == grid->col) {
return;
}
if (0 == row && 0 == col) {
- unibi_out(ui, unibi_cursor_home);
+ unibi_out(tui, unibi_cursor_home);
ugrid_goto(grid, row, col);
return;
}
@@ -795,12 +746,12 @@ static void cursor_goto(UI *ui, int row, int col)
}
if (0 == col ? col != grid->col :
row != grid->row ? false :
- 1 == col ? 2 < grid->col && cheap_to_print(ui, grid->row, 0, col) :
- 2 == col ? 5 < grid->col && cheap_to_print(ui, grid->row, 0, col) :
+ 1 == col ? 2 < grid->col && cheap_to_print(tui, grid->row, 0, col) :
+ 2 == col ? 5 < grid->col && cheap_to_print(tui, grid->row, 0, col) :
false) {
// Motion to left margin from anywhere else, or CR + printing chars is
// even less expensive than using BSes or CUB.
- unibi_out(ui, unibi_carriage_return);
+ unibi_out(tui, unibi_carriage_return);
ugrid_goto(grid, grid->row, 0);
}
if (row == grid->row) {
@@ -810,15 +761,15 @@ static void cursor_goto(UI *ui, int row, int col)
// motion calculations have OBOEs that cannot be compensated for,
// because two terminals that claim to be the same will implement
// different cursor positioning rules.
- && (data->immediate_wrap_after_last_column || grid->col < ui->width)) {
+ && (tui->immediate_wrap_after_last_column || grid->col < tui->width)) {
int n = grid->col - col;
if (n <= 4) { // This might be just BS, so it is considered really cheap.
while (n--) {
- unibi_out(ui, unibi_cursor_left);
+ unibi_out(tui, unibi_cursor_left);
}
} else {
- UNIBI_SET_NUM_VAR(data->params[0], n);
- unibi_out(ui, unibi_parm_left_cursor);
+ UNIBI_SET_NUM_VAR(tui->params[0], n);
+ unibi_out(tui, unibi_parm_left_cursor);
}
ugrid_goto(grid, row, col);
return;
@@ -826,11 +777,11 @@ static void cursor_goto(UI *ui, int row, int col)
int n = col - grid->col;
if (n <= 2) {
while (n--) {
- unibi_out(ui, unibi_cursor_right);
+ unibi_out(tui, unibi_cursor_right);
}
} else {
- UNIBI_SET_NUM_VAR(data->params[0], n);
- unibi_out(ui, unibi_parm_right_cursor);
+ UNIBI_SET_NUM_VAR(tui->params[0], n);
+ unibi_out(tui, unibi_parm_right_cursor);
}
ugrid_goto(grid, row, col);
return;
@@ -841,11 +792,11 @@ static void cursor_goto(UI *ui, int row, int col)
int n = row - grid->row;
if (n <= 4) { // This might be just LF, so it is considered really cheap.
while (n--) {
- unibi_out(ui, unibi_cursor_down);
+ unibi_out(tui, unibi_cursor_down);
}
} else {
- UNIBI_SET_NUM_VAR(data->params[0], n);
- unibi_out(ui, unibi_parm_down_cursor);
+ UNIBI_SET_NUM_VAR(tui->params[0], n);
+ unibi_out(tui, unibi_parm_down_cursor);
}
ugrid_goto(grid, row, col);
return;
@@ -853,11 +804,11 @@ static void cursor_goto(UI *ui, int row, int col)
int n = grid->row - row;
if (n <= 2) {
while (n--) {
- unibi_out(ui, unibi_cursor_up);
+ unibi_out(tui, unibi_cursor_up);
}
} else {
- UNIBI_SET_NUM_VAR(data->params[0], n);
- unibi_out(ui, unibi_parm_up_cursor);
+ UNIBI_SET_NUM_VAR(tui->params[0], n);
+ unibi_out(tui, unibi_parm_up_cursor);
}
ugrid_goto(grid, row, col);
return;
@@ -865,20 +816,19 @@ static void cursor_goto(UI *ui, int row, int col)
}
safe_move:
- unibi_goto(ui, row, col);
+ unibi_goto(tui, row, col);
ugrid_goto(grid, row, col);
}
-static void print_spaces(UI *ui, int width)
+static void print_spaces(TUIData *tui, int width)
{
- TUIData *data = ui->data;
- UGrid *grid = &data->grid;
+ UGrid *grid = &tui->grid;
- out(ui, data->space_buf, (size_t)width);
+ out(tui, tui->space_buf, (size_t)width);
grid->col += width;
- if (data->immediate_wrap_after_last_column) {
+ if (tui->immediate_wrap_after_last_column) {
// Printing at the right margin immediately advances the cursor.
- final_column_wrap(ui);
+ final_column_wrap(tui);
}
}
@@ -887,28 +837,27 @@ static void print_spaces(UI *ui, int width)
///
/// @param is_doublewidth whether the character is double-width on the grid.
/// If true and the character is ambiguous-width, clear two cells.
-static void print_cell_at_pos(UI *ui, int row, int col, UCell *cell, bool is_doublewidth)
+static void print_cell_at_pos(TUIData *tui, int row, int col, UCell *cell, bool is_doublewidth)
{
- TUIData *data = ui->data;
- UGrid *grid = &data->grid;
+ UGrid *grid = &tui->grid;
if (grid->row == -1 && cell->data[0] == NUL) {
// If cursor needs to repositioned and there is nothing to print, don't move cursor.
return;
}
- cursor_goto(ui, row, col);
+ cursor_goto(tui, row, col);
bool is_ambiwidth = utf_ambiguous_width(utf_ptr2char(cell->data));
if (is_ambiwidth && is_doublewidth) {
// Clear the two screen cells.
// If the character is single-width in the host terminal it won't change the second cell.
- update_attrs(ui, cell->attr);
- print_spaces(ui, 2);
- cursor_goto(ui, row, col);
+ update_attrs(tui, cell->attr);
+ print_spaces(tui, 2);
+ cursor_goto(tui, row, col);
}
- print_cell(ui, cell);
+ print_cell(tui, cell);
if (is_ambiwidth) {
// Force repositioning cursor after printing an ambiguous-width character.
@@ -916,120 +865,116 @@ static void print_cell_at_pos(UI *ui, int row, int col, UCell *cell, bool is_dou
}
}
-static void clear_region(UI *ui, int top, int bot, int left, int right, int attr_id)
+static void clear_region(TUIData *tui, int top, int bot, int left, int right, int attr_id)
{
- TUIData *data = ui->data;
- UGrid *grid = &data->grid;
+ UGrid *grid = &tui->grid;
- update_attrs(ui, attr_id);
+ update_attrs(tui, attr_id);
// Background is set to the default color and the right edge matches the
// screen end, try to use terminal codes for clearing the requested area.
- if (data->can_clear_attr
- && left == 0 && right == ui->width && bot == ui->height) {
+ if (tui->can_clear_attr
+ && left == 0 && right == tui->width && bot == tui->height) {
if (top == 0) {
- unibi_out(ui, unibi_clear_screen);
+ unibi_out(tui, unibi_clear_screen);
ugrid_goto(grid, top, left);
} else {
- cursor_goto(ui, top, 0);
- unibi_out(ui, unibi_clr_eos);
+ cursor_goto(tui, top, 0);
+ unibi_out(tui, unibi_clr_eos);
}
} else {
int width = right - left;
// iterate through each line and clear
for (int row = top; row < bot; row++) {
- cursor_goto(ui, row, left);
- if (data->can_clear_attr && right == ui->width) {
- unibi_out(ui, unibi_clr_eol);
- } else if (data->can_erase_chars && data->can_clear_attr && width >= 5) {
- UNIBI_SET_NUM_VAR(data->params[0], width);
- unibi_out(ui, unibi_erase_chars);
+ cursor_goto(tui, row, left);
+ if (tui->can_clear_attr && right == tui->width) {
+ unibi_out(tui, unibi_clr_eol);
+ } else if (tui->can_erase_chars && tui->can_clear_attr && width >= 5) {
+ UNIBI_SET_NUM_VAR(tui->params[0], width);
+ unibi_out(tui, unibi_erase_chars);
} else {
- print_spaces(ui, width);
+ print_spaces(tui, width);
}
}
}
}
-static void set_scroll_region(UI *ui, int top, int bot, int left, int right)
+static void set_scroll_region(TUIData *tui, int top, int bot, int left, int right)
{
- TUIData *data = ui->data;
- UGrid *grid = &data->grid;
+ UGrid *grid = &tui->grid;
- UNIBI_SET_NUM_VAR(data->params[0], top);
- UNIBI_SET_NUM_VAR(data->params[1], bot);
- unibi_out(ui, unibi_change_scroll_region);
- if (left != 0 || right != ui->width - 1) {
- unibi_out_ext(ui, data->unibi_ext.enable_lr_margin);
- if (data->can_set_lr_margin) {
- UNIBI_SET_NUM_VAR(data->params[0], left);
- UNIBI_SET_NUM_VAR(data->params[1], right);
- unibi_out(ui, unibi_set_lr_margin);
+ UNIBI_SET_NUM_VAR(tui->params[0], top);
+ UNIBI_SET_NUM_VAR(tui->params[1], bot);
+ unibi_out(tui, unibi_change_scroll_region);
+ if (left != 0 || right != tui->width - 1) {
+ unibi_out_ext(tui, tui->unibi_ext.enable_lr_margin);
+ if (tui->can_set_lr_margin) {
+ UNIBI_SET_NUM_VAR(tui->params[0], left);
+ UNIBI_SET_NUM_VAR(tui->params[1], right);
+ unibi_out(tui, unibi_set_lr_margin);
} else {
- UNIBI_SET_NUM_VAR(data->params[0], left);
- unibi_out(ui, unibi_set_left_margin_parm);
- UNIBI_SET_NUM_VAR(data->params[0], right);
- unibi_out(ui, unibi_set_right_margin_parm);
+ UNIBI_SET_NUM_VAR(tui->params[0], left);
+ unibi_out(tui, unibi_set_left_margin_parm);
+ UNIBI_SET_NUM_VAR(tui->params[0], right);
+ unibi_out(tui, unibi_set_right_margin_parm);
}
}
grid->row = -1;
}
-static void reset_scroll_region(UI *ui, bool fullwidth)
+static void reset_scroll_region(TUIData *tui, bool fullwidth)
{
- TUIData *data = ui->data;
- UGrid *grid = &data->grid;
+ UGrid *grid = &tui->grid;
- if (0 <= data->unibi_ext.reset_scroll_region) {
- unibi_out_ext(ui, data->unibi_ext.reset_scroll_region);
+ if (0 <= tui->unibi_ext.reset_scroll_region) {
+ unibi_out_ext(tui, tui->unibi_ext.reset_scroll_region);
} else {
- UNIBI_SET_NUM_VAR(data->params[0], 0);
- UNIBI_SET_NUM_VAR(data->params[1], ui->height - 1);
- unibi_out(ui, unibi_change_scroll_region);
+ UNIBI_SET_NUM_VAR(tui->params[0], 0);
+ UNIBI_SET_NUM_VAR(tui->params[1], tui->height - 1);
+ unibi_out(tui, unibi_change_scroll_region);
}
if (!fullwidth) {
- if (data->can_set_lr_margin) {
- UNIBI_SET_NUM_VAR(data->params[0], 0);
- UNIBI_SET_NUM_VAR(data->params[1], ui->width - 1);
- unibi_out(ui, unibi_set_lr_margin);
+ if (tui->can_set_lr_margin) {
+ UNIBI_SET_NUM_VAR(tui->params[0], 0);
+ UNIBI_SET_NUM_VAR(tui->params[1], tui->width - 1);
+ unibi_out(tui, unibi_set_lr_margin);
} else {
- UNIBI_SET_NUM_VAR(data->params[0], 0);
- unibi_out(ui, unibi_set_left_margin_parm);
- UNIBI_SET_NUM_VAR(data->params[0], ui->width - 1);
- unibi_out(ui, unibi_set_right_margin_parm);
+ UNIBI_SET_NUM_VAR(tui->params[0], 0);
+ unibi_out(tui, unibi_set_left_margin_parm);
+ UNIBI_SET_NUM_VAR(tui->params[0], tui->width - 1);
+ unibi_out(tui, unibi_set_right_margin_parm);
}
- unibi_out_ext(ui, data->unibi_ext.disable_lr_margin);
+ unibi_out_ext(tui, tui->unibi_ext.disable_lr_margin);
}
grid->row = -1;
}
-static void tui_grid_resize(UI *ui, Integer g, Integer width, Integer height)
+void tui_grid_resize(TUIData *tui, Integer g, Integer width, Integer height)
{
- TUIData *data = ui->data;
- UGrid *grid = &data->grid;
+ UGrid *grid = &tui->grid;
ugrid_resize(grid, (int)width, (int)height);
- xfree(data->space_buf);
- data->space_buf = xmalloc((size_t)width * sizeof(*data->space_buf));
- memset(data->space_buf, ' ', (size_t)width);
+ xfree(tui->space_buf);
+ tui->space_buf = xmalloc((size_t)width * sizeof(*tui->space_buf));
+ memset(tui->space_buf, ' ', (size_t)width);
// resize might not always be followed by a clear before flush
// so clip the invalid region
- for (size_t i = 0; i < kv_size(data->invalid_regions); i++) {
- Rect *r = &kv_A(data->invalid_regions, i);
+ for (size_t i = 0; i < kv_size(tui->invalid_regions); i++) {
+ Rect *r = &kv_A(tui->invalid_regions, i);
r->bot = MIN(r->bot, grid->height);
r->right = MIN(r->right, grid->width);
}
- if (!got_winch && !data->is_starting) {
+ if (!got_winch && !tui->is_starting) {
// Resize the _host_ terminal.
- UNIBI_SET_NUM_VAR(data->params[0], (int)height);
- UNIBI_SET_NUM_VAR(data->params[1], (int)width);
- unibi_out_ext(ui, data->unibi_ext.resize_screen);
+ UNIBI_SET_NUM_VAR(tui->params[0], (int)height);
+ UNIBI_SET_NUM_VAR(tui->params[1], (int)width);
+ unibi_out_ext(tui, tui->unibi_ext.resize_screen);
// DECSLPP does not reset the scroll region.
- if (data->scroll_region_is_full_screen) {
- reset_scroll_region(ui, ui->width == grid->width);
+ if (tui->scroll_region_is_full_screen) {
+ reset_scroll_region(tui, tui->width == grid->width);
}
} else { // Already handled the SIGWINCH signal; avoid double-resize.
got_winch = got_winch > 0 ? got_winch - 1 : 0;
@@ -1037,22 +982,19 @@ static void tui_grid_resize(UI *ui, Integer g, Integer width, Integer height)
}
}
-static void tui_grid_clear(UI *ui, Integer g)
+void tui_grid_clear(TUIData *tui, Integer g)
{
- TUIData *data = ui->data;
- UGrid *grid = &data->grid;
+ UGrid *grid = &tui->grid;
ugrid_clear(grid);
- kv_size(data->invalid_regions) = 0;
- clear_region(ui, 0, grid->height, 0, grid->width, 0);
+ kv_size(tui->invalid_regions) = 0;
+ clear_region(tui, 0, grid->height, 0, grid->width, 0);
}
-static void tui_grid_cursor_goto(UI *ui, Integer grid, Integer row, Integer col)
+void tui_grid_cursor_goto(TUIData *tui, Integer grid, Integer row, Integer col)
{
- TUIData *data = ui->data;
-
// cursor position is validated in tui_flush
- data->row = (int)row;
- data->col = (int)col;
+ tui->row = (int)row;
+ tui->col = (int)col;
}
CursorShape tui_cursor_decode_shape(const char *shape_str)
@@ -1092,13 +1034,12 @@ static cursorentry_T decode_cursor_entry(Dictionary args)
return r;
}
-static void tui_mode_info_set(UI *ui, bool guicursor_enabled, Array args)
+void tui_mode_info_set(TUIData *tui, bool guicursor_enabled, Array args)
{
cursor_style_enabled = guicursor_enabled;
if (!guicursor_enabled) {
return; // Do not send cursor style control codes.
}
- TUIData *data = ui->data;
assert(args.size);
@@ -1106,84 +1047,81 @@ static void tui_mode_info_set(UI *ui, bool guicursor_enabled, Array args)
for (size_t i = 0; i < args.size; i++) {
assert(args.items[i].type == kObjectTypeDictionary);
cursorentry_T r = decode_cursor_entry(args.items[i].data.dictionary);
- data->cursor_shapes[i] = r;
+ tui->cursor_shapes[i] = r;
}
- tui_set_mode(ui, data->showing_mode);
+ tui_set_mode(tui, tui->showing_mode);
}
-static void tui_update_menu(UI *ui)
+void tui_update_menu(TUIData *tui)
{
// Do nothing; menus are for GUI only
}
-static void tui_busy_start(UI *ui)
+void tui_busy_start(TUIData *tui)
{
- ((TUIData *)ui->data)->busy = true;
+ tui->busy = true;
}
-static void tui_busy_stop(UI *ui)
+void tui_busy_stop(TUIData *tui)
{
- ((TUIData *)ui->data)->busy = false;
+ tui->busy = false;
}
-static void tui_mouse_on(UI *ui)
+void tui_mouse_on(TUIData *tui)
{
- TUIData *data = ui->data;
- if (!data->mouse_enabled) {
- unibi_out_ext(ui, data->unibi_ext.enable_mouse);
- if (data->mouse_move_enabled) {
- unibi_out_ext(ui, data->unibi_ext.enable_mouse_move);
+ if (!tui->mouse_enabled) {
+ unibi_out_ext(tui, tui->unibi_ext.enable_mouse);
+ if (tui->mouse_move_enabled) {
+ unibi_out_ext(tui, tui->unibi_ext.enable_mouse_move);
}
- data->mouse_enabled = true;
+ tui->mouse_enabled = true;
}
}
-static void tui_mouse_off(UI *ui)
+void tui_mouse_off(TUIData *tui)
{
- TUIData *data = ui->data;
- if (data->mouse_enabled) {
- if (data->mouse_move_enabled) {
- unibi_out_ext(ui, data->unibi_ext.disable_mouse_move);
+ if (tui->mouse_enabled) {
+ if (tui->mouse_move_enabled) {
+ unibi_out_ext(tui, tui->unibi_ext.disable_mouse_move);
}
- unibi_out_ext(ui, data->unibi_ext.disable_mouse);
- data->mouse_enabled = false;
+ unibi_out_ext(tui, tui->unibi_ext.disable_mouse);
+ tui->mouse_enabled = false;
}
}
-static void tui_set_mode(UI *ui, ModeShape mode)
+void tui_set_mode(TUIData *tui, ModeShape mode)
{
if (!cursor_style_enabled) {
return;
}
- TUIData *data = ui->data;
- cursorentry_T c = data->cursor_shapes[mode];
+ cursorentry_T c = tui->cursor_shapes[mode];
- if (c.id != 0 && c.id < (int)kv_size(data->attrs) && ui->rgb) {
- HlAttrs aep = kv_A(data->attrs, c.id);
+ if (c.id != 0 && c.id < (int)kv_size(tui->attrs) && tui->rgb) {
+ HlAttrs aep = kv_A(tui->attrs, c.id);
- data->want_invisible = aep.hl_blend == 100;
- if (data->want_invisible) {
- unibi_out(ui, unibi_cursor_invisible);
+ tui->want_invisible = aep.hl_blend == 100;
+ if (tui->want_invisible) {
+ unibi_out(tui, unibi_cursor_invisible);
} else if (aep.rgb_ae_attr & HL_INVERSE) {
// We interpret "inverse" as "default" (no termcode for "inverse"...).
// Hopefully the user's default cursor color is inverse.
- unibi_out_ext(ui, data->unibi_ext.reset_cursor_color);
+ unibi_out_ext(tui, tui->unibi_ext.reset_cursor_color);
} else {
- if (data->set_cursor_color_as_str) {
+ if (tui->set_cursor_color_as_str) {
char hexbuf[8];
snprintf(hexbuf, 7 + 1, "#%06x", aep.rgb_bg_color);
- UNIBI_SET_STR_VAR(data->params[0], hexbuf);
+ UNIBI_SET_STR_VAR(tui->params[0], hexbuf);
} else {
- UNIBI_SET_NUM_VAR(data->params[0], aep.rgb_bg_color);
+ UNIBI_SET_NUM_VAR(tui->params[0], aep.rgb_bg_color);
}
- unibi_out_ext(ui, data->unibi_ext.set_cursor_color);
- data->cursor_color_changed = true;
+ unibi_out_ext(tui, tui->unibi_ext.set_cursor_color);
+ tui->cursor_color_changed = true;
}
} else if (c.id == 0) {
// No cursor color for this mode; reset to default.
- data->want_invisible = false;
- unibi_out_ext(ui, data->unibi_ext.reset_cursor_color);
+ tui->want_invisible = false;
+ unibi_out_ext(tui, tui->unibi_ext.reset_cursor_color);
}
int shape;
@@ -1197,88 +1135,86 @@ static void tui_set_mode(UI *ui, ModeShape mode)
case SHAPE_VER:
shape = 5; break;
}
- UNIBI_SET_NUM_VAR(data->params[0], shape + (int)(c.blinkon == 0));
- unibi_out_ext(ui, data->unibi_ext.set_cursor_style);
+ UNIBI_SET_NUM_VAR(tui->params[0], shape + (int)(c.blinkon == 0));
+ unibi_out_ext(tui, tui->unibi_ext.set_cursor_style);
}
/// @param mode editor mode
-static void tui_mode_change(UI *ui, String mode, Integer mode_idx)
+void tui_mode_change(TUIData *tui, String mode, Integer mode_idx)
{
- TUIData *data = ui->data;
#ifdef UNIX
// If stdin is not a TTY, the LHS of pipe may change the state of the TTY
// after calling uv_tty_set_mode. So, set the mode of the TTY again here.
// #13073
- if (data->is_starting && data->input.in_fd == STDERR_FILENO) {
- int ret = uv_tty_set_mode(&data->output_handle.tty, UV_TTY_MODE_NORMAL);
+ if (tui->is_starting && tui->input.in_fd == STDERR_FILENO) {
+ int ret = uv_tty_set_mode(&tui->output_handle.tty, UV_TTY_MODE_NORMAL);
if (ret) {
ELOG("uv_tty_set_mode failed: %s", uv_strerror(ret));
}
- ret = uv_tty_set_mode(&data->output_handle.tty, UV_TTY_MODE_IO);
+ ret = uv_tty_set_mode(&tui->output_handle.tty, UV_TTY_MODE_IO);
if (ret) {
ELOG("uv_tty_set_mode failed: %s", uv_strerror(ret));
}
}
#endif
- tui_set_mode(ui, (ModeShape)mode_idx);
- if (data->is_starting) {
- if (data->verbose >= 3) {
- show_verbose_terminfo(data);
+ tui_set_mode(tui, (ModeShape)mode_idx);
+ if (tui->is_starting) {
+ if (tui->verbose >= 3) {
+ show_verbose_terminfo(tui);
}
}
- data->is_starting = false; // mode entered, no longer starting
- data->showing_mode = (ModeShape)mode_idx;
+ tui->is_starting = false; // mode entered, no longer starting
+ tui->showing_mode = (ModeShape)mode_idx;
}
-static void tui_grid_scroll(UI *ui, Integer g, Integer startrow, // -V751
- Integer endrow, Integer startcol, Integer endcol, Integer rows,
- Integer cols FUNC_ATTR_UNUSED)
+void tui_grid_scroll(TUIData *tui, Integer g, Integer startrow, // -V751
+ Integer endrow, Integer startcol, Integer endcol, Integer rows,
+ Integer cols FUNC_ATTR_UNUSED)
{
- TUIData *data = ui->data;
- UGrid *grid = &data->grid;
+ UGrid *grid = &tui->grid;
int top = (int)startrow, bot = (int)endrow - 1;
int left = (int)startcol, right = (int)endcol - 1;
- bool fullwidth = left == 0 && right == ui->width - 1;
- data->scroll_region_is_full_screen = fullwidth
- && top == 0 && bot == ui->height - 1;
+ bool fullwidth = left == 0 && right == tui->width - 1;
+ tui->scroll_region_is_full_screen = fullwidth
+ && top == 0 && bot == tui->height - 1;
ugrid_scroll(grid, top, bot, left, right, (int)rows);
- bool can_scroll = data->can_scroll
- && (data->scroll_region_is_full_screen
- || (data->can_change_scroll_region
- && ((left == 0 && right == ui->width - 1)
- || data->can_set_lr_margin
- || data->can_set_left_right_margin)));
+ bool can_scroll = tui->can_scroll
+ && (tui->scroll_region_is_full_screen
+ || (tui->can_change_scroll_region
+ && ((left == 0 && right == tui->width - 1)
+ || tui->can_set_lr_margin
+ || tui->can_set_left_right_margin)));
if (can_scroll) {
// Change terminal scroll region and move cursor to the top
- if (!data->scroll_region_is_full_screen) {
- set_scroll_region(ui, top, bot, left, right);
+ if (!tui->scroll_region_is_full_screen) {
+ set_scroll_region(tui, top, bot, left, right);
}
- cursor_goto(ui, top, left);
- update_attrs(ui, 0);
+ cursor_goto(tui, top, left);
+ update_attrs(tui, 0);
if (rows > 0) {
if (rows == 1) {
- unibi_out(ui, unibi_delete_line);
+ unibi_out(tui, unibi_delete_line);
} else {
- UNIBI_SET_NUM_VAR(data->params[0], (int)rows);
- unibi_out(ui, unibi_parm_delete_line);
+ UNIBI_SET_NUM_VAR(tui->params[0], (int)rows);
+ unibi_out(tui, unibi_parm_delete_line);
}
} else {
if (rows == -1) {
- unibi_out(ui, unibi_insert_line);
+ unibi_out(tui, unibi_insert_line);
} else {
- UNIBI_SET_NUM_VAR(data->params[0], -(int)rows);
- unibi_out(ui, unibi_parm_insert_line);
+ UNIBI_SET_NUM_VAR(tui->params[0], -(int)rows);
+ unibi_out(tui, unibi_parm_insert_line);
}
}
// Restore terminal scroll region and cursor
- if (!data->scroll_region_is_full_screen) {
- reset_scroll_region(ui, fullwidth);
+ if (!tui->scroll_region_is_full_screen) {
+ reset_scroll_region(tui, fullwidth);
}
} else {
// Mark the moved region as invalid for redrawing later
@@ -1287,50 +1223,46 @@ static void tui_grid_scroll(UI *ui, Integer g, Integer startrow, // -V751
} else {
startrow = startrow - rows;
}
- invalidate(ui, (int)startrow, (int)endrow, (int)startcol, (int)endcol);
+ invalidate(tui, (int)startrow, (int)endrow, (int)startcol, (int)endcol);
}
}
-static void tui_hl_attr_define(UI *ui, Integer id, HlAttrs attrs, HlAttrs cterm_attrs, Array info)
+void tui_hl_attr_define(TUIData *tui, Integer id, HlAttrs attrs, HlAttrs cterm_attrs, Array info)
{
- TUIData *data = ui->data;
attrs.cterm_ae_attr = cterm_attrs.cterm_ae_attr;
attrs.cterm_fg_color = cterm_attrs.cterm_fg_color;
attrs.cterm_bg_color = cterm_attrs.cterm_bg_color;
- kv_a(data->attrs, (size_t)id) = attrs;
+ kv_a(tui->attrs, (size_t)id) = attrs;
}
-static void tui_bell(UI *ui)
+void tui_bell(TUIData *tui)
{
- unibi_out(ui, unibi_bell);
+ unibi_out(tui, unibi_bell);
}
-static void tui_visual_bell(UI *ui)
+void tui_visual_bell(TUIData *tui)
{
- unibi_out(ui, unibi_flash_screen);
+ unibi_out(tui, unibi_flash_screen);
}
-static void tui_default_colors_set(UI *ui, Integer rgb_fg, Integer rgb_bg, Integer rgb_sp,
- Integer cterm_fg, Integer cterm_bg)
+void tui_default_colors_set(TUIData *tui, Integer rgb_fg, Integer rgb_bg, Integer rgb_sp,
+ Integer cterm_fg, Integer cterm_bg)
{
- TUIData *data = ui->data;
+ tui->clear_attrs.rgb_fg_color = (int)rgb_fg;
+ tui->clear_attrs.rgb_bg_color = (int)rgb_bg;
+ tui->clear_attrs.rgb_sp_color = (int)rgb_sp;
+ tui->clear_attrs.cterm_fg_color = (int)cterm_fg;
+ tui->clear_attrs.cterm_bg_color = (int)cterm_bg;
- data->clear_attrs.rgb_fg_color = (int)rgb_fg;
- data->clear_attrs.rgb_bg_color = (int)rgb_bg;
- data->clear_attrs.rgb_sp_color = (int)rgb_sp;
- data->clear_attrs.cterm_fg_color = (int)cterm_fg;
- data->clear_attrs.cterm_bg_color = (int)cterm_bg;
-
- data->print_attr_id = -1;
- invalidate(ui, 0, data->grid.height, 0, data->grid.width);
+ tui->print_attr_id = -1;
+ invalidate(tui, 0, tui->grid.height, 0, tui->grid.width);
}
-static void tui_flush(UI *ui)
+void tui_flush(TUIData *tui)
{
- TUIData *data = ui->data;
- UGrid *grid = &data->grid;
+ UGrid *grid = &tui->grid;
- size_t nrevents = loop_size(data->loop);
+ size_t nrevents = loop_size(tui->loop);
if (nrevents > TOO_MANY_EVENTS) {
WLOG("TUI event-queue flooded (thread_events=%zu); purging", nrevents);
// Back-pressure: UI events may accumulate much faster than the terminal
@@ -1338,12 +1270,12 @@ static void tui_flush(UI *ui)
// wait for the TUI event-queue to drain, and if there are ~millions of
// events in the queue, it could take hours. Clearing the queue allows the
// UI to recover. #1234 #5396
- loop_purge(data->loop);
- tui_busy_stop(ui); // avoid hidden cursor
+ loop_purge(tui->loop);
+ tui_busy_stop(tui); // avoid hidden cursor
}
- while (kv_size(data->invalid_regions)) {
- Rect r = kv_pop(data->invalid_regions);
+ while (kv_size(tui->invalid_regions)) {
+ Rect r = kv_pop(tui->invalid_regions);
assert(r.bot <= grid->height && r.right <= grid->width);
for (int row = r.top; row < r.bot; row++) {
@@ -1358,24 +1290,24 @@ static void tui_flush(UI *ui)
}
UGRID_FOREACH_CELL(grid, row, r.left, clear_col, {
- print_cell_at_pos(ui, row, curcol, cell,
+ print_cell_at_pos(tui, row, curcol, cell,
curcol < clear_col - 1 && (cell + 1)->data[0] == NUL);
});
if (clear_col < r.right) {
- clear_region(ui, row, row + 1, clear_col, r.right, clear_attr);
+ clear_region(tui, row, row + 1, clear_col, r.right, clear_attr);
}
}
}
- cursor_goto(ui, data->row, data->col);
+ cursor_goto(tui, tui->row, tui->col);
- flush_buf(ui);
+ flush_buf(tui);
}
/// Dumps termcap info to the messages area, if 'verbose' >= 3.
-static void show_verbose_terminfo(TUIData *data)
+static void show_verbose_terminfo(TUIData *tui)
{
- const unibi_term *const ut = data->ut;
+ const unibi_term *const ut = tui->ut;
if (!ut) {
abort();
}
@@ -1386,7 +1318,7 @@ static void show_verbose_terminfo(TUIData *data)
ADD(title, STRING_OBJ(cstr_to_string("Title")));
ADD(chunks, ARRAY_OBJ(title));
Array info = ARRAY_DICT_INIT;
- String str = terminfo_info_msg(ut, data->term);
+ String str = terminfo_info_msg(ut, tui->term);
ADD(info, STRING_OBJ(str));
ADD(chunks, ARRAY_OBJ(info));
Array end_fold = ARRAY_DICT_INIT;
@@ -1407,24 +1339,23 @@ static void show_verbose_terminfo(TUIData *data)
#ifdef UNIX
static void suspend_event(void **argv)
{
- UI *ui = argv[0];
- TUIData *data = ui->data;
- bool enable_mouse = data->mouse_enabled;
- tui_terminal_stop(ui);
+ TUIData *tui = argv[0];
+ bool enable_mouse = tui->mouse_enabled;
+ tui_terminal_stop(tui);
stream_set_blocking(input_global_fd(), true); // normalize stream (#2598)
kill(0, SIGTSTP);
- tui_terminal_start(ui);
- tui_terminal_after_startup(ui);
+ tui_terminal_start(tui);
+ tui_terminal_after_startup(tui);
if (enable_mouse) {
- tui_mouse_on(ui);
+ tui_mouse_on(tui);
}
stream_set_blocking(input_global_fd(), false); // libuv expects this
}
#endif
-static void tui_suspend(UI *ui)
+void tui_suspend(TUIData *tui)
{
// on a non-UNIX system, this is a no-op
#ifdef UNIX
@@ -1432,66 +1363,63 @@ static void tui_suspend(UI *ui)
// before continuing. This is done in another callback to avoid
// loop_poll_events recursion
multiqueue_put_event(resize_events,
- event_create(suspend_event, 1, ui));
+ event_create(suspend_event, 1, tui));
#endif
}
-static void tui_set_title(UI *ui, String title)
+void tui_set_title(TUIData *tui, String title)
{
- TUIData *data = ui->data;
- if (!(title.data && unibi_get_str(data->ut, unibi_to_status_line)
- && unibi_get_str(data->ut, unibi_from_status_line))) {
+ if (!(title.data && unibi_get_str(tui->ut, unibi_to_status_line)
+ && unibi_get_str(tui->ut, unibi_from_status_line))) {
return;
}
- unibi_out(ui, unibi_to_status_line);
- out(ui, title.data, title.size);
- unibi_out(ui, unibi_from_status_line);
+ unibi_out(tui, unibi_to_status_line);
+ out(tui, title.data, title.size);
+ unibi_out(tui, unibi_from_status_line);
}
-static void tui_set_icon(UI *ui, String icon)
+void tui_set_icon(TUIData *tui, String icon)
{}
-static void tui_screenshot(UI *ui, String path)
+void tui_screenshot(TUIData *tui, String path)
{
- TUIData *data = ui->data;
- UGrid *grid = &data->grid;
- flush_buf(ui);
+ UGrid *grid = &tui->grid;
+ flush_buf(tui);
grid->row = 0;
grid->col = 0;
FILE *f = fopen(path.data, "w");
- data->screenshot = f;
+ tui->screenshot = f;
fprintf(f, "%d,%d\n", grid->height, grid->width);
- unibi_out(ui, unibi_clear_screen);
+ unibi_out(tui, unibi_clear_screen);
for (int i = 0; i < grid->height; i++) {
- cursor_goto(ui, i, 0);
+ cursor_goto(tui, i, 0);
for (int j = 0; j < grid->width; j++) {
- print_cell(ui, &grid->cells[i][j]);
+ print_cell(tui, &grid->cells[i][j]);
}
}
- flush_buf(ui);
- data->screenshot = NULL;
+ flush_buf(tui);
+ tui->screenshot = NULL;
fclose(f);
}
-static void tui_option_set(UI *ui, String name, Object value)
+void tui_option_set(TUIData *tui, String name, Object value)
{
- TUIData *data = ui->data;
if (strequal(name.data, "mousemoveevent")) {
- if (data->mouse_move_enabled != value.data.boolean) {
- if (data->mouse_enabled) {
- tui_mouse_off(ui);
- data->mouse_move_enabled = value.data.boolean;
- tui_mouse_on(ui);
+ if (tui->mouse_move_enabled != value.data.boolean) {
+ if (tui->mouse_enabled) {
+ tui_mouse_off(tui);
+ tui->mouse_move_enabled = value.data.boolean;
+ tui_mouse_on(tui);
} else {
- data->mouse_move_enabled = value.data.boolean;
+ tui->mouse_move_enabled = value.data.boolean;
}
}
} else if (strequal(name.data, "termguicolors")) {
- ui->rgb = value.data.boolean;
- data->print_attr_id = -1;
- invalidate(ui, 0, data->grid.height, 0, data->grid.width);
+ tui->rgb = value.data.boolean;
+ tui->print_attr_id = -1;
+ invalidate(tui, 0, tui->grid.height, 0, tui->grid.width);
if (ui_client_channel_id) {
MAXSIZE_TEMP_ARRAY(args, 2);
@@ -1500,38 +1428,37 @@ static void tui_option_set(UI *ui, String name, Object value)
rpc_send_event(ui_client_channel_id, "nvim_ui_set_option", args);
}
} else if (strequal(name.data, "ttimeout")) {
- data->input.ttimeout = value.data.boolean;
+ tui->input.ttimeout = value.data.boolean;
} else if (strequal(name.data, "ttimeoutlen")) {
- data->input.ttimeoutlen = (long)value.data.integer;
+ tui->input.ttimeoutlen = (long)value.data.integer;
} else if (strequal(name.data, "verbose")) {
- data->verbose = value.data.integer;
+ tui->verbose = value.data.integer;
}
}
-static void tui_raw_line(UI *ui, Integer g, Integer linerow, Integer startcol, Integer endcol,
- Integer clearcol, Integer clearattr, LineFlags flags, const schar_T *chunk,
- const sattr_T *attrs)
+void tui_raw_line(TUIData *tui, Integer g, Integer linerow, Integer startcol, Integer endcol,
+ Integer clearcol, Integer clearattr, LineFlags flags, const schar_T *chunk,
+ const sattr_T *attrs)
{
- TUIData *data = ui->data;
- UGrid *grid = &data->grid;
+ UGrid *grid = &tui->grid;
for (Integer c = startcol; c < endcol; c++) {
memcpy(grid->cells[linerow][c].data, chunk[c - startcol], sizeof(schar_T));
- assert((size_t)attrs[c - startcol] < kv_size(data->attrs));
+ assert((size_t)attrs[c - startcol] < kv_size(tui->attrs));
grid->cells[linerow][c].attr = attrs[c - startcol];
}
UGRID_FOREACH_CELL(grid, (int)linerow, (int)startcol, (int)endcol, {
- print_cell_at_pos(ui, (int)linerow, curcol, cell,
+ print_cell_at_pos(tui, (int)linerow, curcol, cell,
curcol < endcol - 1 && (cell + 1)->data[0] == NUL);
});
if (clearcol > endcol) {
ugrid_clear_chunk(grid, (int)linerow, (int)endcol, (int)clearcol,
(sattr_T)clearattr);
- clear_region(ui, (int)linerow, (int)linerow + 1, (int)endcol, (int)clearcol,
+ clear_region(tui, (int)linerow, (int)linerow + 1, (int)endcol, (int)clearcol,
(int)clearattr);
}
- if (flags & kLineFlagWrap && ui->width == grid->width
+ if (flags & kLineFlagWrap && tui->width == grid->width
&& linerow + 1 < grid->height) {
// Only do line wrapping if the grid width is equal to the terminal
// width and the line continuation is within the grid.
@@ -1539,23 +1466,22 @@ static void tui_raw_line(UI *ui, Integer g, Integer linerow, Integer startcol, I
if (endcol != grid->width) {
// Print the last char of the row, if we haven't already done so.
int size = grid->cells[linerow][grid->width - 1].data[0] == NUL ? 2 : 1;
- print_cell_at_pos(ui, (int)linerow, grid->width - size,
+ print_cell_at_pos(tui, (int)linerow, grid->width - size,
&grid->cells[linerow][grid->width - size], size == 2);
}
// Wrap the cursor over to the next line. The next line will be
// printed immediately without an intervening newline.
- final_column_wrap(ui);
+ final_column_wrap(tui);
}
}
-static void invalidate(UI *ui, int top, int bot, int left, int right)
+static void invalidate(TUIData *tui, int top, int bot, int left, int right)
{
- TUIData *data = ui->data;
Rect *intersects = NULL;
- for (size_t i = 0; i < kv_size(data->invalid_regions); i++) {
- Rect *r = &kv_A(data->invalid_regions, i);
+ for (size_t i = 0; i < kv_size(tui->invalid_regions); i++) {
+ Rect *r = &kv_A(tui->invalid_regions, i);
// adjacent regions are treated as overlapping
if (!(top > r->bot || bot < r->top)
&& !(left > r->right || right < r->left)) {
@@ -1573,20 +1499,19 @@ static void invalidate(UI *ui, int top, int bot, int left, int right)
intersects->right = MAX(right, intersects->right);
} else {
// Else just add a new entry;
- kv_push(data->invalid_regions, ((Rect) { top, bot, left, right }));
+ kv_push(tui->invalid_regions, ((Rect) { top, bot, left, right }));
}
}
/// Tries to get the user's wanted dimensions (columns and rows) for the entire
/// application (i.e., the host terminal).
-static void tui_guess_size(UI *ui)
+void tui_guess_size(TUIData *tui)
{
- TUIData *data = ui->data;
int width = 0, height = 0;
// 1 - try from a system call(ioctl/TIOCGWINSZ on unix)
- if (data->out_isatty
- && !uv_tty_get_winsize(&data->output_handle.tty, &width, &height)) {
+ if (tui->out_isatty
+ && !uv_tty_get_winsize(&tui->output_handle.tty, &width, &height)) {
goto end;
}
@@ -1601,8 +1526,8 @@ static void tui_guess_size(UI *ui)
}
// 3 - read from terminfo if available
- height = unibi_get_num(data->ut, unibi_lines);
- width = unibi_get_num(data->ut, unibi_columns);
+ height = unibi_get_num(tui->ut, unibi_lines);
+ width = unibi_get_num(tui->ut, unibi_columns);
end:
if (width <= 0 || height <= 0) {
@@ -1611,50 +1536,49 @@ static void tui_guess_size(UI *ui)
height = DFLT_ROWS;
}
- ui->width = width;
- ui->height = height;
+ if (tui->width != width || tui->height != height) {
+ tui->width = width;
+ tui->height = height;
- // TODO(bfredl): only if different from last value
- ui_schedule_refresh();
+ ui_client_set_size(width, height);
+ }
}
-static void unibi_goto(UI *ui, int row, int col)
+static void unibi_goto(TUIData *tui, int row, int col)
{
- TUIData *data = ui->data;
- UNIBI_SET_NUM_VAR(data->params[0], row);
- UNIBI_SET_NUM_VAR(data->params[1], col);
- unibi_out(ui, unibi_cursor_address);
+ UNIBI_SET_NUM_VAR(tui->params[0], row);
+ UNIBI_SET_NUM_VAR(tui->params[1], col);
+ unibi_out(tui, unibi_cursor_address);
}
#define UNIBI_OUT(fn) \
do { \
- TUIData *data = ui->data; \
const char *str = NULL; \
if (unibi_index >= 0) { \
- str = fn(data->ut, (unsigned)unibi_index); \
+ str = fn(tui->ut, (unsigned)unibi_index); \
} \
if (str) { \
unibi_var_t vars[26 + 26]; \
unibi_var_t params[9]; \
- size_t orig_pos = data->bufpos; \
+ size_t orig_pos = tui->bufpos; \
memset(&vars, 0, sizeof(vars)); \
- data->cork = true; \
+ tui->cork = true; \
retry: \
- memcpy(params, data->params, sizeof(params)); \
- unibi_format(vars, vars + 26, str, params, out, ui, pad, ui); \
- if (data->overflow) { \
- data->bufpos = orig_pos; \
- flush_buf(ui); \
+ memcpy(params, tui->params, sizeof(params)); \
+ unibi_format(vars, vars + 26, str, params, out, tui, pad, tui); \
+ if (tui->overflow) { \
+ tui->bufpos = orig_pos; \
+ flush_buf(tui); \
goto retry; \
} \
- data->cork = false; \
+ tui->cork = false; \
} \
} while (0)
-static void unibi_out(UI *ui, int unibi_index)
+static void unibi_out(TUIData *tui, int unibi_index)
{
UNIBI_OUT(unibi_get_str);
}
-static void unibi_out_ext(UI *ui, int unibi_index)
+static void unibi_out_ext(TUIData *tui, int unibi_index)
{
UNIBI_OUT(unibi_get_ext_str);
}
@@ -1662,25 +1586,24 @@ static void unibi_out_ext(UI *ui, int unibi_index)
static void out(void *ctx, const char *str, size_t len)
{
- UI *ui = ctx;
- TUIData *data = ui->data;
- size_t available = sizeof(data->buf) - data->bufpos;
+ TUIData *tui = ctx;
+ size_t available = sizeof(tui->buf) - tui->bufpos;
- if (data->cork && data->overflow) {
+ if (tui->cork && tui->overflow) {
return;
}
if (len > available) {
- if (data->cork) {
+ if (tui->cork) {
// Called by unibi_format(): avoid flush_buf() halfway an escape sequence.
- data->overflow = true;
+ tui->overflow = true;
return;
}
- flush_buf(ui);
+ flush_buf(tui);
}
- memcpy(data->buf + data->bufpos, str, len);
- data->bufpos += len;
+ memcpy(tui->buf + tui->bufpos, str, len);
+ tui->bufpos += len;
}
/// Called by unibi_format() for padding instructions.
@@ -1696,15 +1619,14 @@ static void pad(void *ctx, size_t delay, int scale FUNC_ATTR_UNUSED, int force)
return;
}
- UI *ui = ctx;
- TUIData *data = ui->data;
+ TUIData *tui = ctx;
- if (data->overflow) {
+ if (tui->overflow) {
return;
}
- flush_buf(ui);
- loop_uv_run(data->loop, (int64_t)(delay / 10), false);
+ flush_buf(tui);
+ loop_uv_run(tui->loop, (int64_t)(delay / 10), false);
}
static void unibi_set_if_empty(unibi_term *ut, enum unibi_string str, const char *val)
@@ -1741,10 +1663,10 @@ static int unibi_find_ext_bool(unibi_term *ut, const char *name)
/// Patches the terminfo records after loading from system or built-in db.
/// Several entries in terminfo are known to be deficient or outright wrong;
/// and several terminal emulators falsely announce incorrect terminal types.
-static void patch_terminfo_bugs(TUIData *data, const char *term, const char *colorterm,
+static void patch_terminfo_bugs(TUIData *tui, const char *term, const char *colorterm,
long vte_version, long konsolev, bool iterm_env, bool nsterm)
{
- unibi_term *ut = data->ut;
+ unibi_term *ut = tui->ut;
const char *xterm_version = os_getenv("XTERM_VERSION");
#if 0 // We don't need to identify this specifically, for now.
bool roxterm = !!os_getenv("ROXTERM_ID");
@@ -1941,14 +1863,14 @@ static void patch_terminfo_bugs(TUIData *data, const char *term, const char *col
#define XTERM_SETAB_16 \
"\x1b[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e39%;m"
- data->unibi_ext.get_bg = (int)unibi_add_ext_str(ut, "ext.get_bg",
- "\x1b]11;?\x07");
+ tui->unibi_ext.get_bg = (int)unibi_add_ext_str(ut, "ext.get_bg",
+ "\x1b]11;?\x07");
// Query the terminal to see if it supports CSI u key encoding by writing CSI
// ? u followed by a request for the primary device attributes (CSI c)
// See https://sw.kovidgoyal.net/kitty/keyboard-protocol/#detection-of-support-for-this-protocol
- data->unibi_ext.get_extkeys = (int)unibi_add_ext_str(ut, "ext.get_extkeys",
- "\x1b[?u\x1b[c");
+ tui->unibi_ext.get_extkeys = (int)unibi_add_ext_str(ut, "ext.get_extkeys",
+ "\x1b[?u\x1b[c");
// Terminals with 256-colour SGR support despite what terminfo says.
if (unibi_get_num(ut, unibi_max_colors) < 256) {
@@ -1979,14 +1901,14 @@ static void patch_terminfo_bugs(TUIData *data, const char *term, const char *col
// Blacklist of terminals that cannot be trusted to report DECSCUSR support.
if (!(st || (vte_version != 0 && vte_version < 3900) || konsolev)) {
- data->unibi_ext.reset_cursor_style = unibi_find_ext_str(ut, "Se");
- data->unibi_ext.set_cursor_style = unibi_find_ext_str(ut, "Ss");
+ tui->unibi_ext.reset_cursor_style = unibi_find_ext_str(ut, "Se");
+ tui->unibi_ext.set_cursor_style = unibi_find_ext_str(ut, "Ss");
}
// Dickey ncurses terminfo includes Ss/Se capabilities since 2011-07-14. So
// adding them to terminal types, that have such control sequences but lack
// the correct terminfo entries, is a fixup, not an augmentation.
- if (-1 == data->unibi_ext.set_cursor_style) {
+ if (-1 == tui->unibi_ext.set_cursor_style) {
// DECSCUSR (cursor shape) is widely supported.
// https://github.com/gnachman/iTerm2/pull/92
if ((!bsdvt && (!konsolev || konsolev >= 180770))
@@ -2012,59 +1934,59 @@ static void patch_terminfo_bugs(TUIData *data, const char *term, const char *col
// Example: console-terminal-emulator from the nosh toolset.
|| (linuxvt
&& (xterm_version || (vte_version > 0) || colorterm)))) {
- data->unibi_ext.set_cursor_style =
+ tui->unibi_ext.set_cursor_style =
(int)unibi_add_ext_str(ut, "Ss", "\x1b[%p1%d q");
- if (-1 == data->unibi_ext.reset_cursor_style) {
- data->unibi_ext.reset_cursor_style = (int)unibi_add_ext_str(ut, "Se",
- "");
+ if (-1 == tui->unibi_ext.reset_cursor_style) {
+ tui->unibi_ext.reset_cursor_style = (int)unibi_add_ext_str(ut, "Se",
+ "");
}
- unibi_set_ext_str(ut, (size_t)data->unibi_ext.reset_cursor_style,
+ unibi_set_ext_str(ut, (size_t)tui->unibi_ext.reset_cursor_style,
"\x1b[ q");
} else if (linuxvt) {
// Linux uses an idiosyncratic escape code to set the cursor shape and
// does not support DECSCUSR.
// See http://linuxgazette.net/137/anonymous.html for more info
- data->unibi_ext.set_cursor_style = (int)unibi_add_ext_str(ut, "Ss",
- "\x1b[?"
- "%?"
- // The parameter passed to Ss is the DECSCUSR parameter, so the
- // terminal capability has to translate into the Linux idiosyncratic
- // parameter.
- //
- // linuxvt only supports block and underline. It is also only
- // possible to have a steady block (no steady underline)
- "%p1%{2}%<" "%t%{8}" // blink block
- "%e%p1%{2}%=" "%t%{112}" // steady block
- "%e%p1%{3}%=" "%t%{4}" // blink underline (set to half block)
- "%e%p1%{4}%=" "%t%{4}" // steady underline
- "%e%p1%{5}%=" "%t%{2}" // blink bar (set to underline)
- "%e%p1%{6}%=" "%t%{2}" // steady bar
- "%e%{0}" // anything else
- "%;" "%dc");
- if (-1 == data->unibi_ext.reset_cursor_style) {
- data->unibi_ext.reset_cursor_style = (int)unibi_add_ext_str(ut, "Se",
- "");
+ tui->unibi_ext.set_cursor_style = (int)unibi_add_ext_str(ut, "Ss",
+ "\x1b[?"
+ "%?"
+ // The parameter passed to Ss is the DECSCUSR parameter, so the
+ // terminal capability has to translate into the Linux idiosyncratic
+ // parameter.
+ //
+ // linuxvt only supports block and underline. It is also only
+ // possible to have a steady block (no steady underline)
+ "%p1%{2}%<" "%t%{8}" // blink block
+ "%e%p1%{2}%=" "%t%{112}" // steady block
+ "%e%p1%{3}%=" "%t%{4}" // blink underline (set to half block)
+ "%e%p1%{4}%=" "%t%{4}" // steady underline
+ "%e%p1%{5}%=" "%t%{2}" // blink bar (set to underline)
+ "%e%p1%{6}%=" "%t%{2}" // steady bar
+ "%e%{0}" // anything else
+ "%;" "%dc");
+ if (-1 == tui->unibi_ext.reset_cursor_style) {
+ tui->unibi_ext.reset_cursor_style = (int)unibi_add_ext_str(ut, "Se",
+ "");
}
- unibi_set_ext_str(ut, (size_t)data->unibi_ext.reset_cursor_style,
+ unibi_set_ext_str(ut, (size_t)tui->unibi_ext.reset_cursor_style,
"\x1b[?c");
} else if (konsolev > 0 && konsolev < 180770) {
// Konsole before version 18.07.70: set up a nonce profile. This has
// side effects on temporary font resizing. #6798
- data->unibi_ext.set_cursor_style = (int)unibi_add_ext_str(ut, "Ss",
- TMUX_WRAP(tmux,
- "\x1b]50;CursorShape=%?"
- "%p1%{3}%<" "%t%{0}" // block
- "%e%p1%{5}%<" "%t%{2}" // underline
- "%e%{1}" // everything else is bar
- "%;%d;BlinkingCursorEnabled=%?"
- "%p1%{1}%<" "%t%{1}" // Fortunately if we exclude zero as special,
- "%e%p1%{1}%&" // in all other cases we can treat bit #0 as a flag.
- "%;%d\x07"));
- if (-1 == data->unibi_ext.reset_cursor_style) {
- data->unibi_ext.reset_cursor_style = (int)unibi_add_ext_str(ut, "Se",
- "");
+ tui->unibi_ext.set_cursor_style = (int)unibi_add_ext_str(ut, "Ss",
+ TMUX_WRAP(tmux,
+ "\x1b]50;CursorShape=%?"
+ "%p1%{3}%<" "%t%{0}" // block
+ "%e%p1%{5}%<" "%t%{2}" // underline
+ "%e%{1}" // everything else is bar
+ "%;%d;BlinkingCursorEnabled=%?"
+ "%p1%{1}%<" "%t%{1}" // Fortunately if we exclude zero as special,
+ "%e%p1%{1}%&" // in all other cases we can treat bit #0 as a flag.
+ "%;%d\x07"));
+ if (-1 == tui->unibi_ext.reset_cursor_style) {
+ tui->unibi_ext.reset_cursor_style = (int)unibi_add_ext_str(ut, "Se",
+ "");
}
- unibi_set_ext_str(ut, (size_t)data->unibi_ext.reset_cursor_style,
+ unibi_set_ext_str(ut, (size_t)tui->unibi_ext.reset_cursor_style,
"\x1b]50;\x07");
}
}
@@ -2072,10 +1994,10 @@ static void patch_terminfo_bugs(TUIData *data, const char *term, const char *col
/// This adds stuff that is not in standard terminfo as extended unibilium
/// capabilities.
-static void augment_terminfo(TUIData *data, const char *term, long vte_version, long konsolev,
+static void augment_terminfo(TUIData *tui, const char *term, long vte_version, long konsolev,
bool iterm_env, bool nsterm)
{
- unibi_term *ut = data->ut;
+ unibi_term *ut = tui->ut;
bool xterm = terminfo_is_term_family(term, "xterm")
// Treat Terminal.app as generic xterm-like, for now.
|| nsterm;
@@ -2105,19 +2027,19 @@ static void augment_terminfo(TUIData *data, const char *term, long vte_version,
|| konsolev // per commentary in VT102Emulation.cpp
|| teraterm // per TeraTerm "Supported Control Functions" doco
|| rxvt) { // per command.C
- data->unibi_ext.resize_screen = (int)unibi_add_ext_str(ut,
- "ext.resize_screen",
- "\x1b[8;%p1%d;%p2%dt");
+ tui->unibi_ext.resize_screen = (int)unibi_add_ext_str(ut,
+ "ext.resize_screen",
+ "\x1b[8;%p1%d;%p2%dt");
}
if (putty || xterm || hterm || rxvt) {
- data->unibi_ext.reset_scroll_region = (int)unibi_add_ext_str(ut,
- "ext.reset_scroll_region",
- "\x1b[r");
+ tui->unibi_ext.reset_scroll_region = (int)unibi_add_ext_str(ut,
+ "ext.reset_scroll_region",
+ "\x1b[r");
}
// terminfo describes strikethrough modes as rmxx/smxx with respect
// to the ECMA-48 strikeout/crossed-out attributes.
- data->unibi_ext.enter_strikethrough_mode = unibi_find_ext_str(ut, "smxx");
+ tui->unibi_ext.enter_strikethrough_mode = unibi_find_ext_str(ut, "smxx");
// Dickey ncurses terminfo does not include the setrgbf and setrgbb
// capabilities, proposed by RĂ¼diger Sonderfeld on 2013-10-15. Adding
@@ -2137,120 +2059,119 @@ static void augment_terminfo(TUIData *data, const char *term, long vte_version,
// per http://invisible-island.net/xterm/xterm.log.html#xterm_282
|| true_xterm);
- data->unibi_ext.set_rgb_foreground = unibi_find_ext_str(ut, "setrgbf");
- if (-1 == data->unibi_ext.set_rgb_foreground) {
+ tui->unibi_ext.set_rgb_foreground = unibi_find_ext_str(ut, "setrgbf");
+ if (-1 == tui->unibi_ext.set_rgb_foreground) {
if (has_colon_rgb) {
- data->unibi_ext.set_rgb_foreground = (int)unibi_add_ext_str(ut, "setrgbf",
- "\x1b[38:2:%p1%d:%p2%d:%p3%dm");
+ tui->unibi_ext.set_rgb_foreground = (int)unibi_add_ext_str(ut, "setrgbf",
+ "\x1b[38:2:%p1%d:%p2%d:%p3%dm");
} else {
- data->unibi_ext.set_rgb_foreground = (int)unibi_add_ext_str(ut, "setrgbf",
- "\x1b[38;2;%p1%d;%p2%d;%p3%dm");
+ tui->unibi_ext.set_rgb_foreground = (int)unibi_add_ext_str(ut, "setrgbf",
+ "\x1b[38;2;%p1%d;%p2%d;%p3%dm");
}
}
- data->unibi_ext.set_rgb_background = unibi_find_ext_str(ut, "setrgbb");
- if (-1 == data->unibi_ext.set_rgb_background) {
+ tui->unibi_ext.set_rgb_background = unibi_find_ext_str(ut, "setrgbb");
+ if (-1 == tui->unibi_ext.set_rgb_background) {
if (has_colon_rgb) {
- data->unibi_ext.set_rgb_background = (int)unibi_add_ext_str(ut, "setrgbb",
- "\x1b[48:2:%p1%d:%p2%d:%p3%dm");
+ tui->unibi_ext.set_rgb_background = (int)unibi_add_ext_str(ut, "setrgbb",
+ "\x1b[48:2:%p1%d:%p2%d:%p3%dm");
} else {
- data->unibi_ext.set_rgb_background = (int)unibi_add_ext_str(ut, "setrgbb",
- "\x1b[48;2;%p1%d;%p2%d;%p3%dm");
+ tui->unibi_ext.set_rgb_background = (int)unibi_add_ext_str(ut, "setrgbb",
+ "\x1b[48;2;%p1%d;%p2%d;%p3%dm");
}
}
- data->unibi_ext.set_cursor_color = unibi_find_ext_str(ut, "Cs");
- if (-1 == data->unibi_ext.set_cursor_color) {
+ tui->unibi_ext.set_cursor_color = unibi_find_ext_str(ut, "Cs");
+ if (-1 == tui->unibi_ext.set_cursor_color) {
if (iterm || iterm_pretending_xterm) {
// FIXME: Bypassing tmux like this affects the cursor colour globally, in
// all panes, which is not particularly desirable. A better approach
// would use a tmux control sequence and an extra if(screen) test.
- data->unibi_ext.set_cursor_color =
+ tui->unibi_ext.set_cursor_color =
(int)unibi_add_ext_str(ut, NULL, TMUX_WRAP(tmux, "\033]Pl%p1%06x\033\\"));
} else if ((xterm || hterm || rxvt || tmux || alacritty)
&& (vte_version == 0 || vte_version >= 3900)) {
// Supported in urxvt, newer VTE.
- data->unibi_ext.set_cursor_color = (int)unibi_add_ext_str(ut, "ext.set_cursor_color",
- "\033]12;%p1%s\007");
+ tui->unibi_ext.set_cursor_color = (int)unibi_add_ext_str(ut, "ext.set_cursor_color",
+ "\033]12;%p1%s\007");
}
}
- if (-1 != data->unibi_ext.set_cursor_color) {
+ if (-1 != tui->unibi_ext.set_cursor_color) {
// Some terminals supporting cursor color changing specify their Cs
// capability to take a string parameter. Others take a numeric parameter.
// If and only if the format string contains `%s` we assume a string
// parameter. #20628
const char *set_cursor_color =
- unibi_get_ext_str(ut, (unsigned)data->unibi_ext.set_cursor_color);
+ unibi_get_ext_str(ut, (unsigned)tui->unibi_ext.set_cursor_color);
if (set_cursor_color) {
- data->set_cursor_color_as_str = strstr(set_cursor_color, "%s") != NULL;
+ tui->set_cursor_color_as_str = strstr(set_cursor_color, "%s") != NULL;
}
- data->unibi_ext.reset_cursor_color = unibi_find_ext_str(ut, "Cr");
- if (-1 == data->unibi_ext.reset_cursor_color) {
- data->unibi_ext.reset_cursor_color = (int)unibi_add_ext_str(ut, "ext.reset_cursor_color",
- "\x1b]112\x07");
+ tui->unibi_ext.reset_cursor_color = unibi_find_ext_str(ut, "Cr");
+ if (-1 == tui->unibi_ext.reset_cursor_color) {
+ tui->unibi_ext.reset_cursor_color = (int)unibi_add_ext_str(ut, "ext.reset_cursor_color",
+ "\x1b]112\x07");
}
}
- data->unibi_ext.save_title = (int)unibi_add_ext_str(ut, "ext.save_title", "\x1b[22;0t");
- data->unibi_ext.restore_title = (int)unibi_add_ext_str(ut, "ext.restore_title", "\x1b[23;0t");
+ tui->unibi_ext.save_title = (int)unibi_add_ext_str(ut, "ext.save_title", "\x1b[22;0t");
+ tui->unibi_ext.restore_title = (int)unibi_add_ext_str(ut, "ext.restore_title", "\x1b[23;0t");
/// Terminals usually ignore unrecognized private modes, and there is no
/// known ambiguity with these. So we just set them unconditionally.
- data->unibi_ext.enable_lr_margin =
+ tui->unibi_ext.enable_lr_margin =
(int)unibi_add_ext_str(ut, "ext.enable_lr_margin", "\x1b[?69h");
- data->unibi_ext.disable_lr_margin = (int)unibi_add_ext_str(ut, "ext.disable_lr_margin",
- "\x1b[?69l");
- data->unibi_ext.enable_bracketed_paste = (int)unibi_add_ext_str(ut, "ext.enable_bpaste",
- "\x1b[?2004h");
- data->unibi_ext.disable_bracketed_paste = (int)unibi_add_ext_str(ut, "ext.disable_bpaste",
- "\x1b[?2004l");
+ tui->unibi_ext.disable_lr_margin = (int)unibi_add_ext_str(ut, "ext.disable_lr_margin",
+ "\x1b[?69l");
+ tui->unibi_ext.enable_bracketed_paste = (int)unibi_add_ext_str(ut, "ext.enable_bpaste",
+ "\x1b[?2004h");
+ tui->unibi_ext.disable_bracketed_paste = (int)unibi_add_ext_str(ut, "ext.disable_bpaste",
+ "\x1b[?2004l");
// For urxvt send BOTH xterm and old urxvt sequences. #8695
- data->unibi_ext.enable_focus_reporting = (int)unibi_add_ext_str(ut, "ext.enable_focus",
- rxvt ? "\x1b[?1004h\x1b]777;focus;on\x7" : "\x1b[?1004h");
- data->unibi_ext.disable_focus_reporting = (int)unibi_add_ext_str(ut, "ext.disable_focus",
- rxvt ? "\x1b[?1004l\x1b]777;focus;off\x7" : "\x1b[?1004l");
- data->unibi_ext.enable_mouse = (int)unibi_add_ext_str(ut, "ext.enable_mouse",
- "\x1b[?1002h\x1b[?1006h");
- data->unibi_ext.disable_mouse = (int)unibi_add_ext_str(ut, "ext.disable_mouse",
- "\x1b[?1002l\x1b[?1006l");
- data->unibi_ext.enable_mouse_move = (int)unibi_add_ext_str(ut, "ext.enable_mouse_move",
- "\x1b[?1003h");
- data->unibi_ext.disable_mouse_move = (int)unibi_add_ext_str(ut, "ext.disable_mouse_move",
- "\x1b[?1003l");
+ tui->unibi_ext.enable_focus_reporting = (int)unibi_add_ext_str(ut, "ext.enable_focus",
+ rxvt ? "\x1b[?1004h\x1b]777;focus;on\x7" : "\x1b[?1004h");
+ tui->unibi_ext.disable_focus_reporting = (int)unibi_add_ext_str(ut, "ext.disable_focus",
+ rxvt ? "\x1b[?1004l\x1b]777;focus;off\x7" : "\x1b[?1004l");
+ tui->unibi_ext.enable_mouse = (int)unibi_add_ext_str(ut, "ext.enable_mouse",
+ "\x1b[?1002h\x1b[?1006h");
+ tui->unibi_ext.disable_mouse = (int)unibi_add_ext_str(ut, "ext.disable_mouse",
+ "\x1b[?1002l\x1b[?1006l");
+ tui->unibi_ext.enable_mouse_move = (int)unibi_add_ext_str(ut, "ext.enable_mouse_move",
+ "\x1b[?1003h");
+ tui->unibi_ext.disable_mouse_move = (int)unibi_add_ext_str(ut, "ext.disable_mouse_move",
+ "\x1b[?1003l");
// Extended underline.
// terminfo will have Smulx for this (but no support for colors yet).
- data->unibi_ext.set_underline_style = unibi_find_ext_str(ut, "Smulx");
- if (data->unibi_ext.set_underline_style == -1) {
+ tui->unibi_ext.set_underline_style = unibi_find_ext_str(ut, "Smulx");
+ if (tui->unibi_ext.set_underline_style == -1) {
int ext_bool_Su = unibi_find_ext_bool(ut, "Su"); // used by kitty
if (vte_version >= 5102 || konsolev >= 221170
|| (ext_bool_Su != -1
&& unibi_get_ext_bool(ut, (size_t)ext_bool_Su))) {
- data->unibi_ext.set_underline_style = (int)unibi_add_ext_str(ut, "ext.set_underline_style",
- "\x1b[4:%p1%dm");
+ tui->unibi_ext.set_underline_style = (int)unibi_add_ext_str(ut, "ext.set_underline_style",
+ "\x1b[4:%p1%dm");
}
}
- if (data->unibi_ext.set_underline_style != -1) {
+ if (tui->unibi_ext.set_underline_style != -1) {
// Only support colon syntax. #9270
- data->unibi_ext.set_underline_color = (int)unibi_add_ext_str(ut, "ext.set_underline_color",
- "\x1b[58:2::%p1%d:%p2%d:%p3%dm");
+ tui->unibi_ext.set_underline_color = (int)unibi_add_ext_str(ut, "ext.set_underline_color",
+ "\x1b[58:2::%p1%d:%p2%d:%p3%dm");
}
if (!kitty && (vte_version == 0 || vte_version >= 5400)) {
// Fallback to Xterm's modifyOtherKeys if terminal does not support CSI u
- data->input.extkeys_type = kExtkeysXterm;
+ tui->input.extkeys_type = kExtkeysXterm;
}
}
-static void flush_buf(UI *ui)
+static void flush_buf(TUIData *tui)
{
uv_write_t req;
uv_buf_t bufs[3];
uv_buf_t *bufp = &bufs[0];
- TUIData *data = ui->data;
// The content of the output for each condition is shown in the following
- // table. Therefore, if data->bufpos == 0 and N/A or invis + norm, there is
+ // table. Therefore, if tui->bufpos == 0 and N/A or invis + norm, there is
// no need to output it.
//
// | is_invisible | !is_invisible
@@ -2262,54 +2183,54 @@ static void flush_buf(UI *ui)
// | !want_invisible | norm | invis + norm
// ------+-----------------+--------------+---------------
//
- if (data->bufpos <= 0
- && ((data->is_invisible && data->busy)
- || (data->is_invisible && !data->busy && data->want_invisible)
- || (!data->is_invisible && !data->busy && !data->want_invisible))) {
+ if (tui->bufpos <= 0
+ && ((tui->is_invisible && tui->busy)
+ || (tui->is_invisible && !tui->busy && tui->want_invisible)
+ || (!tui->is_invisible && !tui->busy && !tui->want_invisible))) {
return;
}
- if (!data->is_invisible) {
+ if (!tui->is_invisible) {
// cursor is visible. Write a "cursor invisible" command before writing the
// buffer.
- bufp->base = data->invis;
- bufp->len = UV_BUF_LEN(data->invislen);
+ bufp->base = tui->invis;
+ bufp->len = UV_BUF_LEN(tui->invislen);
bufp++;
- data->is_invisible = true;
+ tui->is_invisible = true;
}
- if (data->bufpos > 0) {
- bufp->base = data->buf;
- bufp->len = UV_BUF_LEN(data->bufpos);
+ if (tui->bufpos > 0) {
+ bufp->base = tui->buf;
+ bufp->len = UV_BUF_LEN(tui->bufpos);
bufp++;
}
- if (!data->busy) {
- assert(data->is_invisible);
+ if (!tui->busy) {
+ assert(tui->is_invisible);
// not busy and the cursor is invisible. Write a "cursor normal" command
// after writing the buffer.
- if (!data->want_invisible) {
- bufp->base = data->norm;
- bufp->len = UV_BUF_LEN(data->normlen);
+ if (!tui->want_invisible) {
+ bufp->base = tui->norm;
+ bufp->len = UV_BUF_LEN(tui->normlen);
bufp++;
- data->is_invisible = false;
+ tui->is_invisible = false;
}
}
- if (data->screenshot) {
+ if (tui->screenshot) {
for (size_t i = 0; i < (size_t)(bufp - bufs); i++) {
- fwrite(bufs[i].base, bufs[i].len, 1, data->screenshot);
+ fwrite(bufs[i].base, bufs[i].len, 1, tui->screenshot);
}
} else {
- int ret = uv_write(&req, STRUCT_CAST(uv_stream_t, &data->output_handle),
+ int ret = uv_write(&req, STRUCT_CAST(uv_stream_t, &tui->output_handle),
bufs, (unsigned)(bufp - bufs), NULL);
if (ret) {
ELOG("uv_write failed: %s", uv_strerror(ret));
}
- uv_run(&data->write_loop, UV_RUN_DEFAULT);
+ uv_run(&tui->write_loop, UV_RUN_DEFAULT);
}
- data->bufpos = 0;
- data->overflow = false;
+ tui->bufpos = 0;
+ tui->overflow = false;
}
/// Try to get "kbs" code from stty because "the terminfo kbs entry is extremely
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();
+}
diff --git a/src/nvim/ui.h b/src/nvim/ui.h
index c28393476e..9140a9f1f3 100644
--- a/src/nvim/ui.h
+++ b/src/nvim/ui.h
@@ -52,6 +52,41 @@ enum {
typedef int LineFlags;
+typedef struct {
+ uint64_t channel_id;
+
+#define UI_BUF_SIZE 4096 ///< total buffer size for pending msgpack data.
+ /// guaranteed size available for each new event (so packing of simple events
+ /// and the header of grid_line will never fail)
+#define EVENT_BUF_SIZE 256
+ char buf[UI_BUF_SIZE]; ///< buffer of packed but not yet sent msgpack data
+ char *buf_wptr; ///< write head of buffer
+ const char *cur_event; ///< name of current event (might get multiple arglists)
+ Array call_buf; ///< buffer for constructing a single arg list (max 16 elements!)
+
+ // state for write_cb, while packing a single arglist to msgpack. This
+ // might fail due to buffer overflow.
+ size_t pack_totlen;
+ bool buf_overflow;
+ char *temp_buf;
+
+ // We start packing the two outermost msgpack arrays before knowing the total
+ // number of elements. Thus track the location where array size will need
+ // to be written in the msgpack buffer, once the specific array is finished.
+ char *nevents_pos;
+ char *ncalls_pos;
+ uint32_t nevents; ///< number of distinct events (top-level args to "redraw"
+ uint32_t ncalls; ///< number of calls made to the current event (plus one for the name!)
+ bool flushed_events; ///< events where sent to client without "flush" event
+
+ int hl_id; // Current highlight for legacy put event.
+ Integer cursor_row, cursor_col; // Intended visible cursor position.
+
+ // Position of legacy cursor, used both for drawing and visible user cursor.
+ Integer client_row, client_col;
+ bool wildmenu_active;
+} UIData;
+
struct ui_t {
bool rgb;
bool override; ///< Force highest-requested UI capabilities.
@@ -65,13 +100,9 @@ struct ui_t {
double pum_col;
double pum_height;
double pum_width;
- void *data;
-
-#ifdef INCLUDE_GENERATED_DECLARATIONS
-# include "ui_events.generated.h"
-#endif
- void (*inspect)(UI *ui, Dictionary *info);
+ // TODO(bfredl): integrate into struct!
+ UIData data[1];
};
typedef struct ui_event_callback {
diff --git a/src/nvim/ui_client.c b/src/nvim/ui_client.c
index 365a76de3f..2821054909 100644
--- a/src/nvim/ui_client.c
+++ b/src/nvim/ui_client.c
@@ -15,15 +15,19 @@
#include "nvim/main.h"
#include "nvim/memory.h"
#include "nvim/msgpack_rpc/channel.h"
+#include "nvim/tui/tui.h"
#include "nvim/ui.h"
#include "nvim/ui_client.h"
+static TUIData *tui = NULL;
+
// uncrustify:off
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "ui_client.c.generated.h"
# include "ui_events_client.generated.h"
#endif
// uncrustify:on
+//
uint64_t ui_client_start_server(int argc, char **argv)
{
@@ -52,20 +56,20 @@ uint64_t ui_client_start_server(int argc, char **argv)
void ui_client_run(bool remote_ui)
FUNC_ATTR_NORETURN
{
- ui_builtin_start();
-
- loop_poll_events(&main_loop, 1);
+ int width, height;
+ char *term;
+ tui = tui_start(&width, &height, &term);
MAXSIZE_TEMP_ARRAY(args, 3);
- ADD_C(args, INTEGER_OBJ(Columns));
- ADD_C(args, INTEGER_OBJ(Rows));
+ ADD_C(args, INTEGER_OBJ(width));
+ ADD_C(args, INTEGER_OBJ(height));
MAXSIZE_TEMP_DICT(opts, 9);
PUT_C(opts, "rgb", BOOLEAN_OBJ(true));
PUT_C(opts, "ext_linegrid", BOOLEAN_OBJ(true));
PUT_C(opts, "ext_termcolors", BOOLEAN_OBJ(true));
- if (ui_client_termname) {
- PUT_C(opts, "term_name", STRING_OBJ(cstr_as_string(ui_client_termname)));
+ if (term) {
+ PUT(opts, "term_name", STRING_OBJ(cstr_to_string(term)));
}
if (ui_client_bg_respose != kNone) {
bool is_dark = (ui_client_bg_respose == kTrue);
@@ -80,6 +84,7 @@ void ui_client_run(bool remote_ui)
}
}
ADD_C(args, DICTIONARY_OBJ(opts));
+
rpc_send_event(ui_client_channel_id, "nvim_ui_attach", args);
ui_client_attached = true;
@@ -89,6 +94,22 @@ void ui_client_run(bool remote_ui)
}
}
+void ui_client_stop(void)
+{
+ tui_stop(tui);
+}
+
+void ui_client_set_size(int width, int height)
+{
+ // The currently known size will be sent when attaching
+ if (ui_client_attached) {
+ 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);
+ }
+}
+
UIClientHandler ui_client_get_redraw_handler(const char *name, size_t name_len, Error *error)
{
int hash = ui_client_handler_hash(name, name_len);
@@ -133,7 +154,7 @@ void ui_client_event_grid_resize(Array args)
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);
+ tui_grid_resize(tui, grid, width, height);
if (grid_line_buf_size < (size_t)width) {
xfree(grid_line_buf_char);
@@ -159,6 +180,6 @@ void ui_client_event_raw_line(GridLineEvent *g)
// TODO(hlpr98): Accommodate other LineFlags when included in grid_line
LineFlags lineflags = 0;
- ui_call_raw_line(grid, row, startcol, endcol, clearcol, g->cur_attr, lineflags,
- (const schar_T *)grid_line_buf_char, grid_line_buf_attr);
+ tui_raw_line(tui, grid, row, startcol, endcol, clearcol, g->cur_attr, lineflags,
+ (const schar_T *)grid_line_buf_char, grid_line_buf_attr);
}
diff --git a/src/nvim/ui_client.h b/src/nvim/ui_client.h
index 67d16e7fb1..24b8fad4cc 100644
--- a/src/nvim/ui_client.h
+++ b/src/nvim/ui_client.h
@@ -34,8 +34,6 @@ EXTERN TriState ui_client_bg_respose INIT(= kNone);
/// by convention, this uses fd=3 (next free number after stdio)
EXTERN bool ui_client_forward_stdin INIT(= false);
-EXTERN char *ui_client_termname INIT(= NULL);
-
#define UI_CLIENT_STDIN_FD 3
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "ui_client.h.generated.h"
diff --git a/src/nvim/ui_compositor.c b/src/nvim/ui_compositor.c
index 26a17ef747..0f9b0af1c1 100644
--- a/src/nvim/ui_compositor.c
+++ b/src/nvim/ui_compositor.c
@@ -23,7 +23,6 @@
#include "nvim/highlight.h"
#include "nvim/highlight_group.h"
#include "nvim/log.h"
-#include "nvim/lua/executor.h"
#include "nvim/macros.h"
#include "nvim/map.h"
#include "nvim/memory.h"
@@ -39,7 +38,6 @@
# include "ui_compositor.c.generated.h"
#endif
-static UI *compositor = NULL;
static int composed_uis = 0;
kvec_t(ScreenGrid *) layers = KV_INITIAL_VALUE;
@@ -60,52 +58,12 @@ static bool msg_was_scrolled = false;
static int msg_sep_row = -1;
static schar_T msg_sep_char = { ' ', NUL };
-static PMap(uint32_t) ui_event_cbs = MAP_INIT;
-
static int dbghl_normal, dbghl_clear, dbghl_composed, dbghl_recompose;
void ui_comp_init(void)
{
- if (compositor != NULL) {
- return;
- }
- compositor = xcalloc(1, sizeof(UI));
-
- compositor->rgb = true;
- compositor->grid_resize = ui_comp_grid_resize;
- compositor->grid_scroll = ui_comp_grid_scroll;
- compositor->grid_cursor_goto = ui_comp_grid_cursor_goto;
- compositor->raw_line = ui_comp_raw_line;
- compositor->msg_set_pos = ui_comp_msg_set_pos;
- compositor->event = ui_comp_event;
-
- // Be unopinionated: will be attached together with a "real" ui anyway
- compositor->width = INT_MAX;
- compositor->height = INT_MAX;
- for (UIExtension i = kUIGlobalCount; (int)i < kUIExtCount; i++) {
- compositor->ui_ext[i] = true;
- }
-
- // TODO(bfredl): one day. in the future.
- compositor->ui_ext[kUIMultigrid] = false;
-
- // TODO(bfredl): this will be more complicated if we implement
- // hlstate per UI (i e reduce hl ids for non-hlstate UIs)
- compositor->ui_ext[kUIHlState] = false;
-
kv_push(layers, &default_grid);
curgrid = &default_grid;
-
- ui_attach_impl(compositor, 0);
-}
-
-void ui_comp_free_all_mem(void)
-{
- UIEventCallback *event_cb;
- map_foreach_value(&ui_event_cbs, event_cb, {
- free_ui_event_callback(event_cb);
- })
- pmap_destroy(uint32_t)(&ui_event_cbs);
}
void ui_comp_syn_init(void)
@@ -258,7 +216,7 @@ bool ui_comp_set_grid(handle_T handle)
return false;
}
-static void ui_comp_raise_grid(ScreenGrid *grid, size_t new_index)
+void ui_comp_raise_grid(ScreenGrid *grid, size_t new_index)
{
size_t old_index = grid->comp_index;
for (size_t i = old_index; i < new_index; i++) {
@@ -278,7 +236,7 @@ static void ui_comp_raise_grid(ScreenGrid *grid, size_t new_index)
}
}
-static void ui_comp_grid_cursor_goto(UI *ui, Integer grid_handle, Integer r, Integer c)
+void ui_comp_grid_cursor_goto(Integer grid_handle, Integer r, Integer c)
{
if (!ui_comp_should_draw() || !ui_comp_set_grid((int)grid_handle)) {
return;
@@ -538,9 +496,9 @@ void ui_comp_compose_grid(ScreenGrid *grid)
}
}
-static void ui_comp_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Integer endcol,
- Integer clearcol, Integer clearattr, LineFlags flags,
- const schar_T *chunk, const sattr_T *attrs)
+void ui_comp_raw_line(Integer grid, Integer row, Integer startcol, Integer endcol, Integer clearcol,
+ Integer clearattr, LineFlags flags, const schar_T *chunk,
+ const sattr_T *attrs)
{
if (!ui_comp_should_draw() || !ui_comp_set_grid((int)grid)) {
return;
@@ -605,8 +563,7 @@ bool ui_comp_set_screen_valid(bool valid)
return old_val;
}
-static void ui_comp_msg_set_pos(UI *ui, Integer grid, Integer row, Boolean scrolled,
- String sep_char)
+void ui_comp_msg_set_pos(Integer grid, Integer row, Boolean scrolled, String sep_char)
{
msg_grid.comp_row = (int)row;
if (scrolled && row > 0) {
@@ -650,8 +607,8 @@ static bool curgrid_covered_above(int row)
return kv_size(layers) - (above_msg?1:0) > curgrid->comp_index + 1;
}
-static void ui_comp_grid_scroll(UI *ui, Integer grid, Integer top, Integer bot, Integer left,
- Integer right, Integer rows, Integer cols)
+void ui_comp_grid_scroll(Integer grid, Integer top, Integer bot, Integer left, Integer right,
+ Integer rows, Integer cols)
{
if (!ui_comp_should_draw() || !ui_comp_set_grid((int)grid)) {
return;
@@ -685,7 +642,7 @@ static void ui_comp_grid_scroll(UI *ui, Integer grid, Integer top, Integer bot,
}
}
-static void ui_comp_grid_resize(UI *ui, Integer grid, Integer width, Integer height)
+void ui_comp_grid_resize(Integer grid, Integer width, Integer height)
{
if (grid == 1) {
ui_composed_call_grid_resize(1, width, height);
@@ -703,75 +660,3 @@ static void ui_comp_grid_resize(UI *ui, Integer grid, Integer width, Integer hei
}
}
}
-
-static void ui_comp_event(UI *ui, 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_composed_call_event(name, args);
- }
-}
-
-static void ui_comp_update_ext(void)
-{
- memset(compositor->ui_ext, 0, ARRAY_SIZE(compositor->ui_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]) {
- compositor->ui_ext[i] = true;
- break;
- }
- })
- }
-}
-
-void free_ui_event_callback(UIEventCallback *event_cb)
-{
- api_free_luaref(event_cb->cb);
- xfree(event_cb);
-}
-
-void ui_comp_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_comp_update_ext();
- ui_refresh();
-}
-
-void ui_comp_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_comp_update_ext();
- ui_refresh();
-}