This commit is contained in:
Gregory Anders 2024-12-18 22:45:17 -03:00 committed by GitHub
commit 6ba2e1b34d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 74 additions and 28 deletions

View File

@ -1006,21 +1006,30 @@ TermClose When a |terminal| job ends.
*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 or DCS sequence. Sets |v:termrequest|. The
|event-data| is the request string. |event-data| is a table with the following
fields:
payload: the received sequence
row: cursor row
col: cursor column
*TermResponse* *TermResponse*
TermResponse When Nvim receives an OSC or DCS response from TermResponse When Nvim receives an OSC or DCS response from
the host terminal. Sets |v:termresponse|. The the host terminal. Sets |v:termresponse|. The
|event-data| is the response string. May be |event-data| is a table with the following fields:
triggered during another event (file I/O,
a shell command, or anything else that takes payload: the received sequence
time). Example: >lua
May be triggered during another event (file
I/O, a shell command, or anything else that
takes time). Example: >lua
-- Query the terminal palette for the RGB value of color 1 -- Query the terminal palette for the RGB value of color 1
-- (red) using OSC 4 -- (red) using OSC 4
vim.api.nvim_create_autocmd('TermResponse', { vim.api.nvim_create_autocmd('TermResponse', {
once = true, once = true,
callback = function(args) callback = function(args)
local resp = args.data local resp = args.data.payload
local r, g, b = resp:match("\027%]4;1;rgb:(%w+)/(%w+)/(%w+)") local r, g, b = resp:match("\027%]4;1;rgb:(%w+)/(%w+)/(%w+)")
end, end,
}) })

View File

@ -86,6 +86,10 @@ EVENTS
• |vim.ui_attach()| callbacks for |ui-messages| `msg_show` events are executed in • |vim.ui_attach()| callbacks for |ui-messages| `msg_show` events are executed in
|api-fast| context. |api-fast| context.
• |TermRequest| and |TermResponse| |event-data| is now a table. The "payload"
field contains the received sequence. |TermRequest| also contains "row" and
"col" fields indicating the cursor's position when the sequence was
received.
HIGHLIGHTS HIGHLIGHTS
@ -294,6 +298,8 @@ TERMINAL
means that the |TermCursorNC| highlight group is no longer supported: an means that the |TermCursorNC| highlight group is no longer supported: an
unfocused terminal window will have no cursor at all (so there is nothing to unfocused terminal window will have no cursor at all (so there is nothing to
highlight). highlight).
• |TermRequest| has "row" and "col" fields in its |event-data| indicating the
cursor position when the sequence was received.
TREESITTER TREESITTER

View File

@ -144,8 +144,8 @@ directory indicated in the request. >lua
vim.api.nvim_create_autocmd({ 'TermRequest' }, { vim.api.nvim_create_autocmd({ 'TermRequest' }, {
desc = 'Handles OSC 7 dir change requests', desc = 'Handles OSC 7 dir change requests',
callback = function(ev) callback = function(ev)
if string.sub(vim.v.termrequest, 1, 4) == '\x1b]7;' then if string.sub(ev.data.payload, 1, 4) == '\x1b]7;' then
local dir = string.gsub(vim.v.termrequest, '\x1b]7;file://[^/]*', '') local dir = string.gsub(ev.data.payload, '\x1b]7;file://[^/]*', '')
if vim.fn.isdirectory(dir) == 0 then if vim.fn.isdirectory(dir) == 0 then
vim.notify('invalid dir: '..dir) vim.notify('invalid dir: '..dir)
return return

View File

@ -205,7 +205,9 @@ local function try_query_terminal_color(color)
once = true, once = true,
callback = function(args) callback = function(args)
hex = '#' hex = '#'
.. table.concat({ args.data:match('\027%]%d+;%d*;?rgb:(%w%w)%w%w/(%w%w)%w%w/(%w%w)%w%w') }) .. table.concat({
args.data.payload:match('\027%]%d+;%d*;?rgb:(%w%w)%w%w/(%w%w)%w%w/(%w%w)%w%w'),
})
end, end,
}) })
if type(color) == 'number' then if type(color) == 'number' then

View File

