mirror of
https://github.com/neovim/neovim.git
synced 2025-10-05 17:36:29 +00:00
fix(terminal): handle OSC 8 split into multiple fragments
Also fix off-by-one size passed to xmemdupz().
This commit is contained in:
@@ -279,19 +279,19 @@ static void schedule_termrequest(Terminal *term, char *sequence, size_t sequence
|
|||||||
(void *)(intptr_t)term->cursor.col);
|
(void *)(intptr_t)term->cursor.col);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_osc8(VTermStringFragment frag, int *attr)
|
static int parse_osc8(const char *str, size_t len, int *attr)
|
||||||
FUNC_ATTR_NONNULL_ALL
|
FUNC_ATTR_NONNULL_ALL
|
||||||
{
|
{
|
||||||
// Parse the URI from the OSC 8 sequence and add the URL to our URL set.
|
// Parse the URI from the OSC 8 sequence and add the URL to our URL set.
|
||||||
// Skip the ID, we don't use it (for now)
|
// Skip the ID, we don't use it (for now)
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
for (; i < frag.len; i++) {
|
for (; i < len; i++) {
|
||||||
if (frag.str[i] == ';') {
|
if (str[i] == ';') {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frag.str[i] != ';') {
|
if (str[i] != ';') {
|
||||||
// Invalid OSC sequence
|
// Invalid OSC sequence
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -299,14 +299,13 @@ static int parse_osc8(VTermStringFragment frag, int *attr)
|
|||||||
// Move past the semicolon
|
// Move past the semicolon
|
||||||
i++;
|
i++;
|
||||||
|
|
||||||
if (i >= frag.len) {
|
if (i >= len) {
|
||||||
// Empty OSC 8, no URL
|
// Empty OSC 8, no URL
|
||||||
*attr = 0;
|
*attr = 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *url = xmemdupz(&frag.str[i], frag.len - i + 1);
|
char *url = xmemdupz(str + i, len - i);
|
||||||
url[frag.len - i] = 0;
|
|
||||||
*attr = hl_add_url(0, url);
|
*attr = hl_add_url(0, url);
|
||||||
xfree(url);
|
xfree(url);
|
||||||
|
|
||||||
@@ -322,16 +321,7 @@ static int on_osc(int command, VTermStringFragment frag, void *user)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (command == 8) {
|
if (command != 8 && !has_event(EVENT_TERMREQUEST)) {
|
||||||
int attr = 0;
|
|
||||||
if (parse_osc8(frag, &attr)) {
|
|
||||||
VTermState *state = vterm_obtain_state(term->vt);
|
|
||||||
VTermValue value = { .number = attr };
|
|
||||||
vterm_state_set_penattr(state, VTERM_ATTR_URI, VTERM_VALUETYPE_INT, &value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!has_event(EVENT_TERMREQUEST)) {
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -341,8 +331,20 @@ static int on_osc(int command, VTermStringFragment frag, void *user)
|
|||||||
}
|
}
|
||||||
kv_concat_len(term->termrequest_buffer, frag.str, frag.len);
|
kv_concat_len(term->termrequest_buffer, frag.str, frag.len);
|
||||||
if (frag.final) {
|
if (frag.final) {
|
||||||
char *sequence = xmemdup(term->termrequest_buffer.items, term->termrequest_buffer.size);
|
if (command == 8) {
|
||||||
schedule_termrequest(user, sequence, term->termrequest_buffer.size);
|
int attr = 0;
|
||||||
|
const int off = STRLEN_LITERAL("\x1b]8;");
|
||||||
|
if (parse_osc8(term->termrequest_buffer.items + off,
|
||||||
|
term->termrequest_buffer.size - off, &attr)) {
|
||||||
|
VTermState *state = vterm_obtain_state(term->vt);
|
||||||
|
VTermValue value = { .number = attr };
|
||||||
|
vterm_state_set_penattr(state, VTERM_ATTR_URI, VTERM_VALUETYPE_INT, &value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (has_event(EVENT_TERMREQUEST)) {
|
||||||
|
char *sequence = xmemdup(term->termrequest_buffer.items, term->termrequest_buffer.size);
|
||||||
|
schedule_termrequest(user, sequence, term->termrequest_buffer.size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@@ -388,6 +388,19 @@ describe(':terminal', function()
|
|||||||
^This is an {100:example} of a link |
|
^This is an {100:example} of a link |
|
||||||
|*6
|
|*6
|
||||||
]])
|
]])
|
||||||
|
-- Also works if OSC 8 is split into multiple fragments.
|
||||||
|
api.nvim_chan_send(chan, '\nThis is another \027]8;;https')
|
||||||
|
n.poke_eventloop()
|
||||||
|
api.nvim_chan_send(chan, '://')
|
||||||
|
n.poke_eventloop()
|
||||||
|
api.nvim_chan_send(chan, 'example')
|
||||||
|
n.poke_eventloop()
|
||||||
|
api.nvim_chan_send(chan, '.com\027\\EXAMPLE\027]8;;\027\\ of a link')
|
||||||
|
screen:expect([[
|
||||||
|
^This is an {100:example} of a link |
|
||||||
|
This is another {100:EXAMPLE} of a link |
|
||||||
|
|*5
|
||||||
|
]])
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it('zoomout with large horizontal output #30374', function()
|
it('zoomout with large horizontal output #30374', function()
|
||||||
|
Reference in New Issue
Block a user