diff options
author | Ghjuvan Lacambre <code@lacamb.re> | 2024-01-09 15:27:56 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-01-09 08:27:56 -0600 |
commit | beca827212b106114c371f8bb61aa1a50810062f (patch) | |
tree | 8c48282193fef8f58768a03663df94bf00b8aa29 /src | |
parent | f40df63bdca33d343cada6ceaafbc8b765ed7cc6 (diff) | |
download | rneovim-beca827212b106114c371f8bb61aa1a50810062f.tar.gz rneovim-beca827212b106114c371f8bb61aa1a50810062f.tar.bz2 rneovim-beca827212b106114c371f8bb61aa1a50810062f.zip |
feat(terminal): trigger TermRequest autocommand events (#22159)
This commit implements a new TermRequest autocommand event and has Neovim
emit this event when children of terminal buffers emit an OSC or DCS sequence
libvterm does not handle.
The TermRequest autocommand event has additional data in the
v:termrequest variable.
Co-authored-by: Gregory Anders <greg@gpanders.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/auevents.lua | 2 | ||||
-rw-r--r-- | src/nvim/eval.c | 1 | ||||
-rw-r--r-- | src/nvim/eval.h | 1 | ||||
-rw-r--r-- | src/nvim/terminal.c | 49 | ||||
-rw-r--r-- | src/nvim/vvars.lua | 12 |
5 files changed, 64 insertions, 1 deletions
diff --git a/src/nvim/auevents.lua b/src/nvim/auevents.lua index 11d1597236..b931907fe3 100644 --- a/src/nvim/auevents.lua +++ b/src/nvim/auevents.lua @@ -109,6 +109,7 @@ return { 'TermEnter', -- after entering Terminal mode 'TermLeave', -- after leaving Terminal mode 'TermOpen', -- after opening a terminal buffer + 'TermRequest', -- after an unhandled OSC sequence is emitted 'TermResponse', -- after setting "v:termresponse" 'TextChanged', -- text was modified 'TextChangedI', -- text was modified in Insert mode(no popup) @@ -166,6 +167,7 @@ return { TabNewEntered = true, TermClose = true, TermOpen = true, + TermRequest = true, UIEnter = true, UILeave = true, }, diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 5069f00df0..451e258356 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -185,6 +185,7 @@ static struct vimvar { VV(VV_VERSION, "version", VAR_NUMBER, VV_COMPAT + VV_RO), VV(VV_LNUM, "lnum", VAR_NUMBER, VV_RO_SBX), VV(VV_TERMRESPONSE, "termresponse", VAR_STRING, VV_RO), + VV(VV_TERMREQUEST, "termrequest", VAR_STRING, VV_RO), VV(VV_FNAME, "fname", VAR_STRING, VV_RO), VV(VV_LANG, "lang", VAR_STRING, VV_RO), VV(VV_LC_TIME, "lc_time", VAR_STRING, VV_RO), diff --git a/src/nvim/eval.h b/src/nvim/eval.h index c46a895c06..abe2685424 100644 --- a/src/nvim/eval.h +++ b/src/nvim/eval.h @@ -86,6 +86,7 @@ typedef enum { VV_THIS_SESSION, VV_VERSION, VV_LNUM, + VV_TERMREQUEST, VV_TERMRESPONSE, VV_FNAME, VV_LANG, diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index c6a2cb3354..ee482f7104 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -169,6 +169,54 @@ static VTermScreenCallbacks vterm_screen_callbacks = { static Set(ptr_t) invalidated_terminals = SET_INIT; +static void emit_term_request(void **argv) +{ + char *payload = argv[0]; + size_t payload_length = (size_t)argv[1]; + + String termrequest = { .data = payload, .size = payload_length }; + Object data = STRING_OBJ(termrequest); + set_vim_var_string(VV_TERMREQUEST, payload, (ptrdiff_t)payload_length); + apply_autocmds_group(EVENT_TERMREQUEST, NULL, NULL, false, AUGROUP_ALL, curbuf, NULL, &data); + xfree(payload); +} + +static int on_osc(int command, VTermStringFragment frag, void *user) +{ + if (frag.str == NULL) { + return 0; + } + + StringBuilder request = KV_INITIAL_VALUE; + kv_printf(request, "\x1b]%d;", command); + kv_concat_len(request, frag.str, frag.len); + multiqueue_put(main_loop.events, emit_term_request, request.items, (void *)request.size); + return 1; +} + +static int on_dcs(const char *command, size_t commandlen, VTermStringFragment frag, void *user) +{ + if ((command == NULL) || (frag.str == NULL)) { + return 0; + } + + StringBuilder request = KV_INITIAL_VALUE; + kv_printf(request, "\x1bP%*s", (int)commandlen, command); + kv_concat_len(request, frag.str, frag.len); + multiqueue_put(main_loop.events, emit_term_request, request.items, (void *)request.size); + return 1; +} + +static VTermStateFallbacks vterm_fallbacks = { + .control = NULL, + .csi = NULL, + .osc = on_osc, + .dcs = on_dcs, + .apc = NULL, + .pm = NULL, + .sos = NULL, +}; + void terminal_init(void) { time_watcher_init(&main_loop, &refresh_timer, NULL); @@ -222,6 +270,7 @@ void terminal_open(Terminal **termpp, buf_T *buf, TerminalOptions opts) vterm_screen_enable_reflow(rv->vts, true); // delete empty lines at the end of the buffer vterm_screen_set_callbacks(rv->vts, &vterm_screen_callbacks, rv); + vterm_screen_set_unrecognised_fallbacks(rv->vts, &vterm_fallbacks, rv); vterm_screen_set_damage_merge(rv->vts, VTERM_DAMAGE_SCROLL); vterm_screen_reset(rv->vts, 1); vterm_output_set_callback(rv->vt, term_output_callback, rv); diff --git a/src/nvim/vvars.lua b/src/nvim/vvars.lua index d1b5e13401..6410df1a57 100644 --- a/src/nvim/vvars.lua +++ b/src/nvim/vvars.lua @@ -770,13 +770,23 @@ M.vars = { desc = 'Value of |String| type. Read-only. See: |type()|', }, termresponse = { + type = 'string', desc = [=[ - The value of the most recent OSC or DCS escape sequence + The value of the most recent OSC or DCS control sequence received by Nvim from the terminal. This can be read in a |TermResponse| event handler after querying the terminal using another escape sequence. ]=], }, + termrequest = { + type = 'string', + desc = [=[ + The value of the most recent OSC or DCS control sequence + sent from a process running in the embedded |terminal|. + This can be read in a |TermRequest| event handler to respond + to queries from embedded applications. + ]=], + }, testing = { desc = [=[ Must be set before using `test_garbagecollect_now()`. |