feat(tui): support DCS responses in TermResponse event (#26061)

This commit is contained in:
Gregory Anders 2023-11-16 11:12:42 -06:00 committed by GitHub
parent dc3f84bf4f
commit b4b7ca2d54
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 43 additions and 29 deletions

View File

@ -3598,13 +3598,13 @@ nvim_ui_set_option({name}, {value}) *nvim_ui_set_option()*
|RPC| only |RPC| only
nvim_ui_term_event({event}, {value}) *nvim_ui_term_event()* nvim_ui_term_event({event}, {value}) *nvim_ui_term_event()*
Tells Nvim when a terminal event has occurred: sets |v:termresponse| and Tells Nvim when a terminal event has occurred
fires |TermResponse|.
The following terminal events are supported: The following terminal events are supported:
• "osc_response": The terminal sent a OSC response sequence to Nvim. The • "termresponse": The terminal sent an OSC or DCS response sequence to
payload is the received OSC sequence. Nvim. The payload is the received response. Sets |v:termresponse| and
fires |TermResponse|.
Attributes: ~ Attributes: ~
|RPC| only |RPC| only

View File

@ -987,8 +987,8 @@ TermClose When a |terminal| job ends.
Sets these |v:event| keys: Sets these |v:event| keys:
status status
*TermResponse* *TermResponse*
TermResponse When Nvim receives a OSC response from the TermResponse When Nvim receives an OSC or DCS response from
terminal. Sets |v:termresponse|. When used the terminal. Sets |v:termresponse|. When used
from Lua, the response string is included in from Lua, the response string is included in
the "data" field of the autocommand callback. the "data" field of the autocommand callback.
May be triggered halfway through another event May be triggered halfway through another event

View File

@ -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:t_blob Value of |Blob| type. Read-only. See: |type()|
*v:termresponse* *termresponse-variable* *v:termresponse* *termresponse-variable*
v:termresponse The value of the most recent OSC escape sequence received by v:termresponse The value of the most recent OSC or DCS escape sequence
Nvim from the terminal. This can be read in a |TermResponse| received by Nvim from the terminal. This can be read in a
event handler after querying the terminal using another escape |TermResponse| event handler after querying the terminal using
sequence. another escape sequence.
*v:testing* *testing-variable* *v:testing* *testing-variable*
v:testing Must be set before using `test_garbagecollect_now()`. v:testing Must be set before using `test_garbagecollect_now()`.

View File

@ -2065,11 +2065,12 @@ function vim.api.nvim_ui_set_focus(gained) end
--- @param value any --- @param value any
function vim.api.nvim_ui_set_option(name, value) end 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: --- The following terminal events are supported:
--- ---
--- • "osc_response": The terminal sent a OSC response sequence to Nvim. The --- • "termresponse": The terminal sent an OSC or DCS response sequence to
--- payload is the received OSC sequence. --- Nvim. The payload is the received response. Sets `v:termresponse` and
--- fires `TermResponse`.
--- ---
--- ---
--- @param event string Event name --- @param event string Event name

View File

@ -513,12 +513,13 @@ void nvim_ui_pum_set_bounds(uint64_t channel_id, Float width, Float height, Floa
ui->pum_pos = true; 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: /// The following terminal events are supported:
/// ///
/// - "osc_response": The terminal sent a OSC response sequence to Nvim. The /// - "termresponse": The terminal sent an OSC or DCS response sequence to
/// payload is the received OSC sequence. /// Nvim. The payload is the received response. Sets
/// |v:termresponse| and fires |TermResponse|.
/// ///
/// @param channel_id /// @param channel_id
/// @param event Event name /// @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) void nvim_ui_term_event(uint64_t channel_id, String event, Object value, Error *err)
FUNC_API_SINCE(12) FUNC_API_REMOTE_ONLY FUNC_API_SINCE(12) FUNC_API_REMOTE_ONLY
{ {
if (strequal("osc_response", event.data)) { if (strequal("termresponse", event.data)) {
if (value.type != kObjectTypeString) { 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; return;
} }
const String osc_response = value.data.string; const String termresponse = value.data.string;
set_vim_var_string(VV_TERMRESPONSE, osc_response.data, (ptrdiff_t)osc_response.size); 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); apply_autocmds_group(EVENT_TERMRESPONSE, NULL, NULL, false, AUGROUP_ALL, NULL, NULL, &value);
} }
} }

View File

@ -476,8 +476,8 @@ static void tk_getkeys(TermInput *input, bool force)
} }
} }
} }
} else if (key.type == TERMKEY_TYPE_OSC) { } else if (key.type == TERMKEY_TYPE_OSC || key.type == TERMKEY_TYPE_DCS) {
handle_osc_event(input, &key); handle_term_response(input, &key);
} else if (key.type == TERMKEY_TYPE_MODEREPORT) { } else if (key.type == TERMKEY_TYPE_MODEREPORT) {
handle_modereport(input, &key); handle_modereport(input, &key);
} }
@ -578,22 +578,34 @@ static HandleState handle_bracketed_paste(TermInput *input)
return kNotApplicable; 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 FUNC_ATTR_NONNULL_ALL
{ {
const char *str = NULL; const char *str = NULL;
if (termkey_interpret_string(input->tk, key, &str) == TERMKEY_RES_KEY) { if (termkey_interpret_string(input->tk, key, &str) == TERMKEY_RES_KEY) {
assert(str != NULL); assert(str != NULL);
// Send an event to nvim core. This will update the v:termresponse variable and fire the // Send an event to nvim core. This will update the v:termresponse variable
// TermResponse event // and fire the TermResponse event
MAXSIZE_TEMP_ARRAY(args, 2); 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 // libtermkey strips the OSC/DCS bytes from the response. We add it back in
// consumers of v:termresponse can differentiate between OSC and CSI events. // so that downstream consumers of v:termresponse can differentiate between
// the two.
StringBuilder response = KV_INITIAL_VALUE; 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))); ADD_C(args, STRING_OBJ(cbuf_as_string(response.items, response.size)));
rpc_send_event(ui_client_channel_id, "nvim_ui_term_event", args); rpc_send_event(ui_client_channel_id, "nvim_ui_term_event", args);
kv_destroy(response); kv_destroy(response);