aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/tui/tui.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/tui/tui.c')
-rw-r--r--src/nvim/tui/tui.c135
1 files changed, 78 insertions, 57 deletions
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index 3010a7b612..4634c77a1f 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_bridge.c) on the TUI thread.
+// Terminal UI functions. Invoked (by UI_CALL) on the UI process.
#include <assert.h>
#include <signal.h>
@@ -48,7 +48,7 @@
#include "nvim/tui/terminfo.h"
#include "nvim/tui/tui.h"
#include "nvim/ugrid.h"
-#include "nvim/ui_bridge.h"
+#include "nvim/msgpack_rpc/channel.h"
// Space reserved in two output buffers to make the cursor normal or invisible
// when flushing. No existing terminal will require 32 bytes to do that.
@@ -91,7 +91,7 @@ typedef struct {
} Rect;
struct TUIData {
- UIBridgeData *bridge;
+ UI *ui;
Loop *loop;
unibi_var_t params[9];
char buf[OUTBUF_SIZE];
@@ -159,18 +159,19 @@ struct TUIData {
int get_extkeys;
} unibi_ext;
char *space_buf;
+ bool stopped;
};
static int got_winch = 0;
static bool cursor_style_enabled = false;
-
+char *termname_local;
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "tui/tui.c.generated.h"
#endif
UI *tui_start(void)
{
- UI *ui = xcalloc(1, sizeof(UI)); // Freed by ui_bridge_stop().
+ 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;
@@ -198,15 +199,18 @@ UI *tui_start(void)
CLEAR_FIELD(ui->ui_ext);
ui->ui_ext[kUILinegrid] = true;
ui->ui_ext[kUITermColors] = true;
+
+ tui_main(ui);
+ ui_attach_impl(ui, 0);
- return ui_bridge_attach(ui, tui_main, tui_scheduler);
+ return ui;
}
void tui_enable_extkeys(TUIData *data)
{
TermInput input = data->input;
unibi_term *ut = data->ut;
- UI *ui = data->bridge->ui;
+ UI *ui = data->ui;
switch (input.extkeys_type) {
case kExtkeysCSIu:
@@ -237,13 +241,6 @@ static size_t unibi_pre_fmt_str(TUIData *data, unsigned int unibi_index, char *b
return unibi_run(str, data->params, buf, len);
}
-static void termname_set_event(void **argv)
-{
- char *termname = argv[0];
- set_tty_option("term", termname);
- // Do not free termname, it is freed by set_tty_option.
-}
-
static void terminfo_start(UI *ui)
{
TUIData *data = ui->data;
@@ -294,22 +291,19 @@ static void terminfo_start(UI *ui)
#endif
// Set up unibilium/terminfo.
- char *termname = NULL;
+ termname_local = NULL;
if (term) {
os_env_var_lock();
data->ut = unibi_from_term(term);
os_env_var_unlock();
if (data->ut) {
- termname = xstrdup(term);
+ termname_local = xstrdup(term);
data->term = xstrdup(term);
}
}
if (!data->ut) {
- data->ut = terminfo_from_builtin(term, &termname);
+ data->ut = terminfo_from_builtin(term, &termname_local);
}
- // Update 'term' option.
- loop_schedule_deferred(&main_loop,
- event_create(termname_set_event, 1, termname));
// None of the following work over SSH; see :help TERM .
const char *colorterm = os_getenv("COLORTERM");
@@ -467,7 +461,7 @@ static void tui_terminal_stop(UI *ui)
if (uv_is_closing(STRUCT_CAST(uv_handle_t, &data->output_handle))) {
// Race between SIGCONT (tui.c) and SIGHUP (os/signal.c)? #8075
ELOG("TUI already stopped (race?)");
- ui->data = NULL; // Flag UI as "stopped".
+ data->stopped = true;
return;
}
tinput_stop(&data->input);
@@ -479,26 +473,27 @@ static void tui_terminal_stop(UI *ui)
static void tui_stop(UI *ui)
{
tui_terminal_stop(ui);
- ui->data = NULL; // Flag UI as "stopped".
+ TUIData *data = ui->data;
+ data->stopped = true;
}
/// Returns true if UI `ui` is stopped.
static bool tui_is_stopped(UI *ui)
{
- return ui->data == NULL;
+ TUIData *data = ui->data;
+ return data->stopped;
}
-/// Main function of the TUI thread.
-static void tui_main(UIBridgeData *bridge, UI *ui)
+// Main function for TUI
+static void tui_main(UI *ui)
{
- Loop tui_loop;
- loop_init(&tui_loop, NULL);
TUIData *data = xcalloc(1, sizeof(TUIData));
ui->data = data;
- data->bridge = bridge;
- data->loop = &tui_loop;
+ 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);
signal_watcher_init(data->loop, &data->cont_handle, data);
@@ -510,43 +505,54 @@ static void tui_main(UIBridgeData *bridge, UI *ui)
kv_push(data->attrs, HLATTRS_INIT);
data->input.tk_ti_hook_fn = tui_tk_ti_getstr;
- tinput_init(&data->input, &tui_loop);
+ tinput_init(&data->input, &main_loop);
tui_terminal_start(ui);
+ // TODO: borked!
+ // loop_schedule(&main_loop, event_create(show_termcap_event, 1, data->ut));
- // Allow main thread to continue, we are ready to handle UI callbacks.
- CONTINUE(bridge);
+}
- // "Active" loop: first ~100 ms of startup.
- for (size_t ms = 0; ms < 100 && !tui_is_stopped(ui);) {
- ms += (loop_poll_events(&tui_loop, 20) ? 20 : 1);
- }
- if (!tui_is_stopped(ui)) {
- tui_terminal_after_startup(ui);
- }
- // "Passive" (I/O-driven) loop: TUI thread "main loop".
+void tui_execute(void)
+ FUNC_ATTR_NORETURN
+{
+ UI *ui = ui_get_by_index(1);
+ LOOP_PROCESS_EVENTS(&main_loop, main_loop.events, -1);
+ tui_io_driven_loop(ui);
+ tui_exit_safe(ui);
+ getout(0);
+}
+
+// Doesn't return until the TUI is closed (by call of tui_stop())
+static void tui_io_driven_loop(UI *ui){
+ // "Passive" (I/O-driven) loop: TUI process's "main loop".
while (!tui_is_stopped(ui)) {
- loop_poll_events(&tui_loop, -1); // tui_loop.events is never processed
+ loop_poll_events(&main_loop, -1);
}
+}
- ui_bridge_stopped(bridge);
- tinput_destroy(&data->input);
- signal_watcher_stop(&data->cont_handle);
- signal_watcher_close(&data->cont_handle, NULL);
- signal_watcher_close(&data->winch_handle, NULL);
- loop_close(&tui_loop, false);
+// TODO: call me when EXITFREE
+#if 0
+static void tui_data_destroy(void **argv) {
+ UI *ui = argv[0];
+ TUIData *data = ui->data;
kv_destroy(data->invalid_regions);
kv_destroy(data->attrs);
xfree(data->space_buf);
xfree(data->term);
xfree(data);
+ xfree(ui);
}
+#endif
-/// Handoff point between the main (ui_bridge) thread and the TUI thread.
-static void tui_scheduler(Event event, void *d)
-{
- UI *ui = d;
+void tui_exit_safe(UI *ui) {
TUIData *data = ui->data;
- loop_schedule_fast(data->loop, event); // `tui_loop` local to tui_main().
+ if (!tui_is_stopped(ui)) {
+ tui_stop(ui);
+ }
+ tinput_destroy(&data->input);
+ signal_watcher_stop(&data->cont_handle);
+ signal_watcher_close(&data->cont_handle, NULL);
+ signal_watcher_close(&data->winch_handle, NULL);
}
#ifdef UNIX
@@ -1324,6 +1330,9 @@ static void tui_grid_scroll(UI *ui, Integer g, Integer startrow, // -V751
static void tui_hl_attr_define(UI *ui, 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;
}
@@ -1399,6 +1408,7 @@ static void tui_flush(UI *ui)
flush_buf(ui);
}
+#if 0
/// Dumps termcap info to the messages area, if 'verbose' >= 3.
static void show_verbose_terminfo(TUIData *data)
{
@@ -1448,6 +1458,7 @@ static void verbose_terminfo_event(void **argv)
}
api_clear_error(&err);
}
+#endif
#ifdef UNIX
static void suspend_event(void **argv)
@@ -1459,20 +1470,19 @@ static void suspend_event(void **argv)
data->cont_received = false;
stream_set_blocking(input_global_fd(), true); // normalize stream (#2598)
signal_stop();
- kill(0, SIGTSTP);
+ kill(0, SIGTSTP); // make TUI process run in background
signal_start();
while (!data->cont_received) {
// poll the event loop until SIGCONT is received
loop_poll_events(data->loop, -1);
}
+
tui_terminal_start(ui);
tui_terminal_after_startup(ui);
if (enable_mouse) {
tui_mouse_on(ui);
}
stream_set_blocking(input_global_fd(), false); // libuv expects this
- // resume the main thread
- CONTINUE(data->bridge);
}
#endif
@@ -1547,6 +1557,13 @@ static void tui_option_set(UI *ui, String name, Object value)
ui->rgb = value.data.boolean;
data->print_attr_id = -1;
invalidate(ui, 0, data->grid.height, 0, data->grid.width);
+
+ if (ui_client_channel_id) {
+ Array args = ARRAY_DICT_INIT;
+ ADD(args, STRING_OBJ(cstr_as_string(xstrdup("rgb"))));
+ ADD(args, BOOLEAN_OBJ(value.data.boolean));
+ rpc_send_event(ui_client_channel_id, "nvim_ui_set_option", args);
+ }
} else if (strequal(name.data, "ttimeout")) {
data->input.ttimeout = value.data.boolean;
} else if (strequal(name.data, "ttimeoutlen")) {
@@ -1595,6 +1612,10 @@ static void tui_raw_line(UI *ui, Integer g, Integer linerow, Integer startcol, I
// printed immediately without an intervening newline.
final_column_wrap(ui);
}
+
+ // TODO: wat
+ //xfree((void *) chunk);
+ //xfree((void *) attrs);
}
static void invalidate(UI *ui, int top, int bot, int left, int right)
@@ -1659,8 +1680,8 @@ static void tui_guess_size(UI *ui)
height = DFLT_ROWS;
}
- data->bridge->bridge.width = ui->width = width;
- data->bridge->bridge.height = ui->height = height;
+ ui->width = width;
+ ui->height = height;
}
static void unibi_goto(UI *ui, int row, int col)