aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTill Bungert <tillbungert@gmail.com>2025-02-13 15:24:01 +0100
committerGitHub <noreply@github.com>2025-02-13 08:24:01 -0600
commit93480f7fbaa5b4e5418d95dd35005daa6142dbb9 (patch)
treec9e5660e83172c13dca7f00b2669581d9d7811b5
parente4c6e732fd042e879f1f2b6bbef169e5dfbbde8a (diff)
downloadrneovim-93480f7fbaa5b4e5418d95dd35005daa6142dbb9.tar.gz
rneovim-93480f7fbaa5b4e5418d95dd35005daa6142dbb9.tar.bz2
rneovim-93480f7fbaa5b4e5418d95dd35005daa6142dbb9.zip
feat(term): trigger TermRequest for APC (#32407)
Co-authored-by: Gregory Anders <greg@gpanders.com> Co-authored-by: zeertzjq <zeertzjq@outlook.com>
-rw-r--r--runtime/doc/autocmd.txt4
-rw-r--r--runtime/doc/news.txt2
-rw-r--r--runtime/doc/vvars.txt2
-rw-r--r--runtime/lua/vim/_meta/vvars.lua2
-rw-r--r--src/nvim/terminal.c60
-rw-r--r--src/nvim/vvars.lua2
-rw-r--r--test/functional/terminal/buffer_spec.lua11
7 files changed, 67 insertions, 16 deletions
diff --git a/runtime/doc/autocmd.txt b/runtime/doc/autocmd.txt
index a82bac5de5..3ffbdf310f 100644
--- a/runtime/doc/autocmd.txt
+++ b/runtime/doc/autocmd.txt
@@ -1004,8 +1004,8 @@ TermClose When a |terminal| job ends.
Sets these |v:event| keys:
status
*TermRequest*
-TermRequest When a |:terminal| child process emits an OSC
- or DCS sequence. Sets |v:termrequest|. The
+TermRequest When a |:terminal| child process emits an OSC,
+ DCS or APC sequence. Sets |v:termrequest|. The
|event-data| is the request string.
*TermResponse*
TermResponse When Nvim receives an OSC or DCS response from
diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt
index cfda05e6f5..c98084adb6 100644
--- a/runtime/doc/news.txt
+++ b/runtime/doc/news.txt
@@ -372,6 +372,8 @@ TERMINAL
• The |terminal| has experimental support for the Kitty keyboard protocol
(sometimes called "CSI u" key encoding). Only the "Disambiguate escape
codes" mode is currently supported.
+• The |terminal| emits a |TermRequest| autocommand event when the child process
+ emits an APC control sequence.
TREESITTER
diff --git a/runtime/doc/vvars.txt b/runtime/doc/vvars.txt
index 0ebb54e38a..e4f6b10ef7 100644
--- a/runtime/doc/vvars.txt
+++ b/runtime/doc/vvars.txt
@@ -663,7 +663,7 @@ v:t_string Value of |String| type. Read-only. See: |type()|
*v:termrequest* *termrequest-variable*
v:termrequest
- The value of the most recent OSC or DCS control sequence
+ The value of the most recent OSC, DCS or APC 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.
diff --git a/runtime/lua/vim/_meta/vvars.lua b/runtime/lua/vim/_meta/vvars.lua
index c1b8695bbf..d7a80911c6 100644
--- a/runtime/lua/vim/_meta/vvars.lua
+++ b/runtime/lua/vim/_meta/vvars.lua
@@ -700,7 +700,7 @@ vim.v.t_number = ...
--- @type integer
vim.v.t_string = ...
---- The value of the most recent OSC or DCS control sequence
+--- The value of the most recent OSC, DCS or APC 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.
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index 897c393488..959126dd24 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -183,8 +183,10 @@ struct terminal {
bool color_set[16];
- char *selection_buffer; /// libvterm selection buffer
- StringBuilder selection; /// Growable array containing full selection data
+ char *selection_buffer; ///< libvterm selection buffer
+ StringBuilder selection; ///< Growable array containing full selection data
+
+ StringBuilder termrequest_buffer; ///< Growable array containing unfinished request payload
size_t refcount; // reference count
};
@@ -307,15 +309,22 @@ static int on_osc(int command, VTermStringFragment frag, void *user)
return 1;
}
- StringBuilder request = KV_INITIAL_VALUE;
- kv_printf(request, "\x1b]%d;", command);
- kv_concat_len(request, frag.str, frag.len);
- schedule_termrequest(term, request.items, request.size);
+ if (frag.initial) {
+ kv_size(term->termrequest_buffer) = 0;
+ kv_printf(term->termrequest_buffer, "\x1b]%d;", command);
+ }
+ kv_concat_len(term->termrequest_buffer, frag.str, frag.len);
+ if (frag.final) {
+ char *payload = xmemdup(term->termrequest_buffer.items, term->termrequest_buffer.size);
+ schedule_termrequest(user, payload, term->termrequest_buffer.size);
+ }
return 1;
}
static int on_dcs(const char *command, size_t commandlen, VTermStringFragment frag, void *user)
{
+ Terminal *term = user;
+
if (command == NULL || frag.str == NULL) {
return 0;
}
@@ -323,10 +332,38 @@ static int on_dcs(const char *command, size_t commandlen, VTermStringFragment fr
return 1;
}
- StringBuilder request = KV_INITIAL_VALUE;
- kv_printf(request, "\x1bP%*s", (int)commandlen, command);
- kv_concat_len(request, frag.str, frag.len);
- schedule_termrequest(user, request.items, request.size);
+ if (frag.initial) {
+ kv_size(term->termrequest_buffer) = 0;
+ kv_printf(term->termrequest_buffer, "\x1bP%*s", (int)commandlen, command);
+ }
+ kv_concat_len(term->termrequest_buffer, frag.str, frag.len);
+ if (frag.final) {
+ char *payload = xmemdup(term->termrequest_buffer.items, term->termrequest_buffer.size);
+ schedule_termrequest(user, payload, term->termrequest_buffer.size);
+ }
+ return 1;
+}
+
+static int on_apc(VTermStringFragment frag, void *user)
+{
+ Terminal *term = user;
+ if (frag.str == NULL || frag.len == 0) {
+ return 0;
+ }
+
+ if (!has_event(EVENT_TERMREQUEST)) {
+ return 1;
+ }
+
+ if (frag.initial) {
+ kv_size(term->termrequest_buffer) = 0;
+ kv_printf(term->termrequest_buffer, "\x1b_");
+ }
+ kv_concat_len(term->termrequest_buffer, frag.str, frag.len);
+ if (frag.final) {
+ char *payload = xmemdup(term->termrequest_buffer.items, term->termrequest_buffer.size);
+ schedule_termrequest(user, payload, term->termrequest_buffer.size);
+ }
return 1;
}
@@ -335,7 +372,7 @@ static VTermStateFallbacks vterm_fallbacks = {
.csi = NULL,
.osc = on_osc,
.dcs = on_dcs,
- .apc = NULL,
+ .apc = on_apc,
.pm = NULL,
.sos = NULL,
};
@@ -924,6 +961,7 @@ void terminal_destroy(Terminal **termpp)
xfree(term->title);
xfree(term->selection_buffer);
kv_destroy(term->selection);
+ kv_destroy(term->termrequest_buffer);
vterm_free(term->vt);
xfree(term);
*termpp = NULL; // coverity[dead-store]
diff --git a/src/nvim/vvars.lua b/src/nvim/vvars.lua
index 056e281c0b..55f979364f 100644
--- a/src/nvim/vvars.lua
+++ b/src/nvim/vvars.lua
@@ -799,7 +799,7 @@ M.vars = {
termrequest = {
type = 'string',
desc = [=[
- The value of the most recent OSC or DCS control sequence
+ The value of the most recent OSC, DCS or APC 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.
diff --git a/test/functional/terminal/buffer_spec.lua b/test/functional/terminal/buffer_spec.lua
index 4635259e33..f2d679bd5d 100644
--- a/test/functional/terminal/buffer_spec.lua
+++ b/test/functional/terminal/buffer_spec.lua
@@ -350,6 +350,17 @@ describe(':terminal buffer', function()
eq(termbuf, eval('g:termbuf'))
end)
+ it('emits TermRequest events for APC', function()
+ local term = api.nvim_open_term(0, {})
+
+ -- cwd will be inserted in a file URI, which cannot contain backs
+ local cwd = t.fix_slashes(fn.getcwd())
+ local parent = cwd:match('^(.+/)')
+ local expected = '\027_Gfile://host' .. parent
+ api.nvim_chan_send(term, string.format('%s\027\\', expected))
+ eq(expected, eval('v:termrequest'))
+ end)
+
it('TermRequest synchronization #27572', function()
command('autocmd! nvim.terminal TermRequest')
local term = exec_lua([[