diff --git a/cmd-capture-pane.c b/cmd-capture-pane.c index 0f37ad5d..8f537b98 100644 --- a/cmd-capture-pane.c +++ b/cmd-capture-pane.c @@ -29,18 +29,21 @@ static enum cmd_retval cmd_capture_pane_exec(struct cmd *, struct cmdq_item *); -static char *cmd_capture_pane_append(char *, size_t *, char *, size_t); +static char *cmd_capture_pane_append(char *, size_t *, const char *, + size_t); static char *cmd_capture_pane_pending(struct args *, struct window_pane *, size_t *); static char *cmd_capture_pane_history(struct args *, struct cmdq_item *, struct window_pane *, size_t *); +static char *cmd_capture_pane_hyperlinks(struct grid *, struct screen *, + u_int, u_int *, u_int *, size_t *); const struct cmd_entry cmd_capture_pane_entry = { .name = "capture-pane", .alias = "capturep", - .args = { "ab:CeE:FJLMNpPqS:Tt:", 0, 0, NULL }, - .usage = "[-aCeFJLMNpPqT] " CMD_BUFFER_USAGE " [-E end-line] " + .args = { "ab:CeE:FHJLMNpPqS:Tt:", 0, 0, NULL }, + .usage = "[-aCeFHJLMNpPqT] " CMD_BUFFER_USAGE " [-E end-line] " "[-S start-line] " CMD_TARGET_PANE_USAGE, .target = { 't', CMD_FIND_PANE, 0 }, @@ -63,7 +66,8 @@ const struct cmd_entry cmd_clear_history_entry = { }; static char * -cmd_capture_pane_append(char *buf, size_t *len, char *line, size_t linelen) +cmd_capture_pane_append(char *buf, size_t *len, const char *line, + size_t linelen) { buf = xrealloc(buf, *len + linelen + 1); memcpy(buf + *len, line, linelen); @@ -103,6 +107,46 @@ cmd_capture_pane_pending(struct args *args, struct window_pane *wp, return (buf); } +static char * +cmd_capture_pane_hyperlinks(struct grid *gd, struct screen *s, u_int py, + u_int *links, u_int *nlinks, size_t *len) +{ + const struct grid_line *gl = grid_peek_line(gd, py); + struct grid_cell gc; + const char *uri; + char *line = xstrdup(""); + u_int i, j; + + *len = 0; + + if (s->hyperlinks == NULL || (~gl->flags & GRID_LINE_HYPERLINK)) + return (line); + + for (i = 0; i < gl->cellused; i++) { + grid_get_cell(gd, i, py, &gc); + if (gc.link == 0) + continue; + for (j = 0; j < *nlinks; j++) { + if (links[j] == gc.link) + break; + } + if (j != *nlinks) + continue; + + if (!hyperlinks_get(s->hyperlinks, gc.link, &uri, NULL, NULL)) + continue; + + if (*nlinks == gd->sx) + break; + links[(*nlinks)++] = gc.link; + + if (*len != 0) + line = cmd_capture_pane_append(line, len, " ", 1); + line = cmd_capture_pane_append(line, len, uri, strlen(uri)); + } + return (line); +} + static char * cmd_capture_pane_history(struct args *args, struct cmdq_item *item, struct window_pane *wp, size_t *len) @@ -113,9 +157,10 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item, struct grid_cell *gc = NULL; struct window_mode_entry *wme; int n, join_lines, number_lines, flags = 0; - int show_flags; + int show_flags, hyperlinks; + u_int *links = NULL, nlinks = 0; u_int i, sx, top, bottom, tmp; - char *cause, *buf, *line, b[64], *cp; + char *cause, *buf = NULL, *line, b[64], *cp; const char *Sflag, *Eflag; size_t linelen; @@ -195,11 +240,22 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item, flags |= GRID_STRING_TRIM_SPACES; number_lines = args_has(args, 'L'); show_flags = args_has(args, 'F'); + hyperlinks = args_has(args, 'H'); + if (hyperlinks) + links = xreallocarray(NULL, gd->sx, sizeof *links); - buf = NULL; for (i = top; i <= bottom; i++) { - line = grid_string_cells(gd, 0, i, sx, &gc, flags, s); - linelen = strlen(line); + if (hyperlinks) { + line = cmd_capture_pane_hyperlinks(gd, s, i, links, + &nlinks, &linelen); + } else { + line = grid_string_cells(gd, 0, i, sx, &gc, flags, s); + linelen = strlen(line); + } + if (hyperlinks && linelen == 0) { + free(line); + continue; + } if (number_lines) { if (i >= gd->hsize) @@ -217,6 +273,8 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item, gl = grid_peek_line(gd, i); if (gl->flags & GRID_LINE_DEAD) *cp++ = 'D'; + if (gl->flags & GRID_LINE_HYPERLINK) + *cp++ = 'H'; if (gl->flags & GRID_LINE_START_OUTPUT) *cp++ = 'O'; if (gl->flags & GRID_LINE_START_PROMPT) @@ -239,6 +297,9 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item, free(line); } + free(links); + if (buf == NULL) + buf = xstrdup(""); return (buf); } @@ -261,7 +322,7 @@ cmd_capture_pane_exec(struct cmd *self, struct cmdq_item *item) } len = 0; - if (args_has(args, 'P')) + if (args_has(args, 'P') && !args_has(args, 'H')) buf = cmd_capture_pane_pending(args, wp, &len); else buf = cmd_capture_pane_history(args, item, wp, &len); diff --git a/grid.c b/grid.c index 20deb936..36c99184 100644 --- a/grid.c +++ b/grid.c @@ -125,6 +125,8 @@ grid_extended_cell(struct grid_line *gl, struct grid_cell_entry *gce, else if (gce->offset >= gl->extdsize) fatalx("offset too big"); gl->flags |= GRID_LINE_EXTENDED; + if (gc->link != 0) + gl->flags |= GRID_LINE_HYPERLINK; if (gc->flags & GRID_FLAG_TAB) uc = gc->data.width; diff --git a/tmux.1 b/tmux.1 index 07f379f0..2b1d543f 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2666,7 +2666,7 @@ but a different format may be specified with .Fl F . .Tg capturep .It Xo Ic capture\-pane -.Op Fl aeFLpPqCJMN +.Op Fl aeFHLpPqCJMN .Op Fl b Ar buffer\-name .Op Fl E Ar end\-line .Op Fl S Ar start\-line @@ -2717,9 +2717,15 @@ is an unused line, .Ql O is a line marked as output, .Ql P -is a line marked as a prompt and +is a line marked as a prompt, .Ql X -is a line containing extended cells). +is a line containing extended cells and +.Ql H +is a line with hyperlinks). +With +.Fl H , +only hyperlinks in the specified lines are captured. +Multiple hyperlinks on the same line are separated by spaces. .Pp .Fl S and diff --git a/tmux.h b/tmux.h index 7f0e438a..887d21bb 100644 --- a/tmux.h +++ b/tmux.h @@ -771,6 +771,7 @@ struct colour_palette { #define GRID_LINE_DEAD 0x4 #define GRID_LINE_START_PROMPT 0x8 #define GRID_LINE_START_OUTPUT 0x10 +#define GRID_LINE_HYPERLINK 0x20 /* Grid string flags. */ #define GRID_STRING_WITH_SEQUENCES 0x1