From 0a81f4d742cfb986a9eaf74fcaa148ba0cc0a019 Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 2 Jul 2026 08:51:05 +0000 Subject: [PATCH] Add a raw grid output to capture-pane for debugging and regression tests. --- attributes.c | 2 +- cmd-capture-pane.c | 98 ++++++++++++++++++++++++++++++++++++++++++++-- grid.c | 95 ++++++++++++++++++++++++++++++++++++++++++++ tmux.1 | 4 +- tmux.h | 3 ++ 5 files changed, 197 insertions(+), 5 deletions(-) diff --git a/attributes.c b/attributes.c index 8eaa8897b..b0c9ef518 100644 --- a/attributes.c +++ b/attributes.c @@ -45,7 +45,7 @@ attributes_tostring(int attr) (attr & GRID_ATTR_UNDERSCORE_3) ? "curly-underscore," : "", (attr & GRID_ATTR_UNDERSCORE_4) ? "dotted-underscore," : "", (attr & GRID_ATTR_UNDERSCORE_5) ? "dashed-underscore," : "", - (attr & GRID_ATTR_OVERLINE) ? "overline," : "", + (attr & GRID_ATTR_OVERLINE) ? "overline," : "", (attr & GRID_ATTR_NOATTR) ? "noattr," : ""); if (len > 0) buf[len - 1] = '\0'; diff --git a/cmd-capture-pane.c b/cmd-capture-pane.c index 7820f3ce7..75ab50867 100644 --- a/cmd-capture-pane.c +++ b/cmd-capture-pane.c @@ -20,6 +20,7 @@ #include #include +#include #include "tmux.h" @@ -42,8 +43,8 @@ const struct cmd_entry cmd_capture_pane_entry = { .name = "capture-pane", .alias = "capturep", - .args = { "ab:CeE:FHJLMNpPqS:Tt:", 0, 0, NULL }, - .usage = "[-aCeFHJLMNpPqT] " CMD_BUFFER_USAGE " [-E end-line] " + .args = { "ab:CeE:FHJLMNpPqRS:Tt:", 0, 0, NULL }, + .usage = "[-aCeFHJLMNpPqRT] " CMD_BUFFER_USAGE " [-E end-line] " "[-S start-line] " CMD_TARGET_PANE_USAGE, .target = { 't', CMD_FIND_PANE, 0 }, @@ -75,6 +76,95 @@ cmd_capture_pane_append(char *buf, size_t *len, const char *line, return (buf); } +static char * +cmd_capture_pane_cell(struct screen *s, u_int xx, u_int yy) +{ + struct grid *gd = s->grid; + struct hyperlinks *hl = s->hyperlinks; + struct grid_cell gc; + char *line, *data, *tmp, *link, *linkid, *f, *b, *u; + const char *uri, *iid; + u_int flags; + + grid_get_cell(gd, xx, yy, &gc); + + tmp = utf8_tocstr(&gc.data); + utf8_stravis(&data, tmp, VIS_OCTAL|VIS_CSTYLE|VIS_TAB|VIS_NL); + free(tmp); + + if (gc.link != 0 && hyperlinks_get(hl, gc.link, &uri, &iid, NULL)) { + xasprintf(&link, "%s", uri); + if (iid != NULL && *iid != '\0') + xasprintf(&linkid, "%s", iid); + else + xasprintf(&linkid, "NONE"); + } else { + xasprintf(&link, "NONE"); + xasprintf(&linkid, "NONE"); + } + + flags = gc.flags; + if (gc.fg & COLOUR_FLAG_256) + flags |= GRID_FLAG_FG256; + if (gc.bg & COLOUR_FLAG_256) + flags |= GRID_FLAG_BG256; + + xasprintf(&f, "%s[%x]", colour_tostring(gc.fg), gc.fg); + xasprintf(&b, "%s[%x]", colour_tostring(gc.bg), gc.bg); + xasprintf(&u, "%s[%x]", colour_tostring(gc.us), gc.us); + + xasprintf(&line, "\t\tC %u,%u data=(%u,%u,%s) flags=%s[%x] " + "attr=%s[%x] fg=%s bg=%s us=%s link=%s linkid=%s\n", + yy, xx, gc.data.width, gc.data.size, data, + grid_cell_flags_string(flags), flags, + grid_cell_attr_string(gc.attr), gc.attr, f, b, u, link, linkid); + + free(f); + free(b); + free(u); + free(link); + free(linkid); + free(data); + return (line); +} + +static char * +cmd_capture_pane_grid(struct window_pane *wp, size_t *len) +{ + struct screen *s = &wp->base; + struct grid *gd = s->grid; + struct grid_line *gl; + char *buf = xstrdup(""), *line; + char p[11]; + u_int yy, xx, total = gd->hsize + gd->sy; + + xasprintf(&line, "G %ux%u (%u/%u)\n", gd->sx, gd->sy, gd->hsize, + gd->hlimit); + buf = cmd_capture_pane_append(buf, len, line, strlen(line)); + free(line); + + for (yy = 0; yy < total; yy++) { + gl = grid_get_line(gd, yy); + if (yy < gd->hsize) + snprintf(p, sizeof p, "-"); + else + snprintf(p, sizeof p, "%u", yy - gd->hsize); + xasprintf(&line, "\tL %u (%s) flags=%s[%x] %u/%u\n", yy, + p, grid_line_flags_string(gl->flags), gl->flags, + gl->cellused, gl->cellsize); + buf = cmd_capture_pane_append(buf, len, line, strlen(line)); + free(line); + + for (xx = 0; xx < gd->sx; xx++) { + line = cmd_capture_pane_cell(s, xx, yy); + buf = cmd_capture_pane_append(buf, len, line, + strlen(line)); + free(line); + } + } + return (buf); +} + static char * cmd_capture_pane_pending(struct args *args, struct window_pane *wp, size_t *len) @@ -323,7 +413,9 @@ cmd_capture_pane_exec(struct cmd *self, struct cmdq_item *item) } len = 0; - if (args_has(args, 'P') && !args_has(args, 'H')) + if (args_has(args, 'R')) + buf = cmd_capture_pane_grid(wp, &len); + else 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 3b1b96a38..aabc3cf3f 100644 --- a/grid.c +++ b/grid.c @@ -1634,3 +1634,98 @@ grid_in_set(struct grid *gd, u_int px, u_int py, const char *set) return (0); return (utf8_cstrhas(set, &gc.data)); } + +/* Line flags to string. */ +const char * +grid_line_flags_string(int flags) +{ + static char s[128]; + + *s = '\0'; + if (flags & GRID_LINE_WRAPPED) + strlcat(s, "WRAPPED,", sizeof s); + if (flags & GRID_LINE_EXTENDED) + strlcat(s, "EXTENDED,", sizeof s); + if (flags & GRID_LINE_DEAD) + strlcat(s, "DEAD,", sizeof s); + if (flags & GRID_LINE_START_PROMPT) + strlcat(s, "START_PROMPT,", sizeof s); + if (flags & GRID_LINE_START_OUTPUT) + strlcat(s, "START_OUTPUT,", sizeof s); + if (flags & GRID_LINE_HYPERLINK) + strlcat(s, "HYPERLINK,", sizeof s); + if (*s == '\0') + return ("NONE"); + s[strlen(s) - 1] = '\0'; + return (s); +} + +/* Cell flags to string. */ +const char * +grid_cell_flags_string(int flags) +{ + static char s[128]; + + *s = '\0'; + if (flags & GRID_FLAG_FG256) + strlcat(s, "FG256,", sizeof s); + if (flags & GRID_FLAG_BG256) + strlcat(s, "BG256,", sizeof s); + if (flags & GRID_FLAG_PADDING) + strlcat(s, "PADDING,", sizeof s); + if (flags & GRID_FLAG_EXTENDED) + strlcat(s, "EXTENDED,", sizeof s); + if (flags & GRID_FLAG_SELECTED) + strlcat(s, "SELECTED,", sizeof s); + if (flags & GRID_FLAG_CLEARED) + strlcat(s, "CLEARED,", sizeof s); + if (flags & GRID_FLAG_TAB) + strlcat(s, "TAB,", sizeof s); + if (flags & GRID_FLAG_NOPALETTE) + strlcat(s, "NOPALETTE,", sizeof s); + if (*s == '\0') + return ("NONE"); + s[strlen(s) - 1] = '\0'; + return (s); +} + +/* Cell attributes to string. */ +const char * +grid_cell_attr_string(int attr) +{ + static char s[256]; + + *s = '\0'; + if (attr & GRID_ATTR_CHARSET) + strlcat(s, "CHARSET,", sizeof s); + if (attr & GRID_ATTR_BRIGHT) + strlcat(s, "BRIGHT,", sizeof s); + if (attr & GRID_ATTR_DIM) + strlcat(s, "DIM,", sizeof s); + if (attr & GRID_ATTR_UNDERSCORE) + strlcat(s, "UNDERSCORE,", sizeof s); + if (attr & GRID_ATTR_BLINK) + strlcat(s, "BLINK,", sizeof s); + if (attr & GRID_ATTR_REVERSE) + strlcat(s, "REVERSE,", sizeof s); + if (attr & GRID_ATTR_HIDDEN) + strlcat(s, "HIDDEN,", sizeof s); + if (attr & GRID_ATTR_ITALICS) + strlcat(s, "ITALICS,", sizeof s); + if (attr & GRID_ATTR_STRIKETHROUGH) + strlcat(s, "STRIKETHROUGH,", sizeof s); + if (attr & GRID_ATTR_UNDERSCORE_2) + strlcat(s, "UNDERSCORE_2,", sizeof s); + if (attr & GRID_ATTR_UNDERSCORE_3) + strlcat(s, "UNDERSCORE_3,", sizeof s); + if (attr & GRID_ATTR_UNDERSCORE_4) + strlcat(s, "UNDERSCORE_4,", sizeof s); + if (attr & GRID_ATTR_UNDERSCORE_5) + strlcat(s, "UNDERSCORE_5,", sizeof s); + if (attr & GRID_ATTR_OVERLINE) + strlcat(s, "OVERLINE,", sizeof s); + if (*s == '\0') + return ("NONE"); + s[strlen(s) - 1] = '\0'; + return (s); +} diff --git a/tmux.1 b/tmux.1 index da766ade9..9e891ac23 100644 --- a/tmux.1 +++ b/tmux.1 @@ -2768,7 +2768,7 @@ The pane must not already be floating or hidden, and the window must not be zoomed. .Tg capturep .It Xo Ic capture\-pane -.Op Fl aeFHLpPqCJMN +.Op Fl aeFHLpPRqCJMN .Op Fl b Ar buffer\-name .Op Fl E Ar end\-line .Op Fl S Ar start\-line @@ -2828,6 +2828,8 @@ With .Fl H , only hyperlinks in the specified lines are captured. Multiple hyperlinks on the same line are separated by spaces. +.Fl R +dumps the internal grid data for diagnostics. .Pp .Fl S and diff --git a/tmux.h b/tmux.h index 2fbe08790..62763a6f4 100644 --- a/tmux.h +++ b/tmux.h @@ -3291,6 +3291,9 @@ struct grid *grid_create(u_int, u_int, u_int); void grid_destroy(struct grid *); void grid_free_lines(struct grid *, u_int, u_int); int grid_compare(struct grid *, struct grid *); +const char *grid_line_flags_string(int); +const char *grid_cell_flags_string(int); +const char *grid_cell_attr_string(int); void grid_collect_history(struct grid *, int); void grid_remove_history(struct grid *, u_int ); void grid_scroll_history(struct grid *, u_int);