diff options
| author | Gregory Anders <8965202+gpanders@users.noreply.github.com> | 2024-08-15 06:09:14 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-08-15 06:09:14 -0500 |
| commit | 4199671047b0cb62781995a8f6a4b66fb6e8b6fd (patch) | |
| tree | 9018e8b4765279f423c89b41a3a27f52d7029fdc /src/nvim | |
| parent | f3677c71f04ee6ef52449664dfb37f0477fd7305 (diff) | |
| download | rneovim-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.c | 61 |
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, |