aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGregory Anders <8965202+gpanders@users.noreply.github.com>2023-11-06 12:42:40 -0600
committerGitHub <noreply@github.com>2023-11-06 12:42:40 -0600
commit56627ca2423e9d6084f87f5bc4639f06d10ecf91 (patch)
tree98926016c96ef66a6c6e27b339e0c3450180af50 /src
parentf9416470b15b3601c5b2d805a8cf3bdabd44a567 (diff)
downloadrneovim-56627ca2423e9d6084f87f5bc4639f06d10ecf91.tar.gz
rneovim-56627ca2423e9d6084f87f5bc4639f06d10ecf91.tar.bz2
rneovim-56627ca2423e9d6084f87f5bc4639f06d10ecf91.zip
feat(tui): use TermResponse event for OSC responses (#25868)
When the terminal emulator sends an OSC sequence to Nvim (as a response to another OSC sequence that was first sent by Nvim), populate the OSC sequence in the v:termresponse variable and fire the TermResponse event. The escape sequence is also included in the "data" field of the autocommand callback when the autocommand is defined in Lua. This makes use of the already documented but unimplemented TermResponse event. This event exists in Vim but is only fired when Vim receives a primary device attributes response. Fixes: https://github.com/neovim/neovim/issues/25856
Diffstat (limited to 'src')
-rw-r--r--src/nvim/api/ui.c27
-rw-r--r--src/nvim/tui/input.c26
2 files changed, 53 insertions, 0 deletions
diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c
index b508a3ee94..99215f7b4f 100644
--- a/src/nvim/api/ui.c
+++ b/src/nvim/api/ui.c
@@ -16,6 +16,7 @@
#include "nvim/api/ui.h"
#include "nvim/autocmd.h"
#include "nvim/channel.h"
+#include "nvim/eval.h"
#include "nvim/event/loop.h"
#include "nvim/event/wstream.h"
#include "nvim/globals.h"
@@ -524,6 +525,32 @@ void nvim_ui_pum_set_bounds(uint64_t channel_id, Float width, Float height, Floa
ui->pum_pos = true;
}
+/// Tells Nvim when a terminal event has occurred.
+///
+/// The following terminal events are supported:
+///
+/// - "osc_response": The terminal sent a OSC response sequence to Nvim. The
+/// payload is the received OSC sequence.
+///
+/// @param channel_id
+/// @param event Event name
+/// @param payload Event payload
+/// @param[out] err Error details, if any.
+void nvim_ui_term_event(uint64_t channel_id, String event, Object value, Error *err)
+ FUNC_API_SINCE(12) FUNC_API_REMOTE_ONLY
+{
+ if (strequal("osc_response", event.data)) {
+ if (value.type != kObjectTypeString) {
+ api_set_error(err, kErrorTypeValidation, "osc_response must be a string");
+ return;
+ }
+
+ const String osc_response = value.data.string;
+ set_vim_var_string(VV_TERMRESPONSE, osc_response.data, (ptrdiff_t)osc_response.size);
+ apply_autocmds_group(EVENT_TERMRESPONSE, NULL, NULL, false, AUGROUP_ALL, NULL, NULL, &value);
+ }
+}
+
static void flush_event(UIData *data)
{
if (data->cur_event) {
diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c
index 487f8b010e..1f659264c5 100644
--- a/src/nvim/tui/input.c
+++ b/src/nvim/tui/input.c
@@ -11,6 +11,7 @@
#include "nvim/api/private/helpers.h"
#include "nvim/ascii.h"
#include "nvim/charset.h"
+#include "nvim/eval.h"
#include "nvim/event/defs.h"
#include "nvim/log.h"
#include "nvim/macros.h"
@@ -479,6 +480,8 @@ static void tk_getkeys(TermInput *input, bool force)
}
}
}
+ } else if (key.type == TERMKEY_TYPE_OSC) {
+ handle_osc_event(input, &key);
}
}
@@ -684,6 +687,29 @@ HandleState handle_background_color(TermInput *input)
return kComplete;
}
+static void handle_osc_event(TermInput *input, const TermKeyKey *key)
+{
+ assert(input);
+
+ const char *str = NULL;
+ if (termkey_interpret_string(input->tk, key, &str) == TERMKEY_RES_KEY) {
+ assert(str != NULL);
+
+ // Send an event to nvim core. This will update the v:termresponse variable and fire the
+ // TermResponse event
+ MAXSIZE_TEMP_ARRAY(args, 2);
+ ADD_C(args, STATIC_CSTR_AS_OBJ("osc_response"));
+
+ // libtermkey strips the OSC bytes from the response. We add it back in so that downstream
+ // consumers of v:termresponse can differentiate between OSC and CSI events.
+ StringBuilder response = KV_INITIAL_VALUE;
+ kv_printf(response, "\x1b]%s", str);
+ ADD_C(args, STRING_OBJ(cbuf_as_string(response.items, response.size)));
+ rpc_send_event(ui_client_channel_id, "nvim_ui_term_event", args);
+ kv_destroy(response);
+ }
+}
+
static void handle_raw_buffer(TermInput *input, bool force)
{
HandleState is_paste = kNotApplicable;