From a5fd5782f87362b8ee31cd5c6975728e112db9ff Mon Sep 17 00:00:00 2001 From: nicm Date: Thu, 12 Oct 2017 11:32:27 +0000 Subject: [PATCH 1/2] Show exit status and time in the remain-on-exit pane text, mostly from Timo Boettcher in GitHub issue 1103. --- format.c | 11 ++++++----- server-fn.c | 30 ++++++++++++++++++++++++------ server.c | 1 + tmux.h | 2 ++ window.c | 1 + 5 files changed, 34 insertions(+), 11 deletions(-) diff --git a/format.c b/format.c index da9eb545..aa8396d7 100644 --- a/format.c +++ b/format.c @@ -1376,8 +1376,8 @@ void format_defaults_pane(struct format_tree *ft, struct window_pane *wp) { struct grid *gd = wp->base.grid; + int status = wp->status; u_int idx; - int status; if (ft->w == NULL) ft->w = wp->window; @@ -1399,8 +1399,7 @@ format_defaults_pane(struct format_tree *ft, struct window_pane *wp) format_add(ft, "pane_input_off", "%d", !!(wp->flags & PANE_INPUTOFF)); format_add(ft, "pane_pipe", "%d", wp->pipe_fd != -1); - status = wp->status; - if (wp->fd == -1 && WIFEXITED(status)) + if ((wp->flags & PANE_STATUSREADY) && WIFEXITED(status)) format_add(ft, "pane_dead_status", "%d", WEXITSTATUS(status)); format_add(ft, "pane_dead", "%d", wp->fd == -1); @@ -1411,8 +1410,10 @@ format_defaults_pane(struct format_tree *ft, struct window_pane *wp) format_add(ft, "pane_bottom", "%u", wp->yoff + wp->sy - 1); format_add(ft, "pane_at_left", "%d", wp->xoff == 0); format_add(ft, "pane_at_top", "%d", wp->yoff == 0); - format_add(ft, "pane_at_right", "%d", wp->xoff + wp->sx == wp->window->sx); - format_add(ft, "pane_at_bottom", "%d", wp->yoff + wp->sy == wp->window->sy); + format_add(ft, "pane_at_right", "%d", + wp->xoff + wp->sx == wp->window->sx); + format_add(ft, "pane_at_bottom", "%d", + wp->yoff + wp->sy == wp->window->sy); } format_add(ft, "pane_in_mode", "%d", wp->screen != &wp->base); diff --git a/server-fn.c b/server-fn.c index f5ede2c2..713e85b7 100644 --- a/server-fn.c +++ b/server-fn.c @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -278,11 +279,11 @@ void server_destroy_pane(struct window_pane *wp, int notify) { struct window *w = wp->window; - int old_fd; struct screen_write_ctx ctx; struct grid_cell gc; + time_t t; + char tim[26]; - old_fd = wp->fd; if (wp->fd != -1) { bufferevent_free(wp->event); close(wp->fd); @@ -290,9 +291,13 @@ server_destroy_pane(struct window_pane *wp, int notify) } if (options_get_number(w->options, "remain-on-exit")) { - if (old_fd == -1) + if (~wp->flags & PANE_STATUSREADY) return; + if (wp->flags & PANE_STATUSDRAWN) + return; + wp->flags |= PANE_STATUSDRAWN; + if (notify) notify_pane("pane-died", wp); @@ -301,11 +306,24 @@ server_destroy_pane(struct window_pane *wp, int notify) screen_write_cursormove(&ctx, 0, screen_size_y(ctx.s) - 1); screen_write_linefeed(&ctx, 1, 8); memcpy(&gc, &grid_default_cell, sizeof gc); - gc.attr |= GRID_ATTR_BRIGHT; - screen_write_puts(&ctx, &gc, "Pane is dead"); + + time(&t); + ctime_r(&t, tim); + + if (WIFEXITED(wp->status)) { + screen_write_nputs(&ctx, -1, &gc, + "Pane is dead (status %d, %s)", + WEXITSTATUS(wp->status), + tim); + } else if (WIFSIGNALED(wp->status)) { + screen_write_nputs(&ctx, -1, &gc, + "Pane is dead (signal %d, %s)", + WTERMSIG(wp->status), + tim); + } + screen_write_stop(&ctx); wp->flags |= PANE_REDRAW; - return; } diff --git a/server.c b/server.c index 753f6d01..82b5a6b8 100644 --- a/server.c +++ b/server.c @@ -424,6 +424,7 @@ server_child_exited(pid_t pid, int status) TAILQ_FOREACH(wp, &w->panes, entry) { if (wp->pid == pid) { wp->status = status; + wp->flags |= PANE_STATUSREADY; log_debug("%%%u exited", wp->id); wp->flags |= PANE_EXITED; diff --git a/tmux.h b/tmux.h index a661a6da..ad35c336 100644 --- a/tmux.h +++ b/tmux.h @@ -778,6 +778,8 @@ struct window_pane { #define PANE_INPUTOFF 0x40 #define PANE_CHANGED 0x80 #define PANE_EXITED 0x100 +#define PANE_STATUSREADY 0x200 +#define PANE_STATUSDRAWN 0x400 int argc; char **argv; diff --git a/window.c b/window.c index 1c97fb8d..2afd42d3 100644 --- a/window.c +++ b/window.c @@ -908,6 +908,7 @@ window_pane_spawn(struct window_pane *wp, int argc, char **argv, free((void *)wp->cwd); wp->cwd = xstrdup(cwd); } + wp->flags &= ~(PANE_STATUSREADY|PANE_STATUSDRAWN); cmd = cmd_stringify_argv(wp->argc, wp->argv); log_debug("spawn: %s -- %s", wp->shell, cmd); From 2f6935a630507351233d6296cc6ec9a08d6a702a Mon Sep 17 00:00:00 2001 From: nicm Date: Mon, 16 Oct 2017 19:30:53 +0000 Subject: [PATCH 2/2] Infrastructure for drawing status lines of more than one line in height, still only one is allowed but this lets tmux draw bigger ones. --- resize.c | 20 ++++++----- screen-redraw.c | 88 +++++++++++++++++++++++++++++-------------------- server-client.c | 15 +++++---- status.c | 67 ++++++++++++++++++++++++++----------- tmux.h | 2 ++ tty.c | 2 +- 6 files changed, 123 insertions(+), 71 deletions(-) diff --git a/resize.c b/resize.c index 0fd30ba0..8ed359b4 100644 --- a/resize.c +++ b/resize.c @@ -49,11 +49,11 @@ recalculate_sizes(void) struct client *c; struct window *w; struct window_pane *wp; - u_int ssx, ssy, has, limit; - int flag, has_status, is_zoomed, forced; + u_int ssx, ssy, has, limit, lines; + int flag, is_zoomed, forced; RB_FOREACH(s, sessions, &sessions) { - has_status = options_get_number(s->options, "status"); + lines = status_line_size(s); s->attached = 0; ssx = ssy = UINT_MAX; @@ -66,10 +66,14 @@ recalculate_sizes(void) if (c->session == s) { if (c->tty.sx < ssx) ssx = c->tty.sx; - if (has_status && + c->flags &= ~CLIENT_STATUSOFF; + if (lines != 0 && lines + PANE_MINIMUM > c->tty.sy) + c->flags |= CLIENT_STATUSOFF; + if ((~c->flags & CLIENT_STATUSOFF) && !(c->flags & CLIENT_CONTROL) && - c->tty.sy > 1 && c->tty.sy - 1 < ssy) - ssy = c->tty.sy - 1; + c->tty.sy > lines && + c->tty.sy - lines < ssy) + ssy = c->tty.sy - lines; else if (c->tty.sy < ssy) ssy = c->tty.sy; s->attached++; @@ -81,8 +85,8 @@ recalculate_sizes(void) } s->flags &= ~SESSION_UNATTACHED; - if (has_status && ssy == 0) - ssy = 1; + if (lines != 0 && ssy == 0) + ssy = lines; if (s->sx == ssx && s->sy == ssy) continue; diff --git a/screen-redraw.c b/screen-redraw.c index 6c4d84d8..7a31182a 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -33,11 +33,11 @@ static int screen_redraw_make_pane_status(struct client *, struct window *, struct window_pane *); static void screen_redraw_draw_pane_status(struct client *, int); -static void screen_redraw_draw_borders(struct client *, int, int, u_int); -static void screen_redraw_draw_panes(struct client *, u_int); -static void screen_redraw_draw_status(struct client *, u_int); +static void screen_redraw_draw_borders(struct client *, int, u_int, u_int); +static void screen_redraw_draw_panes(struct client *, u_int, u_int); +static void screen_redraw_draw_status(struct client *, u_int, u_int); static void screen_redraw_draw_number(struct client *, struct window_pane *, - u_int); + u_int, u_int); #define CELL_INSIDE 0 #define CELL_LEFTRIGHT 1 @@ -377,36 +377,38 @@ screen_redraw_screen(struct client *c, int draw_panes, int draw_status, struct tty *tty = &c->tty; struct window *w = c->session->curw->window; struct options *wo = w->options; - u_int top; - int status, pane_status, spos; + u_int top, lines; + int position, pane_status; - /* Suspended clients should not be updated. */ if (c->flags & CLIENT_SUSPENDED) return; - /* Get status line, er, status. */ - spos = options_get_number(oo, "status-position"); - if (c->message_string != NULL || c->prompt_string != NULL) - status = 1; + if (c->flags & CLIENT_STATUSOFF) + lines = 0; else - status = options_get_number(oo, "status"); - top = 0; - if (status && spos == 0) + lines = status_line_size(c->session); + if (c->message_string != NULL || c->prompt_string != NULL) + lines = (lines == 0) ? 1 : lines; + + position = options_get_number(oo, "status-position"); + if (lines != 0 && position == 0) top = 1; - if (!status) + else + top = 0; + + if (lines == 0) draw_status = 0; - /* Draw the elements. */ if (draw_borders) { pane_status = options_get_number(wo, "pane-border-status"); - screen_redraw_draw_borders(c, status, pane_status, top); + screen_redraw_draw_borders(c, pane_status, lines, top); if (pane_status != CELL_STATUS_OFF) screen_redraw_draw_pane_status(c, pane_status); } if (draw_panes) - screen_redraw_draw_panes(c, top); + screen_redraw_draw_panes(c, lines, top); if (draw_status) - screen_redraw_draw_status(c, top); + screen_redraw_draw_status(c, lines, top); tty_reset(tty); } @@ -421,7 +423,7 @@ screen_redraw_pane(struct client *c, struct window_pane *wp) yoff = wp->yoff; if (status_at_line(c) == 0) - yoff++; + yoff += status_line_size(c->session); log_debug("%s: redraw pane %%%u (at %u,%u)", c->name, wp->id, wp->xoff, yoff); @@ -433,7 +435,7 @@ screen_redraw_pane(struct client *c, struct window_pane *wp) /* Draw the borders. */ static void -screen_redraw_draw_borders(struct client *c, int status, int pane_status, +screen_redraw_draw_borders(struct client *c, int pane_status, u_int lines, u_int top) { struct session *s = c->session; @@ -449,7 +451,7 @@ screen_redraw_draw_borders(struct client *c, int status, int pane_status, const char *tmp; size_t msglen = 0; - small = (tty->sy - status + top > w->sy) || (tty->sx > w->sx); + small = (tty->sy - lines + top > w->sy) || (tty->sx > w->sx); if (small) { flags = w->flags & (WINDOW_FORCEWIDTH|WINDOW_FORCEHEIGHT); if (flags == (WINDOW_FORCEWIDTH|WINDOW_FORCEHEIGHT)) @@ -458,18 +460,20 @@ screen_redraw_draw_borders(struct client *c, int status, int pane_status, tmp = "force-width"; else if (flags == WINDOW_FORCEHEIGHT) tmp = "force-height"; + else if (c->flags & CLIENT_STATUSOFF) + tmp = "status line"; else tmp = "a smaller client"; xsnprintf(msg, sizeof msg, "(size %ux%u from %s)", w->sx, w->sy, tmp); msglen = strlen(msg); - if (tty->sy - 1 - status + top > w->sy && tty->sx >= msglen) { + if (tty->sy - 1 - lines + top > w->sy && tty->sx >= msglen) { msgx = tty->sx - msglen; - msgy = tty->sy - 1 - status + top; + msgy = tty->sy - 1 - lines + top; } else if (tty->sx - w->sx > msglen) { msgx = tty->sx - msglen; - msgy = tty->sy - 1 - status + top; + msgy = tty->sy - 1 - lines + top; } else small = 0; } @@ -483,7 +487,7 @@ screen_redraw_draw_borders(struct client *c, int status, int pane_status, memcpy(&m_active_gc, &active_gc, sizeof m_active_gc); m_active_gc.attr ^= GRID_ATTR_REVERSE; - for (j = 0; j < tty->sy - status; j++) { + for (j = 0; j < tty->sy - lines; j++) { for (i = 0; i < tty->sx; i++) { type = screen_redraw_check_cell(c, i, j, pane_status, &wp); @@ -505,7 +509,10 @@ screen_redraw_draw_borders(struct client *c, int status, int pane_status, tty_attributes(tty, &active_gc, NULL); else tty_attributes(tty, &other_gc, NULL); - tty_cursor(tty, i, top + j); + if (top) + tty_cursor(tty, i, lines + j); + else + tty_cursor(tty, i, j); tty_putc(tty, CELL_BORDERS[type]); } } @@ -520,38 +527,47 @@ screen_redraw_draw_borders(struct client *c, int status, int pane_status, /* Draw the panes. */ static void -screen_redraw_draw_panes(struct client *c, u_int top) +screen_redraw_draw_panes(struct client *c, u_int lines, u_int top) { struct window *w = c->session->curw->window; struct tty *tty = &c->tty; struct window_pane *wp; - u_int i; + u_int i, y; + + if (top) + y = lines; + else + y = 0; TAILQ_FOREACH(wp, &w->panes, entry) { if (!window_pane_visible(wp)) continue; for (i = 0; i < wp->sy; i++) - tty_draw_pane(tty, wp, i, wp->xoff, top + wp->yoff); + tty_draw_pane(tty, wp, i, wp->xoff, y + wp->yoff); if (c->flags & CLIENT_IDENTIFY) - screen_redraw_draw_number(c, wp, top); + screen_redraw_draw_number(c, wp, lines, top); } } /* Draw the status line. */ static void -screen_redraw_draw_status(struct client *c, u_int top) +screen_redraw_draw_status(struct client *c, u_int lines, u_int top) { struct tty *tty = &c->tty; + u_int i, y; if (top) - tty_draw_line(tty, NULL, &c->status, 0, 0, 0); + y = 0; else - tty_draw_line(tty, NULL, &c->status, 0, 0, tty->sy - 1); + y = tty->sy - lines; + for (i = 0; i < lines; i++) + tty_draw_line(tty, NULL, &c->status, i, 0, y); } /* Draw number on a pane. */ static void -screen_redraw_draw_number(struct client *c, struct window_pane *wp, u_int top) +screen_redraw_draw_number(struct client *c, struct window_pane *wp, + u_int lines, u_int top) { struct tty *tty = &c->tty; struct session *s = c->session; @@ -576,7 +592,7 @@ screen_redraw_draw_number(struct client *c, struct window_pane *wp, u_int top) xoff = wp->xoff; yoff = wp->yoff; if (top) - yoff++; + yoff += lines; if (wp->sx < len * 6 || wp->sy < 5) { tty_cursor(tty, xoff + px - len / 2, yoff + py); diff --git a/server-client.c b/server-client.c index 0b4146a8..aa0f838e 100644 --- a/server-client.c +++ b/server-client.c @@ -1201,7 +1201,7 @@ server_client_reset_state(struct client *c) struct window_pane *wp = w->active, *loop; struct screen *s = wp->screen; struct options *oo = c->session->options; - int status, mode, o; + int lines, mode; if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED)) return; @@ -1209,13 +1209,14 @@ server_client_reset_state(struct client *c) tty_region_off(&c->tty); tty_margin_off(&c->tty); - status = options_get_number(oo, "status"); - if (!window_pane_visible(wp) || wp->yoff + s->cy >= c->tty.sy - status) + if (status_at_line(c) != 0) + lines = 0; + else + lines = status_line_size(c->session); + if (!window_pane_visible(wp) || wp->yoff + s->cy >= c->tty.sy - lines) tty_cursor(&c->tty, 0, 0); - else { - o = status && options_get_number(oo, "status-position") == 0; - tty_cursor(&c->tty, wp->xoff + s->cx, o + wp->yoff + s->cy); - } + else + tty_cursor(&c->tty, wp->xoff + s->cx, lines + wp->yoff + s->cy); /* * Set mouse mode if requested. To support dragging, always use button diff --git a/status.c b/status.c index b7d24715..a696d561 100644 --- a/status.c +++ b/status.c @@ -210,9 +210,24 @@ status_at_line(struct client *c) { struct session *s = c->session; + if (c->flags & CLIENT_STATUSOFF) + return (-1); if (s->statusat != 1) return (s->statusat); - return (c->tty.sy - 1); + return (c->tty.sy - status_line_size(s)); +} + +/* + * Get size of status line for session. 0 means off. Note that status line may + * be forced off for an individual client if it is too small (the + * CLIENT_STATUSOFF flag is set for this). + */ +u_int +status_line_size(struct session *s) +{ + if (s->statusat == -1) + return (0); + return (1); } /* Retrieve options for left string. */ @@ -296,7 +311,7 @@ status_redraw(struct client *c) time_t t; char *left, *right; const char *sep; - u_int offset, needed; + u_int offset, needed, lines; u_int wlstart, wlwidth, wlavailable, wloffset, wlsize; size_t llen, rlen, seplen; int larrow, rarrow; @@ -309,7 +324,8 @@ status_redraw(struct client *c) } /* No status line? */ - if (c->tty.sy == 0 || !options_get_number(s->options, "status")) + lines = status_line_size(s); + if (c->tty.sy == 0 || lines == 0) return (1); left = right = NULL; larrow = rarrow = 0; @@ -322,14 +338,13 @@ status_redraw(struct client *c) /* Create the target screen. */ memcpy(&old_status, &c->status, sizeof old_status); - screen_init(&c->status, c->tty.sx, 1, 0); + screen_init(&c->status, c->tty.sx, lines, 0); screen_write_start(&ctx, NULL, &c->status); - for (offset = 0; offset < c->tty.sx; offset++) - screen_write_putc(&ctx, &stdgc, ' '); + screen_write_clearscreen(&ctx, stdgc.bg); screen_write_stop(&ctx); - /* If the height is one line, blank status line. */ - if (c->tty.sy <= 1) + /* If the height is too small, blank status line. */ + if (c->tty.sy < lines) goto out; /* Work out left and right strings. */ @@ -637,11 +652,17 @@ status_message_redraw(struct client *c) struct screen old_status; size_t len; struct grid_cell gc; + u_int lines; if (c->tty.sx == 0 || c->tty.sy == 0) return (0); memcpy(&old_status, &c->status, sizeof old_status); - screen_init(&c->status, c->tty.sx, 1, 0); + + lines = status_line_size(c->session); + if (lines <= 1) + screen_init(&c->status, c->tty.sx, 1, 0); + else + screen_init(&c->status, c->tty.sx, lines, 0); len = screen_write_strlen("%s", c->message_string); if (len > c->tty.sx) @@ -650,12 +671,9 @@ status_message_redraw(struct client *c) style_apply(&gc, s->options, "message-style"); screen_write_start(&ctx, NULL, &c->status); - - screen_write_cursormove(&ctx, 0, 0); + screen_write_clearscreen(&ctx, gc.bg); + screen_write_cursormove(&ctx, 0, lines - 1); screen_write_nputs(&ctx, len, &gc, "%s", c->message_string); - for (; len < c->tty.sx; len++) - screen_write_putc(&ctx, &gc, ' '); - screen_write_stop(&ctx); if (grid_compare(c->status.grid, old_status.grid) == 0) { @@ -782,12 +800,24 @@ status_prompt_redraw(struct client *c) struct session *s = c->session; struct screen old_status; u_int i, offset, left, start, pcursor, pwidth, width; + u_int lines; + size_t len, off; struct grid_cell gc, cursorgc; if (c->tty.sx == 0 || c->tty.sy == 0) return (0); memcpy(&old_status, &c->status, sizeof old_status); - screen_init(&c->status, c->tty.sx, 1, 0); + + lines = status_line_size(c->session); + if (lines <= 1) + screen_init(&c->status, c->tty.sx, 1, 0); + else + screen_init(&c->status, c->tty.sx, lines, 0); + + len = screen_write_strlen("%s", c->prompt_string); + if (len > c->tty.sx) + len = c->tty.sx; + off = 0; if (c->prompt_mode == PROMPT_COMMAND) style_apply(&gc, s->options, "message-command-style"); @@ -802,11 +832,10 @@ status_prompt_redraw(struct client *c) start = c->tty.sx; screen_write_start(&ctx, NULL, &c->status); - screen_write_cursormove(&ctx, 0, 0); + screen_write_clearscreen(&ctx, gc.bg); + screen_write_cursormove(&ctx, 0, lines - 1); screen_write_nputs(&ctx, start, &gc, "%s", c->prompt_string); - while (c->status.cx < screen_size_x(&c->status)) - screen_write_putc(&ctx, &gc, ' '); - screen_write_cursormove(&ctx, start, 0); + screen_write_cursormove(&ctx, start, lines - 1); left = c->tty.sx - start; if (left == 0) diff --git a/tmux.h b/tmux.h index ad35c336..6cb9a06f 100644 --- a/tmux.h +++ b/tmux.h @@ -1381,6 +1381,7 @@ struct client { #define CLIENT_DOUBLECLICK 0x100000 #define CLIENT_TRIPLECLICK 0x200000 #define CLIENT_SIZECHANGED 0x400000 +#define CLIENT_STATUSOFF 0x800000 int flags; struct key_table *keytable; @@ -1928,6 +1929,7 @@ void status_timer_start(struct client *); void status_timer_start_all(void); void status_update_saved(struct session *s); int status_at_line(struct client *); +u_int status_line_size(struct session *); struct window *status_get_window_at(struct client *, u_int); int status_redraw(struct client *); void printflike(2, 3) status_message_set(struct client *, const char *, ...); diff --git a/tty.c b/tty.c index 0d1aa368..90361e3f 100644 --- a/tty.c +++ b/tty.c @@ -1038,7 +1038,7 @@ tty_write(void (*cmdfn)(struct tty *, const struct tty_ctx *), ctx->xoff = wp->xoff; ctx->yoff = wp->yoff; if (status_at_line(c) == 0) - ctx->yoff++; + ctx->yoff += status_line_size(c->session); cmdfn(&c->tty, ctx); }