mirror of
https://github.com/neovim/neovim.git
synced 2025-09-06 03:18:16 +00:00
feat(term): trigger TermRequest for APC (#32407)
Co-authored-by: Gregory Anders <greg@gpanders.com> Co-authored-by: zeertzjq <zeertzjq@outlook.com>
This commit is contained in:
@@ -1004,8 +1004,8 @@ TermClose When a |terminal| job ends.
|
|||||||
Sets these |v:event| keys:
|
Sets these |v:event| keys:
|
||||||
status
|
status
|
||||||
*TermRequest*
|
*TermRequest*
|
||||||
TermRequest When a |:terminal| child process emits an OSC
|
TermRequest When a |:terminal| child process emits an OSC,
|
||||||
or DCS sequence. Sets |v:termrequest|. The
|
DCS or APC sequence. Sets |v:termrequest|. The
|
||||||
|event-data| is the request string.
|
|event-data| is the request string.
|
||||||
*TermResponse*
|
*TermResponse*
|
||||||
TermResponse When Nvim receives an OSC or DCS response from
|
TermResponse When Nvim receives an OSC or DCS response from
|
||||||
|
@@ -372,6 +372,8 @@ TERMINAL
|
|||||||
• The |terminal| has experimental support for the Kitty keyboard protocol
|
• The |terminal| has experimental support for the Kitty keyboard protocol
|
||||||
(sometimes called "CSI u" key encoding). Only the "Disambiguate escape
|
(sometimes called "CSI u" key encoding). Only the "Disambiguate escape
|
||||||
codes" mode is currently supported.
|
codes" mode is currently supported.
|
||||||
|
• The |terminal| emits a |TermRequest| autocommand event when the child process
|
||||||
|
emits an APC control sequence.
|
||||||
|
|
||||||
TREESITTER
|
TREESITTER
|
||||||
|
|
||||||
|
@@ -663,7 +663,7 @@ v:t_string Value of |String| type. Read-only. See: |type()|
|
|||||||
|
|
||||||
*v:termrequest* *termrequest-variable*
|
*v:termrequest* *termrequest-variable*
|
||||||
v:termrequest
|
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|.
|
sent from a process running in the embedded |terminal|.
|
||||||
This can be read in a |TermRequest| event handler to respond
|
This can be read in a |TermRequest| event handler to respond
|
||||||
to queries from embedded applications.
|
to queries from embedded applications.
|
||||||
|
2
runtime/lua/vim/_meta/vvars.lua
generated
2
runtime/lua/vim/_meta/vvars.lua
generated
@@ -700,7 +700,7 @@ vim.v.t_number = ...
|
|||||||
--- @type integer
|
--- @type integer
|
||||||
vim.v.t_string = ...
|
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`.
|
--- sent from a process running in the embedded `terminal`.
|
||||||
--- This can be read in a `TermRequest` event handler to respond
|
--- This can be read in a `TermRequest` event handler to respond
|
||||||
--- to queries from embedded applications.
|
--- to queries from embedded applications.
|
||||||
|
@@ -183,8 +183,10 @@ struct terminal {
|
|||||||
|
|
||||||
bool color_set[16];
|
bool color_set[16];
|
||||||
|
|
||||||
char *selection_buffer; /// libvterm selection buffer
|
char *selection_buffer; ///< libvterm selection buffer
|
||||||
StringBuilder selection; /// Growable array containing full selection data
|
StringBuilder selection; ///< Growable array containing full selection data
|
||||||
|
|
||||||
|
StringBuilder termrequest_buffer; ///< Growable array containing unfinished request payload
|
||||||
|
|
||||||
size_t refcount; // reference count
|
size_t refcount; // reference count
|
||||||
};
|
};
|
||||||
@@ -307,15 +309,22 @@ static int on_osc(int command, VTermStringFragment frag, void *user)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
StringBuilder request = KV_INITIAL_VALUE;
|
if (frag.initial) {
|
||||||
kv_printf(request, "\x1b]%d;", command);
|
kv_size(term->termrequest_buffer) = 0;
|
||||||
kv_concat_len(request, frag.str, frag.len);
|
kv_printf(term->termrequest_buffer, "\x1b]%d;", command);
|
||||||
schedule_termrequest(term, request.items, request.size);
|
}
|
||||||
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int on_dcs(const char *command, size_t commandlen, VTermStringFragment frag, void *user)
|
static int on_dcs(const char *command, size_t commandlen, VTermStringFragment frag, void *user)
|
||||||
{
|
{
|
||||||
|
Terminal *term = user;
|
||||||
|
|
||||||
if (command == NULL || frag.str == NULL) {
|
if (command == NULL || frag.str == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -323,10 +332,38 @@ static int on_dcs(const char *command, size_t commandlen, VTermStringFragment fr
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
StringBuilder request = KV_INITIAL_VALUE;
|
if (frag.initial) {
|
||||||
kv_printf(request, "\x1bP%*s", (int)commandlen, command);
|
kv_size(term->termrequest_buffer) = 0;
|
||||||
kv_concat_len(request, frag.str, frag.len);
|
kv_printf(term->termrequest_buffer, "\x1bP%*s", (int)commandlen, command);
|
||||||
schedule_termrequest(user, request.items, request.size);
|
}
|
||||||
|
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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -335,7 +372,7 @@ static VTermStateFallbacks vterm_fallbacks = {
|
|||||||
.csi = NULL,
|
.csi = NULL,
|
||||||
.osc = on_osc,
|
.osc = on_osc,
|
||||||
.dcs = on_dcs,
|
.dcs = on_dcs,
|
||||||
.apc = NULL,
|
.apc = on_apc,
|
||||||
.pm = NULL,
|
.pm = NULL,
|
||||||
.sos = NULL,
|
.sos = NULL,
|
||||||
};
|
};
|
||||||
@@ -924,6 +961,7 @@ void terminal_destroy(Terminal **termpp)
|
|||||||
xfree(term->title);
|
xfree(term->title);
|
||||||
xfree(term->selection_buffer);
|
xfree(term->selection_buffer);
|
||||||
kv_destroy(term->selection);
|
kv_destroy(term->selection);
|
||||||
|
kv_destroy(term->termrequest_buffer);
|
||||||
vterm_free(term->vt);
|
vterm_free(term->vt);
|
||||||
xfree(term);
|
xfree(term);
|
||||||
*termpp = NULL; // coverity[dead-store]
|
*termpp = NULL; // coverity[dead-store]
|
||||||
|
@@ -799,7 +799,7 @@ M.vars = {
|
|||||||
termrequest = {
|
termrequest = {
|
||||||
type = 'string',
|
type = 'string',
|
||||||
desc = [=[
|
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|.
|
sent from a process running in the embedded |terminal|.
|
||||||
This can be read in a |TermRequest| event handler to respond
|
This can be read in a |TermRequest| event handler to respond
|
||||||
to queries from embedded applications.
|
to queries from embedded applications.
|
||||||
|
@@ -350,6 +350,17 @@ describe(':terminal buffer', function()
|
|||||||
eq(termbuf, eval('g:termbuf'))
|
eq(termbuf, eval('g:termbuf'))
|
||||||
end)
|
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()
|
it('TermRequest synchronization #27572', function()
|
||||||
command('autocmd! nvim.terminal TermRequest')
|
command('autocmd! nvim.terminal TermRequest')
|
||||||
local term = exec_lua([[
|
local term = exec_lua([[
|
||||||
|
Reference in New Issue
Block a user