fix(tui): set id parameter in OSC 8 sequences (#29847)

The id parameter is used to communicate to the terminal that two URLs
are the same. Without an id, the terminal must rely on heuristics to
determine which cells belong together to make a single hyperlink.

See the relevant section in the spec [1] for more details.

[1]: https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda#hover-underlining-and-the-id-parameter

(cherry picked from commit b02c839414)
This commit is contained in:
neovim-backports[bot]
2024-07-24 15:18:47 -05:00
committed by GitHub
parent 006fd0304c
commit bce2364f60
2 changed files with 10 additions and 5 deletions

View File

@ -781,7 +781,12 @@ static void update_attrs(TUIData *tui, int attr_id)
if (attrs.url >= 0) { if (attrs.url >= 0) {
const char *url = urls.keys[attrs.url]; const char *url = urls.keys[attrs.url];
kv_size(tui->urlbuf) = 0; kv_size(tui->urlbuf) = 0;
kv_printf(tui->urlbuf, "\x1b]8;;%s\x1b\\", url);
// Add some fixed offset to the URL ID to deconflict with other
// applications which may set their own IDs
const uint64_t id = 0xE1EA0000U + (uint32_t)attrs.url;
kv_printf(tui->urlbuf, "\x1b]8;id=%" PRIu64 ";%s\x1b\\", id, url);
out(tui, tui->urlbuf.items, kv_size(tui->urlbuf)); out(tui, tui->urlbuf.items, kv_size(tui->urlbuf));
} else { } else {
out(tui, S_LEN("\x1b]8;;\x1b\\")); out(tui, S_LEN("\x1b]8;;\x1b\\"));

View File

@ -1941,9 +1941,9 @@ describe('TUI', function()
if not req then if not req then
return return
end end
local url = req:match('\027]8;;(.*)$') local id, url = req:match('\027]8;id=(%d+);(.*)$')
if url ~= nil then if id ~= nil and url ~= nil then
table.insert(_G.urls, url) table.insert(_G.urls, { id = tonumber(id), url = url })
end end
end, end,
}) })
@ -1957,7 +1957,7 @@ describe('TUI', function()
}) })
]]) ]])
retry(nil, 1000, function() retry(nil, 1000, function()
eq({ 'https://example.com', '' }, exec_lua([[return _G.urls]])) eq({ { id = 0xE1EA0000, url = 'https://example.com' } }, exec_lua([[return _G.urls]]))
end) end)
end) end)
end) end)