@ -463,8 +463,8 @@ do
if channel == 0 then if channel == 0 then
return return
end end
local fg_request = args.data == '\027]10;?' local fg_request = args.data.payload == '\027]10;?'
local bg_request = args.data == '\027]11;?' local bg_request = args.data.payload == '\027]11;?'
if fg_request or bg_request then if fg_request or bg_request then
-- WARN: This does not return the actual foreground/background color, -- WARN: This does not return the actual foreground/background color,
-- but rather returns: -- but rather returns:
@ -660,7 +660,7 @@ do
nested = true, nested = true,
desc = "Update the value of 'background' automatically based on the terminal emulator's background color", desc = "Update the value of 'background' automatically based on the terminal emulator's background color",
callback = function(args) callback = function(args)
local resp = args.data ---@type string local resp = args.data.payload ---@type string
local r, g, b = parseosc11(resp) local r, g, b = parseosc11(resp)
if r and g and b then if r and g and b then
local rr = parsecolor(r) local rr = parsecolor(r)
@ -736,7 +736,7 @@ do
group = group, group = group,
nested = true, nested = true,
callback = function(args) callback = function(args)
local resp = args.data ---@type string local resp = args.data.payload ---@type string
local decrqss = resp:match('^\027P1%$r([%d;:]+)m$') local decrqss = resp:match('^\027P1%$r([%d;:]+)m$')
if decrqss then if decrqss then

View File

