mirror of
https://github.com/tmux/tmux.git
synced 2026-10-09 11:44:23 +00:00
Add link=/nolink to styles to specific a hyperlink. GitHub issue 4280
from Moritz Angermann.
This commit is contained in:
@@ -710,6 +710,7 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
|
|||||||
"AFTER" };
|
"AFTER" };
|
||||||
size_t size = strlen(expanded);
|
size_t size = strlen(expanded);
|
||||||
struct screen *os = octx->s, s[TOTAL];
|
struct screen *os = octx->s, s[TOTAL];
|
||||||
|
struct hyperlinks *hl = os->hyperlinks;
|
||||||
struct screen_write_ctx ctx[TOTAL];
|
struct screen_write_ctx ctx[TOTAL];
|
||||||
u_int ocx = os->cx, ocy = os->cy, n, i, width[TOTAL];
|
u_int ocx = os->cx, ocy = os->cy, n, i, width[TOTAL];
|
||||||
u_int map[] = { LEFT,
|
u_int map[] = { LEFT,
|
||||||
@@ -723,7 +724,7 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
|
|||||||
struct grid_cell gc, current_default, base_default;
|
struct grid_cell gc, current_default, base_default;
|
||||||
struct style sy, saved_sy;
|
struct style sy, saved_sy;
|
||||||
struct utf8_data *ud = &sy.gc.data;
|
struct utf8_data *ud = &sy.gc.data;
|
||||||
const char *cp, *end;
|
const char *cp, *end, *link_uri;
|
||||||
enum utf8_state more;
|
enum utf8_state more;
|
||||||
char *tmp;
|
char *tmp;
|
||||||
struct format_range *fr = NULL, *fr1;
|
struct format_range *fr = NULL, *fr1;
|
||||||
@@ -838,6 +839,17 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
|
|||||||
sy.gc.fg = base->fg;
|
sy.gc.fg = base->fg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Resolve any hyperlink and store it in the cell. The URI
|
||||||
|
* doubles as the internal ID so repeated links share one entry
|
||||||
|
* and the ID stays stable across redraws.
|
||||||
|
*/
|
||||||
|
link_uri = style_link(&sy);
|
||||||
|
if (link_uri != NULL && hl != NULL)
|
||||||
|
sy.gc.link = hyperlinks_put(hl, link_uri, link_uri);
|
||||||
|
else
|
||||||
|
sy.gc.link = 0;
|
||||||
|
|
||||||
/* If this style has a fill colour, store it for later. */
|
/* If this style has a fill colour, store it for later. */
|
||||||
if (sy.fill != 8)
|
if (sy.fill != 8)
|
||||||
fill = sy.fill;
|
fill = sy.fill;
|
||||||
|
|||||||
48
style.c
48
style.c
@@ -42,9 +42,17 @@ static struct style style_default = {
|
|||||||
|
|
||||||
STYLE_WIDTH_DEFAULT, 0, STYLE_PAD_DEFAULT,
|
STYLE_WIDTH_DEFAULT, 0, STYLE_PAD_DEFAULT,
|
||||||
|
|
||||||
STYLE_DEFAULT_BASE
|
STYLE_DEFAULT_BASE,
|
||||||
|
|
||||||
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Global hyperlink set holding the URIs for #[link=...] styles, so a style
|
||||||
|
* only needs to store a small ID rather than the URI itself.
|
||||||
|
*/
|
||||||
|
static struct hyperlinks *style_hyperlinks;
|
||||||
|
|
||||||
/* Set range string. */
|
/* Set range string. */
|
||||||
static void
|
static void
|
||||||
style_set_range_string(struct style *sy, const char *s)
|
style_set_range_string(struct style *sy, const char *s)
|
||||||
@@ -91,6 +99,7 @@ style_parse(struct style *sy, const struct grid_cell *base, const char *in)
|
|||||||
sy->gc.us = base->us;
|
sy->gc.us = base->us;
|
||||||
sy->gc.attr = base->attr;
|
sy->gc.attr = base->attr;
|
||||||
sy->gc.flags = base->flags;
|
sy->gc.flags = base->flags;
|
||||||
|
sy->link = 0;
|
||||||
} else if (strcasecmp(tmp, "ignore") == 0)
|
} else if (strcasecmp(tmp, "ignore") == 0)
|
||||||
sy->ignore = 1;
|
sy->ignore = 1;
|
||||||
else if (strcasecmp(tmp, "noignore") == 0)
|
else if (strcasecmp(tmp, "noignore") == 0)
|
||||||
@@ -234,7 +243,9 @@ style_parse(struct style *sy, const struct grid_cell *base, const char *in)
|
|||||||
} else if (strcasecmp(tmp, "none") == 0)
|
} else if (strcasecmp(tmp, "none") == 0)
|
||||||
sy->gc.attr = 0;
|
sy->gc.attr = 0;
|
||||||
else if (end > 2 && strncasecmp(tmp, "no", 2) == 0) {
|
else if (end > 2 && strncasecmp(tmp, "no", 2) == 0) {
|
||||||
if (strcmp(tmp + 2, "attr") == 0)
|
if (strcmp(tmp + 2, "link") == 0)
|
||||||
|
sy->link = 0;
|
||||||
|
else if (strcmp(tmp + 2, "attr") == 0)
|
||||||
sy->gc.attr |= GRID_ATTR_NOATTR;
|
sy->gc.attr |= GRID_ATTR_NOATTR;
|
||||||
else {
|
else {
|
||||||
value = attributes_fromstring(tmp + 2);
|
value = attributes_fromstring(tmp + 2);
|
||||||
@@ -262,6 +273,15 @@ style_parse(struct style *sy, const struct grid_cell *base, const char *in)
|
|||||||
if (errstr != NULL)
|
if (errstr != NULL)
|
||||||
goto error;
|
goto error;
|
||||||
sy->pad = (int)n;
|
sy->pad = (int)n;
|
||||||
|
} else if (strncasecmp(tmp, "link=", 5) == 0) {
|
||||||
|
if (tmp[5] == '\0')
|
||||||
|
sy->link = 0;
|
||||||
|
else {
|
||||||
|
if (style_hyperlinks == NULL)
|
||||||
|
style_hyperlinks = hyperlinks_init();
|
||||||
|
sy->link = hyperlinks_put(style_hyperlinks,
|
||||||
|
tmp + 5, tmp + 5);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if ((value = attributes_fromstring(tmp)) == -1)
|
if ((value = attributes_fromstring(tmp)) == -1)
|
||||||
goto error;
|
goto error;
|
||||||
@@ -284,8 +304,8 @@ style_tostring(struct style *sy)
|
|||||||
{
|
{
|
||||||
struct grid_cell *gc = &sy->gc;
|
struct grid_cell *gc = &sy->gc;
|
||||||
int off = 0;
|
int off = 0;
|
||||||
const char *comma = "", *tmp = "";
|
const char *comma = "", *tmp = "", *uri;
|
||||||
static char s[1024];
|
static char s[2048];
|
||||||
char b[21];
|
char b[21];
|
||||||
|
|
||||||
*s = '\0';
|
*s = '\0';
|
||||||
@@ -389,15 +409,33 @@ style_tostring(struct style *sy)
|
|||||||
comma = ",";
|
comma = ",";
|
||||||
}
|
}
|
||||||
if (sy->pad >= 0) {
|
if (sy->pad >= 0) {
|
||||||
xsnprintf(s + off, sizeof s - off, "%spad=%u", comma,
|
off += xsnprintf(s + off, sizeof s - off, "%spad=%u", comma,
|
||||||
sy->pad);
|
sy->pad);
|
||||||
comma = ",";
|
comma = ",";
|
||||||
}
|
}
|
||||||
|
uri = style_link(sy);
|
||||||
|
if (uri != NULL) {
|
||||||
|
xsnprintf(s + off, sizeof s - off, "%slink=%s", comma, uri);
|
||||||
|
comma = ",";
|
||||||
|
}
|
||||||
if (*s == '\0')
|
if (*s == '\0')
|
||||||
return ("default");
|
return ("default");
|
||||||
return (s);
|
return (s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Get the hyperlink URI for a style, or NULL if it has none. */
|
||||||
|
const char *
|
||||||
|
style_link(struct style *sy)
|
||||||
|
{
|
||||||
|
const char *uri;
|
||||||
|
|
||||||
|
if (sy->link == 0 || style_hyperlinks == NULL)
|
||||||
|
return (NULL);
|
||||||
|
if (!hyperlinks_get(style_hyperlinks, sy->link, &uri, NULL, NULL))
|
||||||
|
return (NULL);
|
||||||
|
return (uri);
|
||||||
|
}
|
||||||
|
|
||||||
/* Apply a style on top of the given style. */
|
/* Apply a style on top of the given style. */
|
||||||
struct style *
|
struct style *
|
||||||
style_add(struct grid_cell *gc, struct options *oo, const char *name,
|
style_add(struct grid_cell *gc, struct options *oo, const char *name,
|
||||||
|
|||||||
22
tmux.1
22
tmux.1
@@ -7266,6 +7266,28 @@ Set the width of the styled area.
|
|||||||
.Ar N
|
.Ar N
|
||||||
may be a column count or a percentage (for example
|
may be a column count or a percentage (for example
|
||||||
.Ql 50% ) .
|
.Ql 50% ) .
|
||||||
|
.It Xo Ic link=uri
|
||||||
|
(or
|
||||||
|
.Ic nolink )
|
||||||
|
.Xc
|
||||||
|
Make the styled text an OSC 8 hyperlink to
|
||||||
|
.Ar uri ,
|
||||||
|
for example
|
||||||
|
.Ql #[link=https://example.com]text#[nolink] .
|
||||||
|
This is emitted only to terminals with the
|
||||||
|
.Ic hyperlinks
|
||||||
|
feature (see
|
||||||
|
.Ic terminal-features ) ;
|
||||||
|
it works in the status line and in other formats drawn with styles.
|
||||||
|
The link continues until
|
||||||
|
.Ic nolink ,
|
||||||
|
.Ic default ,
|
||||||
|
or an empty
|
||||||
|
.Ic link=
|
||||||
|
is given.
|
||||||
|
The
|
||||||
|
.Ar uri
|
||||||
|
may not contain spaces or commas and is limited in length.
|
||||||
.It Xo Ic list=on ,
|
.It Xo Ic list=on ,
|
||||||
.Ic list=focus ,
|
.Ic list=focus ,
|
||||||
.Ic list=left\-marker ,
|
.Ic list=left\-marker ,
|
||||||
|
|||||||
3
tmux.h
3
tmux.h
@@ -984,6 +984,8 @@ struct style {
|
|||||||
int pad;
|
int pad;
|
||||||
|
|
||||||
enum style_default_type default_type;
|
enum style_default_type default_type;
|
||||||
|
|
||||||
|
u_int link;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Cursor style. */
|
/* Cursor style. */
|
||||||
@@ -3960,6 +3962,7 @@ int style_parse(struct style *,const struct grid_cell *,
|
|||||||
int style_parse_colour(struct style *,
|
int style_parse_colour(struct style *,
|
||||||
const struct grid_cell *, const char *);
|
const struct grid_cell *, const char *);
|
||||||
const char *style_tostring(struct style *);
|
const char *style_tostring(struct style *);
|
||||||
|
const char *style_link(struct style *);
|
||||||
struct style *style_add(struct grid_cell *, struct options *,
|
struct style *style_add(struct grid_cell *, struct options *,
|
||||||
const char *, struct format_tree *);
|
const char *, struct format_tree *);
|
||||||
void style_apply(struct grid_cell *, struct options *,
|
void style_apply(struct grid_cell *, struct options *,
|
||||||
|
|||||||
@@ -570,6 +570,7 @@ tty_default_features(int *feat, const char *name, u_int version)
|
|||||||
"cstyle,"
|
"cstyle,"
|
||||||
"extkeys,"
|
"extkeys,"
|
||||||
"focus,"
|
"focus,"
|
||||||
|
"hyperlinks,"
|
||||||
"usstyle"
|
"usstyle"
|
||||||
},
|
},
|
||||||
{ .name = "XTerm",
|
{ .name = "XTerm",
|
||||||
|
|||||||
Reference in New Issue
Block a user