summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Marriott <nicm@cvs.openbsd.org>2022-07-06 07:36:37 +0000
committerNicholas Marriott <nicm@cvs.openbsd.org>2022-07-06 07:36:37 +0000
commit6bd40e339c592bc85e805b752cb38b6d403ce6d0 (patch)
tree0bf070acd30491424840891af7b218b7c4963831
parent8bc13742a5911c3c26e612fc67efdef829f18ee2 (diff)
Support hyperlinks with capture-pane -e and add a mouse_hyperlink
format, GitHub issue 3247 from Jeff Chiang.
-rw-r--r--usr.bin/tmux/cmd-capture-pane.c4
-rw-r--r--usr.bin/tmux/format.c41
-rw-r--r--usr.bin/tmux/grid-view.c4
-rw-r--r--usr.bin/tmux/grid.c74
-rw-r--r--usr.bin/tmux/hyperlinks.c9
-rw-r--r--usr.bin/tmux/key-bindings.c5
-rw-r--r--usr.bin/tmux/tmux.15
-rw-r--r--usr.bin/tmux/tmux.h8
-rw-r--r--usr.bin/tmux/tty.c4
9 files changed, 128 insertions, 26 deletions
diff --git a/usr.bin/tmux/cmd-capture-pane.c b/usr.bin/tmux/cmd-capture-pane.c
index 08ec85a37e0..dd88bbddda8 100644
--- a/usr.bin/tmux/cmd-capture-pane.c
+++ b/usr.bin/tmux/cmd-capture-pane.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cmd-capture-pane.c,v 1.57 2022/06/30 09:55:53 nicm Exp $ */
+/* $OpenBSD: cmd-capture-pane.c,v 1.58 2022/07/06 07:36:36 nicm Exp $ */
/*
* Copyright (c) 2009 Jonathan Alvarado <radobobo@users.sourceforge.net>
@@ -177,7 +177,7 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
buf = NULL;
for (i = top; i <= bottom; i++) {
line = grid_string_cells(gd, 0, i, sx, &gc, with_codes,
- escape_c0, !join_lines && !no_trim);
+ escape_c0, !join_lines && !no_trim, wp->screen);
linelen = strlen(line);
buf = cmd_capture_pane_append(buf, len, line, linelen);
diff --git a/usr.bin/tmux/format.c b/usr.bin/tmux/format.c
index 664a217156a..201f133136c 100644
--- a/usr.bin/tmux/format.c
+++ b/usr.bin/tmux/format.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: format.c,v 1.307 2022/06/27 09:16:54 nicm Exp $ */
+/* $OpenBSD: format.c,v 1.308 2022/07/06 07:36:36 nicm Exp $ */
/*
* Copyright (c) 2011 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -1145,6 +1145,25 @@ format_cb_mouse_word(struct format_tree *ft)
return (format_grid_word(gd, x, gd->hsize + y));
}
+/* Callback for mouse_hyperlink. */
+static void *
+format_cb_mouse_hyperlink(struct format_tree *ft)
+{
+ struct window_pane *wp;
+ struct grid *gd;
+ u_int x, y;
+
+ if (!ft->m.valid)
+ return (NULL);
+ wp = cmd_mouse_pane(&ft->m, NULL, NULL);
+ if (wp == NULL)
+ return (NULL);
+ if (cmd_mouse_at(wp, &ft->m, &x, &y, 0) != 0)
+ return (NULL);
+ gd = wp->base.grid;
+ return (format_grid_hyperlink(gd, x, gd->hsize + y, wp->screen));
+}
+
/* Callback for mouse_line. */
static void *
format_cb_mouse_line(struct format_tree *ft)
@@ -2789,6 +2808,9 @@ static const struct format_table_entry format_table[] = {
{ "mouse_button_flag", FORMAT_TABLE_STRING,
format_cb_mouse_button_flag
},
+ { "mouse_hyperlink", FORMAT_TABLE_STRING,
+ format_cb_mouse_hyperlink
+ },
{ "mouse_line", FORMAT_TABLE_STRING,
format_cb_mouse_line
},
@@ -5064,3 +5086,20 @@ format_grid_line(struct grid *gd, u_int y)
}
return (s);
}
+
+/* Return hyperlink at given coordinates. Caller frees. */
+char *
+format_grid_hyperlink(struct grid *gd, u_int x, u_int y, struct screen* s)
+{
+ const char *uri;
+ struct grid_cell gc;
+
+ grid_get_cell(gd, x, y, &gc);
+ if (gc.flags & GRID_FLAG_PADDING)
+ return (NULL);
+ if (s->hyperlinks == NULL || gc.link == 0)
+ return (NULL);
+ if (!hyperlinks_get(s->hyperlinks, gc.link, &uri, NULL, NULL))
+ return (NULL);
+ return (xstrdup(uri));
+}
diff --git a/usr.bin/tmux/grid-view.c b/usr.bin/tmux/grid-view.c
index 23beae8c61b..053b104fd63 100644
--- a/usr.bin/tmux/grid-view.c
+++ b/usr.bin/tmux/grid-view.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: grid-view.c,v 1.34 2020/06/02 20:51:46 nicm Exp $ */
+/* $OpenBSD: grid-view.c,v 1.35 2022/07/06 07:36:36 nicm Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -231,5 +231,5 @@ grid_view_string_cells(struct grid *gd, u_int px, u_int py, u_int nx)
px = grid_view_x(gd, px);
py = grid_view_y(gd, py);
- return (grid_string_cells(gd, px, py, nx, NULL, 0, 0, 0));
+ return (grid_string_cells(gd, px, py, nx, NULL, 0, 0, 0, NULL));
}
diff --git a/usr.bin/tmux/grid.c b/usr.bin/tmux/grid.c
index 3658fcc62cc..a9f276bfd1d 100644
--- a/usr.bin/tmux/grid.c
+++ b/usr.bin/tmux/grid.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: grid.c,v 1.125 2022/06/30 09:55:53 nicm Exp $ */
+/* $OpenBSD: grid.c,v 1.126 2022/07/06 07:36:36 nicm Exp $ */
/*
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -885,18 +885,47 @@ grid_string_cells_add_code(char *buf, size_t len, u_int n, int *s, int *newc,
}
}
+static int
+grid_string_cells_add_hyperlink(char *buf, size_t len, const char *id,
+ const char *uri, int escape_c0)
+{
+ char *tmp;
+
+ if (strlen(uri) + strlen(id) + 17 >= len)
+ return (0);
+
+ if (escape_c0)
+ strlcat(buf, "\\033]8;", len);
+ else
+ strlcat(buf, "\033]8;", len);
+ if (*id != '\0') {
+ xasprintf(&tmp, "id=%s;", id);
+ strlcat(buf, tmp, len);
+ free(tmp);
+ } else
+ strlcat(buf, ";", len);
+ strlcat(buf, uri, len);
+ if (escape_c0)
+ strlcat(buf, "\\033\\\\", len);
+ else
+ strlcat(buf, "\033\\", len);
+ return (1);
+}
+
/*
* Returns ANSI code to set particular attributes (colour, bold and so on)
* given a current state.
*/
static void
grid_string_cells_code(const struct grid_cell *lastgc,
- const struct grid_cell *gc, char *buf, size_t len, int escape_c0)
+ const struct grid_cell *gc, char *buf, size_t len, int escape_c0,
+ struct screen *sc, int *has_link)
{
- int oldc[64], newc[64], s[128];
- size_t noldc, nnewc, n, i;
- u_int attr = gc->attr, lastattr = lastgc->attr;
- char tmp[64];
+ int oldc[64], newc[64], s[128];
+ size_t noldc, nnewc, n, i;
+ u_int attr = gc->attr, lastattr = lastgc->attr;
+ char tmp[64];
+ const char *uri, *id;
struct {
u_int mask;
@@ -986,19 +1015,32 @@ grid_string_cells_code(const struct grid_cell *lastgc,
else
strlcat(buf, "\017", len); /* SI */
}
+
+ /* Add hyperlink if changed. */
+ if (sc != NULL && sc->hyperlinks != NULL && lastgc->link != gc->link) {
+ if (hyperlinks_get(sc->hyperlinks, gc->link, &uri, &id, NULL)) {
+ *has_link = grid_string_cells_add_hyperlink(buf, len,
+ id, uri, escape_c0);
+ } else if (*has_link) {
+ grid_string_cells_add_hyperlink(buf, len, "", "",
+ escape_c0);
+ *has_link = 0;
+ }
+ }
}
/* Convert cells into a string. */
char *
grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx,
- struct grid_cell **lastgc, int with_codes, int escape_c0, int trim)
+ struct grid_cell **lastgc, int with_codes, int escape_c0, int trim,
+ struct screen *s)
{
struct grid_cell gc;
static struct grid_cell lastgc1;
const char *data;
- char *buf, code[128];
+ char *buf, code[8192];
size_t len, off, size, codelen;
- u_int xx;
+ u_int xx, has_link = 0;
const struct grid_line *gl;
if (lastgc != NULL && *lastgc == NULL) {
@@ -1020,7 +1062,7 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx,
if (with_codes) {
grid_string_cells_code(*lastgc, &gc, code, sizeof code,
- escape_c0);
+ escape_c0, s, &has_link);
codelen = strlen(code);
memcpy(*lastgc, &gc, sizeof **lastgc);
} else
@@ -1046,6 +1088,18 @@ grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx,
off += size;
}
+ if (has_link) {
+ grid_string_cells_add_hyperlink(code, sizeof code, "", "",
+ escape_c0);
+ codelen = strlen(code);
+ while (len < off + size + codelen + 1) {
+ buf = xreallocarray(buf, 2, len);
+ len *= 2;
+ }
+ memcpy(buf + off, code, codelen);
+ off += codelen;
+ }
+
if (trim) {
while (off > 0 && buf[off - 1] == ' ')
off--;
diff --git a/usr.bin/tmux/hyperlinks.c b/usr.bin/tmux/hyperlinks.c
index 6e336ecf70b..4f2585e9ef5 100644
--- a/usr.bin/tmux/hyperlinks.c
+++ b/usr.bin/tmux/hyperlinks.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: hyperlinks.c,v 1.1 2022/06/30 09:55:53 nicm Exp $ */
+/* $OpenBSD: hyperlinks.c,v 1.2 2022/07/06 07:36:36 nicm Exp $ */
/*
* Copyright (c) 2021 Will <author@will.party>
@@ -179,7 +179,7 @@ hyperlinks_put(struct hyperlinks *hl, const char *uri_in,
/* Get hyperlink by inner number. */
int
hyperlinks_get(struct hyperlinks *hl, u_int inner, const char **uri_out,
- const char **external_id_out)
+ const char **internal_id_out, const char **external_id_out)
{
struct hyperlinks_uri find, *hlu;
@@ -188,7 +188,10 @@ hyperlinks_get(struct hyperlinks *hl, u_int inner, const char **uri_out,
hlu = RB_FIND(hyperlinks_by_inner_tree, &hl->by_inner, &find);
if (hlu == NULL)
return (0);
- *external_id_out = hlu->external_id;
+ if (internal_id_out != NULL)
+ *internal_id_out = hlu->internal_id;
+ if (external_id_out != NULL)
+ *external_id_out = hlu->external_id;
*uri_out = hlu->uri;
return (1);
}
diff --git a/usr.bin/tmux/key-bindings.c b/usr.bin/tmux/key-bindings.c
index fcaf5de0e32..dfb4fadbd88 100644
--- a/usr.bin/tmux/key-bindings.c
+++ b/usr.bin/tmux/key-bindings.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: key-bindings.c,v 1.142 2022/02/03 07:26:43 nicm Exp $ */
+/* $OpenBSD: key-bindings.c,v 1.143 2022/07/06 07:36:36 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -54,6 +54,9 @@
" '#{?mouse_word,Copy #[underscore]#{=/9/...:mouse_word},}' 'c' {copy-mode -q; set-buffer -- \"#{q:mouse_word}\"}" \
" '#{?mouse_line,Copy Line,}' 'l' {copy-mode -q; set-buffer -- \"#{q:mouse_line}\"}" \
" ''" \
+ " '#{?mouse_hyperlink,Type #[underscore]#{=/9/...:mouse_hyperlink},}' 'C-h' {copy-mode -q; send-keys -l -- \"#{q:mouse_hyperlink}\"}" \
+ " '#{?mouse_hyperlink,Copy #[underscore]#{=/9/...:mouse_hyperlink},}' 'h' {copy-mode -q; set-buffer -- \"#{q:mouse_hyperlink}\"}" \
+ " ''" \
" 'Horizontal Split' 'h' {split-window -h}" \
" 'Vertical Split' 'v' {split-window -v}" \
" ''" \
diff --git a/usr.bin/tmux/tmux.1 b/usr.bin/tmux/tmux.1
index 5ac2a6379d8..f2c8dd1d897 100644
--- a/usr.bin/tmux/tmux.1
+++ b/usr.bin/tmux/tmux.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: tmux.1,v 1.893 2022/06/30 09:55:53 nicm Exp $
+.\" $OpenBSD: tmux.1,v 1.894 2022/07/06 07:36:36 nicm Exp $
.\"
.\" Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
.\"
@@ -14,7 +14,7 @@
.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: June 30 2022 $
+.Dd $Mdocdate: July 6 2022 $
.Dt TMUX 1
.Os
.Sh NAME
@@ -5160,6 +5160,7 @@ The following variables are available, where appropriate:
.It Li "mouse_all_flag" Ta "" Ta "Pane mouse all flag"
.It Li "mouse_any_flag" Ta "" Ta "Pane mouse any flag"
.It Li "mouse_button_flag" Ta "" Ta "Pane mouse button flag"
+.It Li "mouse_hyperlink" Ta "" Ta "Hyperlink under mouse, if any"
.It Li "mouse_line" Ta "" Ta "Line under mouse, if any"
.It Li "mouse_sgr_flag" Ta "" Ta "Pane mouse SGR flag"
.It Li "mouse_standard_flag" Ta "" Ta "Pane mouse standard flag"
diff --git a/usr.bin/tmux/tmux.h b/usr.bin/tmux/tmux.h
index 38a174edbd3..413fb2b80e5 100644
--- a/usr.bin/tmux/tmux.h
+++ b/usr.bin/tmux/tmux.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: tmux.h,v 1.1176 2022/06/30 09:55:53 nicm Exp $ */
+/* $OpenBSD: tmux.h,v 1.1177 2022/07/06 07:36:36 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -2126,6 +2126,8 @@ void format_defaults_paste_buffer(struct format_tree *,
struct paste_buffer *);
void format_lost_client(struct client *);
char *format_grid_word(struct grid *, u_int, u_int);
+char *format_grid_hyperlink(struct grid *, u_int, u_int,
+ struct screen *);
char *format_grid_line(struct grid *, u_int);
/* format-draw.c */
@@ -2772,7 +2774,7 @@ void grid_clear_lines(struct grid *, u_int, u_int, u_int);
void grid_move_lines(struct grid *, u_int, u_int, u_int, u_int);
void grid_move_cells(struct grid *, u_int, u_int, u_int, u_int, u_int);
char *grid_string_cells(struct grid *, u_int, u_int, u_int,
- struct grid_cell **, int, int, int);
+ struct grid_cell **, int, int, int, struct screen *);
void grid_duplicate_lines(struct grid *, u_int, struct grid *, u_int,
u_int);
void grid_reflow(struct grid *, u_int);
@@ -3312,7 +3314,7 @@ uid_t server_acl_get_uid(struct server_acl_user *);
u_int hyperlinks_put(struct hyperlinks *, const char *,
const char *);
int hyperlinks_get(struct hyperlinks *, u_int,
- const char **, const char **);
+ const char **, const char **, const char **);
struct hyperlinks *hyperlinks_init(void);
void hyperlinks_reset(struct hyperlinks *);
void hyperlinks_free(struct hyperlinks *);
diff --git a/usr.bin/tmux/tty.c b/usr.bin/tmux/tty.c
index 8da3cec0723..e029c9c2710 100644
--- a/usr.bin/tmux/tty.c
+++ b/usr.bin/tmux/tty.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tty.c,v 1.421 2022/06/30 09:55:53 nicm Exp $ */
+/* $OpenBSD: tty.c,v 1.422 2022/07/06 07:36:36 nicm Exp $ */
/*
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
@@ -2501,7 +2501,7 @@ tty_hyperlink(struct tty *tty, const struct grid_cell *gc,
if (hl == NULL)
return;
- if (gc->link == 0 || !hyperlinks_get(hl, gc->link, &uri, &id))
+ if (gc->link == 0 || !hyperlinks_get(hl, gc->link, &uri, NULL, &id))
tty_putcode_ptr2(tty, TTYC_HLS, "", "");
else
tty_putcode_ptr2(tty, TTYC_HLS, id, uri);