mirror of
https://github.com/neovim/neovim.git
synced 2024-12-23 20:55:18 -07:00
fix(terminal): block input when there is pending TermRequest (#27589)
This commit is contained in:
parent
cb5ae22eab
commit
99288ecc77
@ -163,6 +163,9 @@ struct terminal {
|
|||||||
|
|
||||||
bool color_set[16];
|
bool color_set[16];
|
||||||
|
|
||||||
|
// When there is a pending TermRequest autocommand, block and store input.
|
||||||
|
StringBuilder *pending_send;
|
||||||
|
|
||||||
size_t refcount; // reference count
|
size_t refcount; // reference count
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -178,11 +181,12 @@ static VTermScreenCallbacks vterm_screen_callbacks = {
|
|||||||
|
|
||||||
static Set(ptr_t) invalidated_terminals = SET_INIT;
|
static Set(ptr_t) invalidated_terminals = SET_INIT;
|
||||||
|
|
||||||
static void emit_term_request(void **argv)
|
static void emit_termrequest(void **argv)
|
||||||
{
|
{
|
||||||
char *payload = argv[0];
|
Terminal *term = argv[0];
|
||||||
size_t payload_length = (size_t)argv[1];
|
char *payload = argv[1];
|
||||||
Terminal *term = argv[2];
|
size_t payload_length = (size_t)argv[2];
|
||||||
|
StringBuilder *pending_send = argv[3];
|
||||||
|
|
||||||
buf_T *buf = handle_get_buffer(term->buf_handle);
|
buf_T *buf = handle_get_buffer(term->buf_handle);
|
||||||
String termrequest = { .data = payload, .size = payload_length };
|
String termrequest = { .data = payload, .size = payload_length };
|
||||||
@ -190,6 +194,25 @@ static void emit_term_request(void **argv)
|
|||||||
set_vim_var_string(VV_TERMREQUEST, payload, (ptrdiff_t)payload_length);
|
set_vim_var_string(VV_TERMREQUEST, payload, (ptrdiff_t)payload_length);
|
||||||
apply_autocmds_group(EVENT_TERMREQUEST, NULL, NULL, false, AUGROUP_ALL, buf, NULL, &data);
|
apply_autocmds_group(EVENT_TERMREQUEST, NULL, NULL, false, AUGROUP_ALL, buf, NULL, &data);
|
||||||
xfree(payload);
|
xfree(payload);
|
||||||
|
|
||||||
|
StringBuilder *term_pending_send = term->pending_send;
|
||||||
|
term->pending_send = NULL;
|
||||||
|
if (kv_size(*pending_send)) {
|
||||||
|
terminal_send(term, pending_send->items, pending_send->size);
|
||||||
|
kv_destroy(*pending_send);
|
||||||
|
}
|
||||||
|
if (term_pending_send != pending_send) {
|
||||||
|
term->pending_send = term_pending_send;
|
||||||
|
}
|
||||||
|
xfree(pending_send);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void schedule_termrequest(Terminal *term, char *payload, size_t payload_length)
|
||||||
|
{
|
||||||
|
term->pending_send = xmalloc(sizeof(StringBuilder));
|
||||||
|
kv_init(*term->pending_send);
|
||||||
|
multiqueue_put(main_loop.events, emit_termrequest, term, payload, (void *)payload_length,
|
||||||
|
term->pending_send);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int on_osc(int command, VTermStringFragment frag, void *user)
|
static int on_osc(int command, VTermStringFragment frag, void *user)
|
||||||
@ -197,24 +220,30 @@ static int on_osc(int command, VTermStringFragment frag, void *user)
|
|||||||
if (frag.str == NULL) {
|
if (frag.str == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (!has_event(EVENT_TERMREQUEST)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
StringBuilder request = KV_INITIAL_VALUE;
|
StringBuilder request = KV_INITIAL_VALUE;
|
||||||
kv_printf(request, "\x1b]%d;", command);
|
kv_printf(request, "\x1b]%d;", command);
|
||||||
kv_concat_len(request, frag.str, frag.len);
|
kv_concat_len(request, frag.str, frag.len);
|
||||||
multiqueue_put(main_loop.events, emit_term_request, request.items, (void *)request.size, user);
|
schedule_termrequest(user, request.items, request.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)
|
||||||
{
|
{
|
||||||
if ((command == NULL) || (frag.str == NULL)) {
|
if (command == NULL || frag.str == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (!has_event(EVENT_TERMREQUEST)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
StringBuilder request = KV_INITIAL_VALUE;
|
StringBuilder request = KV_INITIAL_VALUE;
|
||||||
kv_printf(request, "\x1bP%*s", (int)commandlen, command);
|
kv_printf(request, "\x1bP%*s", (int)commandlen, command);
|
||||||
kv_concat_len(request, frag.str, frag.len);
|
kv_concat_len(request, frag.str, frag.len);
|
||||||
multiqueue_put(main_loop.events, emit_term_request, request.items, (void *)request.size, user);
|
schedule_termrequest(user, request.items, request.size);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -747,6 +776,10 @@ static void terminal_send(Terminal *term, const char *data, size_t size)
|
|||||||
if (term->closed) {
|
if (term->closed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (term->pending_send) {
|
||||||
|
kv_concat_len(*term->pending_send, data, size);
|
||||||
|
return;
|
||||||
|
}
|
||||||
term->opts.write_cb(data, size, term->opts.data);
|
term->opts.write_cb(data, size, term->opts.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -319,8 +319,7 @@ describe(':terminal buffer', function()
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
it('emits TermRequest events #26972', function()
|
it('emits TermRequest events #26972', function()
|
||||||
command('split')
|
command('new')
|
||||||
command('enew')
|
|
||||||
local term = api.nvim_open_term(0, {})
|
local term = api.nvim_open_term(0, {})
|
||||||
local termbuf = api.nvim_get_current_buf()
|
local termbuf = api.nvim_get_current_buf()
|
||||||
|
|
||||||
@ -336,6 +335,35 @@ describe(':terminal buffer', function()
|
|||||||
eq(expected, eval('v:termrequest'))
|
eq(expected, eval('v:termrequest'))
|
||||||
eq(termbuf, eval('g:termbuf'))
|
eq(termbuf, eval('g:termbuf'))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
it('TermReqeust synchronization #27572', function()
|
||||||
|
command('new')
|
||||||
|
command('autocmd! nvim_terminal TermRequest')
|
||||||
|
local term = exec_lua([[
|
||||||
|
_G.input = {}
|
||||||
|
local term = vim.api.nvim_open_term(0, {
|
||||||
|
on_input = function(_, _, _, data)
|
||||||
|
table.insert(_G.input, data)
|
||||||
|
end,
|
||||||
|
force_crlf = false,
|
||||||
|
})
|
||||||
|
vim.api.nvim_create_autocmd('TermRequest', {
|
||||||
|
callback = function(args)
|
||||||
|
if args.data == '\027]11;?' then
|
||||||
|
table.insert(_G.input, '\027]11;rgb:0000/0000/0000\027\\')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
})
|
||||||
|
return term
|
||||||
|
]])
|
||||||
|
api.nvim_chan_send(term, '\027]11;?\007\027[5n\027]11;?\007\027[5n')
|
||||||
|
eq({
|
||||||
|
'\027]11;rgb:0000/0000/0000\027\\',
|
||||||
|
'\027[0n',
|
||||||
|
'\027]11;rgb:0000/0000/0000\027\\',
|
||||||
|
'\027[0n',
|
||||||
|
}, exec_lua('return _G.input'))
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
describe('No heap-buffer-overflow when using', function()
|
describe('No heap-buffer-overflow when using', function()
|
||||||
|
Loading…
Reference in New Issue
Block a user