summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornicm <nicm>2016-04-29 15:00:48 +0000
committernicm <nicm>2016-04-29 15:00:48 +0000
commit0509be07404a4f4626bbdab56d858f657dc68604 (patch)
treeae0d8196081ac903121f0d2e4ac754a763a3689d
parent0d84fdd95303a6ed4dcd761425e35f3731b86725 (diff)
Add option to include status text in the pane borders. If
pane-border-status is set to "top" or "bottom" (rather than "off"), every pane has a permanent top or bottom border containing the text from pane-border-format. Based on a diff sent long ago by Jonathan Slenders, mostly rewritten and simplified by me.
-rw-r--r--cmd-set-option.c6
-rw-r--r--layout.c50
-rw-r--r--options-table.c16
-rw-r--r--screen-redraw.c175
-rw-r--r--server-client.c14
-rw-r--r--tmux.18
-rw-r--r--tmux.h3
-rw-r--r--window.c2
8 files changed, 239 insertions, 35 deletions
diff --git a/cmd-set-option.c b/cmd-set-option.c
index b1771436..6fc6c8ba 100644
--- a/cmd-set-option.c
+++ b/cmd-set-option.c
@@ -201,6 +201,12 @@ cmd_set_option_exec(struct cmd *self, struct cmd_q *cmdq)
if (strcmp(oe->name, "monitor-silence") == 0)
alerts_reset_all();
+ /* When the pane-border-status option has been changed, resize panes. */
+ if (strcmp(oe->name, "pane-border-status") == 0) {
+ RB_FOREACH(w, windows, &windows)
+ layout_fix_panes(w, w->sx, w->sy);
+ }
+
/* Update sizes and redraw. May not need it but meh. */
recalculate_sizes();
TAILQ_FOREACH(c, &clients, entry) {
diff --git a/layout.c b/layout.c
index 31dce95c..a73ba527 100644
--- a/layout.c
+++ b/layout.c
@@ -32,8 +32,11 @@
* cell a pointer to its parent cell.
*/
-int layout_resize_pane_grow(struct layout_cell *, enum layout_type, int);
-int layout_resize_pane_shrink(struct layout_cell *, enum layout_type, int);
+static int layout_resize_pane_grow(struct layout_cell *, enum layout_type,
+ int);
+static int layout_resize_pane_shrink(struct layout_cell *,
+ enum layout_type, int);
+static int layout_need_status(struct layout_cell *, int);
struct layout_cell *
layout_create_cell(struct layout_cell *lcparent)
@@ -163,6 +166,30 @@ layout_fix_offsets(struct layout_cell *lc)
}
}
+/*
+ * Returns 1 if we need to reserve space for the pane status line. This is the
+ * case for the most upper panes only.
+ */
+static int
+layout_need_status(struct layout_cell *lc, int at_top)
+{
+ struct layout_cell *first_lc;
+
+ if (lc->parent) {
+ if (lc->parent->type == LAYOUT_LEFTRIGHT)
+ return (layout_need_status(lc->parent, at_top));
+
+ if (at_top)
+ first_lc = TAILQ_FIRST(&lc->parent->cells);
+ else
+ first_lc = TAILQ_LAST(&lc->parent->cells,layout_cells);
+ if (lc == first_lc)
+ return (layout_need_status(lc->parent, at_top));
+ return (0);
+ }
+ return (1);
+}
+
/* Update pane offsets and sizes based on their cells. */
void
layout_fix_panes(struct window *w, u_int wsx, u_int wsy)
@@ -170,13 +197,25 @@ layout_fix_panes(struct window *w, u_int wsx, u_int wsy)
struct window_pane *wp;
struct layout_cell *lc;
u_int sx, sy;
+ int shift, status, at_top;
+ status = options_get_number(w->options, "pane-border-status");
+ at_top = (status == 1);
TAILQ_FOREACH(wp, &w->panes, entry) {
if ((lc = wp->layout_cell) == NULL)
continue;
+
+ if (status != 0)
+ shift = layout_need_status(lc, at_top);
+ else
+ shift = 0;
+
wp->xoff = lc->xoff;
wp->yoff = lc->yoff;
+ if (shift && at_top)
+ wp->yoff += 1;
+
/*
* Layout cells are limited by the smallest size of other cells
* within the same row or column; if this isn't the case
@@ -214,6 +253,9 @@ layout_fix_panes(struct window *w, u_int wsx, u_int wsy)
sy = lc->sy;
}
+ if (shift)
+ sy -= 1;
+
window_pane_resize(wp, sx, sy);
}
}
@@ -520,7 +562,7 @@ layout_resize_pane(struct window_pane *wp, enum layout_type type, int change)
}
/* Helper function to grow pane. */
-int
+static int
layout_resize_pane_grow(struct layout_cell *lc, enum layout_type type,
int needed)
{
@@ -561,7 +603,7 @@ layout_resize_pane_grow(struct layout_cell *lc, enum layout_type type,
}
/* Helper function to shrink pane. */
-int
+static int
layout_resize_pane_shrink(struct layout_cell *lc, enum layout_type type,
int needed)
{
diff --git a/options-table.c b/options-table.c
index af0f41ed..c55ce715 100644
--- a/options-table.c
+++ b/options-table.c
@@ -51,6 +51,9 @@ const char *options_table_status_position_list[] = {
const char *options_table_bell_action_list[] = {
"none", "any", "current", "other", NULL
};
+const char *options_table_pane_status_list[] = {
+ "off", "top", "bottom", NULL
+};
/* Server options. */
const struct options_table_entry options_table[] = {
@@ -693,6 +696,19 @@ const struct options_table_entry options_table[] = {
.style = "pane-border-style"
},
+ { .name = "pane-border-format",
+ .type = OPTIONS_TABLE_STRING,
+ .scope = OPTIONS_TABLE_WINDOW,
+ .default_str = "#{?pane_active,#[reverse],}#{pane_index}#[default] \"#{pane_title}\""
+ },
+
+ { .name = "pane-border-status",
+ .type = OPTIONS_TABLE_CHOICE,
+ .scope = OPTIONS_TABLE_WINDOW,
+ .choices = options_table_pane_status_list,
+ .default_num = 0
+ },
+
{ .name = "pane-border-style",
.type = OPTIONS_TABLE_STYLE,
.scope = OPTIONS_TABLE_WINDOW,
diff --git a/screen-redraw.c b/screen-redraw.c
index 952a8515..694f6c27 100644
--- a/screen-redraw.c
+++ b/screen-redraw.c
@@ -24,12 +24,16 @@
int screen_redraw_cell_border1(struct window_pane *, u_int, u_int);
int screen_redraw_cell_border(struct client *, u_int, u_int);
-int screen_redraw_check_cell(struct client *, u_int, u_int,
+int screen_redraw_check_cell(struct client *, u_int, u_int, int,
struct window_pane **);
-int screen_redraw_check_is(u_int, u_int, int, struct window *,
+int screen_redraw_check_is(u_int, u_int, int, int, struct window *,
struct window_pane *, struct window_pane *);
-void screen_redraw_draw_borders(struct client *, int, u_int);
+int screen_redraw_make_pane_status(struct client *, struct window *,
+ struct window_pane *);
+void screen_redraw_draw_pane_status(struct client *, int);
+
+void screen_redraw_draw_borders(struct client *, int, int, u_int);
void screen_redraw_draw_panes(struct client *, u_int);
void screen_redraw_draw_status(struct client *, u_int);
void screen_redraw_draw_number(struct client *, struct window_pane *, u_int);
@@ -50,6 +54,10 @@ void screen_redraw_draw_number(struct client *, struct window_pane *, u_int);
#define CELL_BORDERS " xqlkmjwvtun~"
+#define CELL_STATUS_OFF 0
+#define CELL_STATUS_TOP 1
+#define CELL_STATUS_BOTTOM 2
+
/* Check if cell is on the border of a particular pane. */
int
screen_redraw_cell_border1(struct window_pane *wp, u_int px, u_int py)
@@ -64,15 +72,15 @@ screen_redraw_cell_border1(struct window_pane *wp, u_int px, u_int py)
if (wp->xoff != 0 && px == wp->xoff - 1)
return (1);
if (px == wp->xoff + wp->sx)
- return (1);
+ return (2);
}
/* Top/bottom borders. */
if ((wp->xoff == 0 || px >= wp->xoff - 1) && px <= wp->xoff + wp->sx) {
if (wp->yoff != 0 && py == wp->yoff - 1)
- return (1);
+ return (3);
if (py == wp->yoff + wp->sy)
- return (1);
+ return (4);
}
/* Outside pane. */
@@ -92,7 +100,7 @@ screen_redraw_cell_border(struct client *c, u_int px, u_int py)
if (!window_pane_visible(wp))
continue;
if ((retval = screen_redraw_cell_border1(wp, px, py)) != -1)
- return (retval);
+ return (!!retval);
}
return (0);
@@ -100,16 +108,33 @@ screen_redraw_cell_border(struct client *c, u_int px, u_int py)
/* Check if cell inside a pane. */
int
-screen_redraw_check_cell(struct client *c, u_int px, u_int py,
+screen_redraw_check_cell(struct client *c, u_int px, u_int py, int pane_status,
struct window_pane **wpp)
{
struct window *w = c->session->curw->window;
struct window_pane *wp;
int borders;
+ u_int right, line;
if (px > w->sx || py > w->sy)
return (CELL_OUTSIDE);
+ if (pane_status != CELL_STATUS_OFF) {
+ TAILQ_FOREACH(wp, &w->panes, entry) {
+ if (!window_pane_visible(wp))
+ continue;
+
+ if (pane_status == CELL_STATUS_TOP)
+ line = wp->yoff - 1;
+ else
+ line = wp->yoff + wp->sy;
+ right = wp->xoff + 2 + wp->status_size - 1;
+
+ if (py == line && px >= wp->xoff + 2 && px <= right)
+ return (CELL_INSIDE);
+ }
+ }
+
TAILQ_FOREACH(wp, &w->panes, entry) {
if (!window_pane_visible(wp))
continue;
@@ -135,8 +160,13 @@ screen_redraw_check_cell(struct client *c, u_int px, u_int py,
borders |= 8;
if (px <= w->sx && screen_redraw_cell_border(c, px + 1, py))
borders |= 4;
- if (py == 0 || screen_redraw_cell_border(c, px, py - 1))
- borders |= 2;
+ if (pane_status == CELL_STATUS_TOP) {
+ if (py != 0 && screen_redraw_cell_border(c, px, py - 1))
+ borders |= 2;
+ } else {
+ if (py == 0 || screen_redraw_cell_border(c, px, py - 1))
+ borders |= 2;
+ }
if (py <= w->sy && screen_redraw_cell_border(c, px, py + 1))
borders |= 1;
@@ -177,11 +207,18 @@ screen_redraw_check_cell(struct client *c, u_int px, u_int py,
/* Check if the border of a particular pane. */
int
-screen_redraw_check_is(u_int px, u_int py, int type, struct window *w,
- struct window_pane *wantwp, struct window_pane *wp)
+screen_redraw_check_is(u_int px, u_int py, int type, int pane_status,
+ struct window *w, struct window_pane *wantwp, struct window_pane *wp)
{
+ int border;
+
/* Is this off the active pane border? */
- if (screen_redraw_cell_border1(wantwp, px, py) != 1)
+ border = screen_redraw_cell_border1(wantwp, px, py);
+ if (border == 0 || border == -1)
+ return (0);
+ if (pane_status == CELL_STATUS_TOP && border == 4)
+ return (0);
+ if (pane_status == CELL_STATUS_BOTTOM && border == 3)
return (0);
/* If there are more than two panes, that's enough. */
@@ -192,6 +229,10 @@ screen_redraw_check_is(u_int px, u_int py, int type, struct window *w,
if (wp == NULL || (type == CELL_OUTSIDE || type == CELL_INSIDE))
return (1);
+ /* With status lines mark the entire line. */
+ if (pane_status != CELL_STATUS_OFF)
+ return (1);
+
/* Check if the pane covers the whole width. */
if (wp->xoff == 0 && wp->sx == w->sx) {
/* This can either be the top pane or the bottom pane. */
@@ -214,7 +255,77 @@ screen_redraw_check_is(u_int px, u_int py, int type, struct window *w,
return (0);
}
- return (type);
+ return (1);
+}
+
+/* Update pane status. */
+int
+screen_redraw_make_pane_status(struct client *c, struct window *w,
+ struct window_pane *wp)
+{
+ struct grid_cell gc;
+ const char *fmt;
+ struct format_tree *ft;
+ char *out;
+ size_t outlen, old_size = wp->status_size;
+ struct screen_write_ctx ctx;
+
+ if (wp == w->active)
+ style_apply(&gc, w->options, "pane-active-border-style");
+ else
+ style_apply(&gc, w->options, "pane-border-style");
+
+ fmt = options_get_string(w->options, "pane-border-format");
+
+ ft = format_create(NULL, 0);
+ format_defaults(ft, c, NULL, NULL, wp);
+
+ screen_free(&wp->status_screen);
+ screen_init(&wp->status_screen, wp->sx, 1, 0);
+ wp->status_screen.mode = 0;
+
+ out = format_expand(ft, fmt);
+ outlen = screen_write_cstrlen("%s", out);
+ if (outlen > wp->sx - 4)
+ outlen = wp->sx - 4;
+ screen_resize(&wp->status_screen, outlen, 1, 0);
+
+ screen_write_start(&ctx, NULL, &wp->status_screen);
+ screen_write_cursormove(&ctx, 0, 0);
+ screen_write_clearline(&ctx);
+ screen_write_cnputs(&ctx, outlen, &gc, "%s", out);
+ screen_write_stop(&ctx);
+
+ format_free(ft);
+
+ wp->status_size = outlen;
+ return (wp->status_size != old_size);
+}
+
+/* Draw pane status. */
+void
+screen_redraw_draw_pane_status(struct client *c, int pane_status)
+{
+ struct window *w = c->session->curw->window;
+ struct options *oo = c->session->options;
+ struct tty *tty = &c->tty;
+ struct window_pane *wp;
+ int spos;
+ u_int yoff;
+
+ spos = options_get_number(oo, "status-position");
+ TAILQ_FOREACH(wp, &w->panes, entry) {
+ if (pane_status == CELL_STATUS_TOP)
+ yoff = wp->yoff - 1;
+ else
+ yoff = wp->yoff + wp->sy;
+ if (spos == 0)
+ yoff += 1;
+
+ tty_draw_line(tty, NULL, &wp->status_screen, 0, wp->xoff + 2,
+ yoff);
+ }
+ tty_cursor(tty, 0, 0);
}
/* Redraw entire screen. */
@@ -222,10 +333,12 @@ void
screen_redraw_screen(struct client *c, int draw_panes, int draw_status,
int draw_borders)
{
- struct options *oo = c->session->options;
- struct tty *tty = &c->tty;
- u_int top;
- int status, spos;
+ struct options *oo = c->session->options;
+ struct tty *tty = &c->tty;
+ struct window *w = c->session->curw->window;
+ struct window_pane *wp;
+ u_int top;
+ int status, pane_status, spos;
/* Suspended clients should not be updated. */
if (c->flags & CLIENT_SUSPENDED)
@@ -243,12 +356,24 @@ screen_redraw_screen(struct client *c, int draw_panes, int draw_status,
if (!status)
draw_status = 0;
+ /* Update pane status lines. */
+ pane_status = options_get_number(w->options, "pane-border-status");
+ if (pane_status != CELL_STATUS_OFF && (draw_borders || draw_status)) {
+ TAILQ_FOREACH(wp, &w->panes, entry) {
+ if (screen_redraw_make_pane_status(c, w, wp))
+ draw_borders = draw_status = 1;
+ }
+ }
+
+ /* Draw the elements. */
if (draw_borders)
- screen_redraw_draw_borders(c, status, top);
+ screen_redraw_draw_borders(c, status, pane_status, top);
if (draw_panes)
screen_redraw_draw_panes(c, top);
if (draw_status)
screen_redraw_draw_status(c, top);
+ if (pane_status != CELL_STATUS_OFF && (draw_borders || draw_status))
+ screen_redraw_draw_pane_status(c, pane_status);
tty_reset(tty);
}
@@ -272,7 +397,8 @@ screen_redraw_pane(struct client *c, struct window_pane *wp)
/* Draw the borders. */
void
-screen_redraw_draw_borders(struct client *c, int status, u_int top)
+screen_redraw_draw_borders(struct client *c, int status, int pane_status,
+ u_int top)
{
struct session *s = c->session;
struct window *w = s->curw->window;
@@ -323,16 +449,17 @@ screen_redraw_draw_borders(struct client *c, int status, u_int top)
for (j = 0; j < tty->sy - status; j++) {
for (i = 0; i < tty->sx; i++) {
- type = screen_redraw_check_cell(c, i, j, &wp);
+ type = screen_redraw_check_cell(c, i, j, pane_status,
+ &wp);
if (type == CELL_INSIDE)
continue;
if (type == CELL_OUTSIDE && small &&
i > msgx && j == msgy)
continue;
- active = screen_redraw_check_is(i, j, type, w,
- w->active, wp);
+ active = screen_redraw_check_is(i, j, type, pane_status,
+ w, w->active, wp);
if (server_is_marked(s, s->curw, marked_pane.wp) &&
- screen_redraw_check_is(i, j, type, w,
+ screen_redraw_check_is(i, j, type, pane_status, w,
marked_pane.wp, wp)) {
if (active)
tty_attributes(tty, &m_active_gc, NULL);
diff --git a/server-client.c b/server-client.c
index 9dad52fe..08f48b31 100644
--- a/server-client.c
+++ b/server-client.c
@@ -921,7 +921,7 @@ server_client_check_redraw(struct client *c)
struct session *s = c->session;
struct tty *tty = &c->tty;
struct window_pane *wp;
- int flags, redraw;
+ int flags, masked, redraw;
if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED))
return;
@@ -961,15 +961,15 @@ server_client_check_redraw(struct client *c)
}
}
- if (c->flags & CLIENT_BORDERS) {
+ masked = c->flags & (CLIENT_BORDERS|CLIENT_STATUS);
+ if (masked != 0)
tty_update_mode(tty, tty->mode, NULL);
+ if (masked == CLIENT_BORDERS)
screen_redraw_screen(c, 0, 0, 1);
- }
-
- if (c->flags & CLIENT_STATUS) {
- tty_update_mode(tty, tty->mode, NULL);
+ else if (masked == CLIENT_STATUS)
screen_redraw_screen(c, 0, 1, 0);
- }
+ else if (masked != 0)
+ screen_redraw_screen(c, 0, 1, 1);
tty->flags = (tty->flags & ~(TTY_FREEZE|TTY_NOCURSOR)) | flags;
tty_update_mode(tty, tty->mode, NULL);
diff --git a/tmux.1 b/tmux.1
index 0aeefc32..a5956f18 100644
--- a/tmux.1
+++ b/tmux.1
@@ -3065,6 +3065,14 @@ Like
.Ic base-index ,
but set the starting index for pane numbers.
.Pp
+.It Ic pane-border-format Ar format
+Set the text shown in pane border status lines.
+.Pp
+.It Xo Ic pane-border-status
+.Op Ic off | top | bottom
+.Xc
+Turn pane border status lines off or set their position.
+.Pp
.It Ic pane-border-style Ar style
Set the pane border style for panes aside from the active pane.
For how to specify
diff --git a/tmux.h b/tmux.h
index d6cf114e..f81ed127 100644
--- a/tmux.h
+++ b/tmux.h
@@ -894,6 +894,9 @@ struct window_pane {
struct screen *screen;
struct screen base;
+ struct screen status_screen;
+ size_t status_size;
+
/* Saved in alternative screen mode. */
u_int saved_cx;
u_int saved_cy;
diff --git a/window.c b/window.c
index ff90906f..ad7f36d9 100644
--- a/window.c
+++ b/window.c
@@ -764,6 +764,8 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
screen_init(&wp->base, sx, sy, hlimit);
wp->screen = &wp->base;
+ screen_init(&wp->status_screen, 1, 1, 0);
+
if (gethostname(host, sizeof host) == 0)
screen_set_title(&wp->base, host);