@ -34,7 +34,7 @@ function M.query(caps, cb)
local id = vim.api.nvim_create_autocmd('TermResponse', { local id = vim.api.nvim_create_autocmd('TermResponse', {
nested = true, nested = true,
callback = function(args) callback = function(args)
local resp = args.data ---@type string local resp = args.data.payload ---@type string
local k, rest = resp:match('^\027P1%+r(%x+)(.*)$') local k, rest = resp:match('^\027P1%+r(%x+)(.*)$')
if k and rest then if k and rest then
local cap = vim.text.hexdecode(k) local cap = vim.text.hexdecode(k)

View File

@ -25,7 +25,7 @@ function M.paste(reg)
local contents = nil local contents = nil
local id = vim.api.nvim_create_autocmd('TermResponse', { local id = vim.api.nvim_create_autocmd('TermResponse', {
callback = function(args) callback = function(args)
local resp = args.data ---@type string local resp = args.data.payload ---@type string
local encoded = resp:match('\027%]52;%w?;([A-Za-z0-9+/=]*)') local encoded = resp:match('\027%]52;%w?;([A-Za-z0-9+/=]*)')
if encoded then if encoded then
contents = vim.base64.decode(encoded) contents = vim.base64.decode(encoded)

View File

@ -505,7 +505,11 @@ void nvim_ui_term_event(uint64_t channel_id, String event, Object value, Error *
const String termresponse = value.data.string; const String termresponse = value.data.string;
set_vim_var_string(VV_TERMRESPONSE, termresponse.data, (ptrdiff_t)termresponse.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);
MAXSIZE_TEMP_DICT(data, 1);
PUT_C(data, "payload", value);
apply_autocmds_group(EVENT_TERMRESPONSE, NULL, NULL, false, AUGROUP_ALL, NULL, NULL,
&DICT_OBJ(data));
} }
} }

View File

@ -204,12 +204,20 @@ static void emit_termrequest(void **argv)
char *payload = argv[1]; char *payload = argv[1];
size_t payload_length = (size_t)argv[2]; size_t payload_length = (size_t)argv[2];
StringBuilder *pending_send = argv[3]; StringBuilder *pending_send = argv[3];
int row = (int)(intptr_t)argv[4];
int col = (int)(intptr_t)argv[5];
set_vim_var_string(VV_TERMREQUEST, payload, (ptrdiff_t)payload_length);
MAXSIZE_TEMP_DICT(data, 3);
String termrequest = { .data = payload, .size = payload_length };
PUT_C(data, "payload", STRING_OBJ(termrequest));
PUT_C(data, "row", INTEGER_OBJ(row));
PUT_C(data, "col", INTEGER_OBJ(col));
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 }; apply_autocmds_group(EVENT_TERMREQUEST, NULL, NULL, false, AUGROUP_ALL, buf, NULL,
Object data = STRING_OBJ(termrequest); &DICT_OBJ(data));
set_vim_var_string(VV_TERMREQUEST, payload, (ptrdiff_t)payload_length);
apply_autocmds_group(EVENT_TERMREQUEST, NULL, NULL, false, AUGROUP_ALL, buf, NULL, &data);
xfree(payload); xfree(payload);
StringBuilder *term_pending_send = term->pending.send; StringBuilder *term_pending_send = term->pending.send;
@ -229,7 +237,8 @@ static void schedule_termrequest(Terminal *term, char *payload, size_t payload_l
term->pending.send = xmalloc(sizeof(StringBuilder)); term->pending.send = xmalloc(sizeof(StringBuilder));
kv_init(*term->pending.send); kv_init(*term->pending.send);
multiqueue_put(main_loop.events, emit_termrequest, term, payload, (void *)payload_length, multiqueue_put(main_loop.events, emit_termrequest, term, payload, (void *)payload_length,
term->pending.send); term->pending.send, (void *)(intptr_t)term->cursor.row,
(void *)(intptr_t)term->cursor.col);
} }
static int parse_osc8(VTermStringFragment frag, int *attr) static int parse_osc8(VTermStringFragment frag, int *attr)

View File

@ -362,7 +362,7 @@ describe(':terminal buffer', function()
}) })
vim.api.nvim_create_autocmd('TermRequest', { vim.api.nvim_create_autocmd('TermRequest', {
callback = function(args) callback = function(args)
if args.data == '\027]11;?' then if args.data.payload == '\027]11;?' then
table.insert(_G.input, '\027]11;rgb:0000/0000/0000\027\\') table.insert(_G.input, '\027]11;rgb:0000/0000/0000\027\\')
end end
end end
@ -378,6 +378,22 @@ describe(':terminal buffer', function()
}, exec_lua('return _G.input')) }, exec_lua('return _G.input'))
end) end)
it('TermRequest includes cursor position #31609', function()
command('autocmd! nvim_terminal TermRequest')
local term = exec_lua([[
_G.cursor = {}
local term = vim.api.nvim_open_term(0, {})
vim.api.nvim_create_autocmd('TermRequest', {
callback = function(args)
_G.cursor = { row = args.data.row, col = args.data.col }
end
})
return term
]])
api.nvim_chan_send(term, 'Hello\nworld!\027]133;D\027\\')
eq({ row = 1, col = 6 }, exec_lua('return _G.cursor'))
end)
it('no heap-buffer-overflow when using termopen(echo) #3161', function() it('no heap-buffer-overflow when using termopen(echo) #3161', function()
local testfilename = 'Xtestfile-functional-terminal-buffers_spec' local testfilename = 'Xtestfile-functional-terminal-buffers_spec'
write_file(testfilename, 'aaaaaaaaaaaaaaaaaaaaaaaaaaaa') write_file(testfilename, 'aaaaaaaaaaaaaaaaaaaaaaaaaaaa')

View File

@ -92,7 +92,7 @@ describe('TUI', function()
_G.termresponse = nil _G.termresponse = nil
vim.api.nvim_create_autocmd('TermResponse', { vim.api.nvim_create_autocmd('TermResponse', {
once = true, once = true,
callback = function(ev) _G.termresponse = ev.data end, callback = function(ev) _G.termresponse = ev.data.payload end,
}) })
]]) ]])
feed_data('\027P0$r\027\\') feed_data('\027P0$r\027\\')
@ -2076,7 +2076,7 @@ describe('TUI', function()
vim.api.nvim_create_autocmd('TermRequest', { vim.api.nvim_create_autocmd('TermRequest', {
buffer = buf, buffer = buf,
callback = function(args) callback = function(args)
local req = args.data local req = args.data.payload
if not req then if not req then
return return
end end
@ -3070,7 +3070,7 @@ describe('TUI', function()
exec_lua([[ exec_lua([[
vim.api.nvim_create_autocmd('TermRequest', { vim.api.nvim_create_autocmd('TermRequest', {
callback = function(args) callback = function(args)
local req = args.data local req = args.data.payload
local payload = req:match('^\027P%+q([%x;]+)$') local payload = req:match('^\027P%+q([%x;]+)$')
if payload then if payload then
local t = {} local t = {}
@ -3124,7 +3124,7 @@ describe('TUI', function()
exec_lua([[ exec_lua([[
vim.api.nvim_create_autocmd('TermRequest', { vim.api.nvim_create_autocmd('TermRequest', {
callback = function(args) callback = function(args)
local req = args.data local req = args.data.payload
vim.g.termrequest = req vim.g.termrequest = req
local xtgettcap = req:match('^\027P%+q([%x;]+)$') local xtgettcap = req:match('^\027P%+q([%x;]+)$')
if xtgettcap then if xtgettcap then
@ -3179,7 +3179,7 @@ describe('TUI', function()
exec_lua([[ exec_lua([[
vim.api.nvim_create_autocmd('TermRequest', { vim.api.nvim_create_autocmd('TermRequest', {
callback = function(args) callback = function(args)
local req = args.data local req = args.data.payload
local payload = req:match('^\027P%+q([%x;]+)$') local payload = req:match('^\027P%+q([%x;]+)$')
if payload and vim.text.hexdecode(payload) == 'Ms' then if payload and vim.text.hexdecode(payload) == 'Ms' then
vim.g.xtgettcap = 'Ms' vim.g.xtgettcap = 'Ms'
@ -3269,7 +3269,7 @@ describe('TUI bg color', function()
exec_lua([[ exec_lua([[
vim.api.nvim_create_autocmd('TermRequest', { vim.api.nvim_create_autocmd('TermRequest', {
callback = function(args) callback = function(args)
local req = args.data local req = args.data.payload
if req == '\027]11;?' then if req == '\027]11;?' then
vim.g.oscrequest = true vim.g.oscrequest = true
return true return true