From b4b7ca2d548a1cc1a2cd8c48e5c93478811bd275 Mon Sep 17 00:00:00 2001 From: Gregory Anders <8965202+gpanders@users.noreply.github.com> Date: Thu, 16 Nov 2023 11:12:42 -0600 Subject: [PATCH] feat(tui): support DCS responses in TermResponse event (#26061) --- runtime/doc/api.txt | 8 ++++---- runtime/doc/autocmd.txt | 4 ++-- runtime/doc/eval.txt | 8 ++++---- runtime/lua/vim/_meta/api.lua | 7 ++++--- src/nvim/api/ui.c | 15 ++++++++------- src/nvim/tui/input.c | 30 +++++++++++++++++++++--------- 6 files changed, 43 insertions(+), 29 deletions(-) diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt index 6970479a78..908198de4c 100644 --- a/runtime/doc/api.txt +++ b/runtime/doc/api.txt @@ -3598,13 +3598,13 @@ nvim_ui_set_option({name}, {value}) *nvim_ui_set_option()* |RPC| only nvim_ui_term_event({event}, {value}) *nvim_ui_term_event()* - Tells Nvim when a terminal event has occurred: sets |v:termresponse| and - fires |TermResponse|. + 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. + • "termresponse": The terminal sent an OSC or DCS response sequence to + Nvim. The payload is the received response. Sets |v:termresponse| and + fires |TermResponse|. Attributes: ~ |RPC| only diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt index 6b698b0868..c6f6559e37 100644 --- a/runtime/doc/autocmd.txt +++ b/runtime/doc/autocmd.txt @@ -987,8 +987,8 @@ TermClose When a |terminal| job ends. Sets these |v:event| keys: status *TermResponse* -TermResponse When Nvim receives a OSC response from the - terminal. Sets |v:termresponse|. When used +TermResponse When Nvim receives an OSC or DCS response from + the terminal. Sets |v:termresponse|. When used from Lua, the response string is included in the "data" field of the autocommand callback. May be triggered halfway through another event diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 2223829548..a73932be00 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -2318,10 +2318,10 @@ v:t_string Value of |String| type. Read-only. See: |type()| v:t_blob Value of |Blob| type. Read-only. See: |type()| *v:termresponse* *termresponse-variable* -v:termresponse The value of the most recent OSC escape sequence received by - Nvim from the terminal. This can be read in a |TermResponse| - event handler after querying the terminal using another escape - sequence. +v:termresponse The value of the most recent OSC or DCS escape sequence + received by Nvim from the terminal. This can be read in a + |TermResponse| event handler after querying the terminal using + another escape sequence. *v:testing* *testing-variable* v:testing Must be set before using `test_garbagecollect_now()`. diff --git a/runtime/lua/vim/_meta/api.lua b/runtime/lua/vim/_meta/api.lua index 2142a429a2..0c8979054f 100644 --- a/runtime/lua/vim/_meta/api.lua +++ b/runtime/lua/vim/_meta/api.lua @@ -2065,11 +2065,12 @@ function vim.api.nvim_ui_set_focus(gained) end --- @param value any function vim.api.nvim_ui_set_option(name, value) end ---- Tells Nvim when a terminal event has occurred. +--- 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. +--- • "termresponse": The terminal sent an OSC or DCS response sequence to +--- Nvim. The payload is the received response. Sets `v:termresponse` and +--- fires `TermResponse`. --- --- --- @param event string Event name diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index 1483650739..c1fc986029 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -513,12 +513,13 @@ 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: sets |v:termresponse| and fires |TermResponse|. +/// 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. +/// - "termresponse": The terminal sent an OSC or DCS response sequence to +/// Nvim. The payload is the received response. Sets +/// |v:termresponse| and fires |TermResponse|. /// /// @param channel_id /// @param event Event name @@ -527,14 +528,14 @@ void nvim_ui_pum_set_bounds(uint64_t channel_id, Float width, Float height, Floa 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 (strequal("termresponse", event.data)) { if (value.type != kObjectTypeString) { - api_set_error(err, kErrorTypeValidation, "osc_response must be a string"); + api_set_error(err, kErrorTypeValidation, "termresponse 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); + const String termresponse = value.data.string; + set_vim_var_string(VV_TERMRESPONSE, termresponse.data, (ptrdiff_t)termresponse.size); apply_autocmds_group(EVENT_TERMRESPONSE, NULL, NULL, false, AUGROUP_ALL, NULL, NULL, &value); } } diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c index ce17d22578..de4afa68cf 100644 --- a/src/nvim/tui/input.c +++ b/src/nvim/tui/input.c @@ -476,8 +476,8 @@ static void tk_getkeys(TermInput *input, bool force) } } } - } else if (key.type == TERMKEY_TYPE_OSC) { - handle_osc_event(input, &key); + } else if (key.type == TERMKEY_TYPE_OSC || key.type == TERMKEY_TYPE_DCS) { + handle_term_response(input, &key); } else if (key.type == TERMKEY_TYPE_MODEREPORT) { handle_modereport(input, &key); } @@ -578,22 +578,34 @@ static HandleState handle_bracketed_paste(TermInput *input) return kNotApplicable; } -static void handle_osc_event(TermInput *input, const TermKeyKey *key) +static void handle_term_response(TermInput *input, const TermKeyKey *key) FUNC_ATTR_NONNULL_ALL { 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 + // 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")); + ADD_C(args, STATIC_CSTR_AS_OBJ("termresponse")); - // 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. + // libtermkey strips the OSC/DCS bytes from the response. We add it back in + // so that downstream consumers of v:termresponse can differentiate between + // the two. StringBuilder response = KV_INITIAL_VALUE; - kv_printf(response, "\x1b]%s", str); + switch (key->type) { + case TERMKEY_TYPE_OSC: + kv_printf(response, "\x1b]%s", str); + break; + case TERMKEY_TYPE_DCS: + kv_printf(response, "\x1bP%s", str); + break; + default: + // Key type already checked for OSC/DCS in termkey_interpret_string + UNREACHABLE; + } + 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);