aboutsummaryrefslogtreecommitdiff
path: root/src/nvim
diff options
context:
space:
mode:
authorGregory Anders <8965202+gpanders@users.noreply.github.com>2024-08-15 06:09:14 -0500
committerGitHub <noreply@github.com>2024-08-15 06:09:14 -0500
commit4199671047b0cb62781995a8f6a4b66fb6e8b6fd (patch)
tree9018e8b4765279f423c89b41a3a27f52d7029fdc /src/nvim
parentf3677c71f04ee6ef52449664dfb37f0477fd7305 (diff)
downloadrneovim-4199671047b0cb62781995a8f6a4b66fb6e8b6fd.tar.gz
rneovim-4199671047b0cb62781995a8f6a4b66fb6e8b6fd.tar.bz2
rneovim-4199671047b0cb62781995a8f6a4b66fb6e8b6fd.zip
feat(term): support OSC 8 hyperlinks in :terminal (#30050)
Diffstat (limited to 'src/nvim')
-rw-r--r--src/nvim/terminal.c61
1 files changed, 60 insertions, 1 deletions
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index 54a0de9c22..2b44763ddd 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -227,11 +227,66 @@ static void schedule_termrequest(Terminal *term, char *payload, size_t payload_l
term->pending_send);
}
+static int parse_osc8(VTermStringFragment frag, int *attr)
+ FUNC_ATTR_NONNULL_ALL
+{
+ // 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)
+ size_t i = 0;
+ for (; i < frag.len; i++) {
+ if (frag.str[i] == ';') {
+ break;
+ }
+ }
+
+ // Move past the semicolon
+ i++;
+
+ if (i >= frag.len) {
+ // Invalid OSC sequence
+ return 0;
+ }
+
+ // Find the terminator
+ const size_t start = i;
+ for (; i < frag.len; i++) {
+ if (frag.str[i] == '\a' || frag.str[i] == '\x1b') {
+ break;
+ }
+ }
+
+ const size_t len = i - start;
+ if (len == 0) {
+ // Empty OSC 8, no URL
+ *attr = 0;
+ return 1;
+ }
+
+ char *url = xmemdupz(&frag.str[start], len + 1);
+ url[len] = 0;
+ *attr = hl_add_url(0, url);
+ xfree(url);
+
+ return 1;
+}
+
static int on_osc(int command, VTermStringFragment frag, void *user)
{
+ Terminal *term = user;
+
if (frag.str == NULL) {
return 0;
}
+
+ if (command == 8) {
+ 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;
}
@@ -239,7 +294,7 @@ static int on_osc(int command, VTermStringFragment frag, void *user)
StringBuilder request = KV_INITIAL_VALUE;
kv_printf(request, "\x1b]%d;", command);
kv_concat_len(request, frag.str, frag.len);
- schedule_termrequest(user, request.items, request.size);
+ schedule_termrequest(term, request.items, request.size);
return 1;
}
@@ -992,6 +1047,10 @@ void terminal_get_line_attributes(Terminal *term, win_T *wp, int linenr, int *te
});
}
+ if (cell.uri > 0) {
+ attr_id = hl_combine_attr(attr_id, cell.uri);
+ }
+
if (term->cursor.visible && term->cursor.row == row
&& term->cursor.col == col) {
attr_id = hl_combine_attr(attr_id,