xref: /openbsd-src/usr.bin/tmux/cmd-display-panes.c (revision 0ad0daf479ce2b7e9979aff0d50e70a92a639a30)
1*0ad0daf4Snicm /* $OpenBSD: cmd-display-panes.c,v 1.46 2024/03/21 11:30:42 nicm Exp $ */
2669c539cSnicm 
3669c539cSnicm /*
498ca8272Snicm  * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
5669c539cSnicm  *
6669c539cSnicm  * Permission to use, copy, modify, and distribute this software for any
7669c539cSnicm  * purpose with or without fee is hereby granted, provided that the above
8669c539cSnicm  * copyright notice and this permission notice appear in all copies.
9669c539cSnicm  *
10669c539cSnicm  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11669c539cSnicm  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12669c539cSnicm  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13669c539cSnicm  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14669c539cSnicm  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15669c539cSnicm  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16669c539cSnicm  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17669c539cSnicm  */
18669c539cSnicm 
19669c539cSnicm #include <sys/types.h>
20669c539cSnicm 
212413453fSnicm #include <stdlib.h>
2270c21bfbSnicm #include <string.h>
232413453fSnicm 
24669c539cSnicm #include "tmux.h"
25669c539cSnicm 
26669c539cSnicm /*
27669c539cSnicm  * Display panes on a client.
28669c539cSnicm  */
29669c539cSnicm 
30e4c0b811Snicm static enum args_parse_type	cmd_display_panes_args_parse(struct args *,
31e4c0b811Snicm 				    u_int, char **);
3268e0a7f2Snicm static enum cmd_retval		cmd_display_panes_exec(struct cmd *,
3368e0a7f2Snicm 				    struct cmdq_item *);
342413453fSnicm 
35669c539cSnicm const struct cmd_entry cmd_display_panes_entry = {
36c057646bSnicm 	.name = "display-panes",
37c057646bSnicm 	.alias = "displayp",
38c057646bSnicm 
39e4c0b811Snicm 	.args = { "bd:Nt:", 0, 1, cmd_display_panes_args_parse },
4088eb9092Snicm 	.usage = "[-bN] [-d duration] " CMD_TARGET_CLIENT_USAGE " [template]",
41c057646bSnicm 
42035dc73dSnicm 	.flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG,
43c057646bSnicm 	.exec = cmd_display_panes_exec
44669c539cSnicm };
45669c539cSnicm 
4670c21bfbSnicm struct cmd_display_panes_data {
4770c21bfbSnicm 	struct cmdq_item		*item;
482db6a388Snicm 	struct args_command_state	*state;
4970c21bfbSnicm };
5070c21bfbSnicm 
51e4c0b811Snicm static enum args_parse_type
cmd_display_panes_args_parse(__unused struct args * args,__unused u_int idx,__unused char ** cause)52e4c0b811Snicm cmd_display_panes_args_parse(__unused struct args *args, __unused u_int idx,
53e4c0b811Snicm     __unused char **cause)
54e4c0b811Snicm {
55e4c0b811Snicm 	return (ARGS_PARSE_COMMANDS_OR_STRING);
56e4c0b811Snicm }
57e4c0b811Snicm 
5870c21bfbSnicm static void
cmd_display_panes_draw_pane(struct screen_redraw_ctx * ctx,struct window_pane * wp)5970c21bfbSnicm cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
6070c21bfbSnicm     struct window_pane *wp)
61669c539cSnicm {
6270c21bfbSnicm 	struct client		*c = ctx->c;
6370c21bfbSnicm 	struct tty		*tty = &c->tty;
6470c21bfbSnicm 	struct session		*s = c->session;
6570c21bfbSnicm 	struct options		*oo = s->options;
6670c21bfbSnicm 	struct window		*w = wp->window;
67cf629db8Snicm 	struct grid_cell	 fgc, bgc;
68cf629db8Snicm 	u_int			 pane, idx, px, py, i, j, xoff, yoff, sx, sy;
6970c21bfbSnicm 	int			 colour, active_colour;
70cf629db8Snicm 	char			 buf[16], lbuf[16], rbuf[16], *ptr;
71cf629db8Snicm 	size_t			 len, llen, rlen;
72bf0d297eSnicm 
7370c21bfbSnicm 	if (wp->xoff + wp->sx <= ctx->ox ||
7470c21bfbSnicm 	    wp->xoff >= ctx->ox + ctx->sx ||
7570c21bfbSnicm 	    wp->yoff + wp->sy <= ctx->oy ||
7670c21bfbSnicm 	    wp->yoff >= ctx->oy + ctx->sy)
7770c21bfbSnicm 		return;
782413453fSnicm 
7970c21bfbSnicm 	if (wp->xoff >= ctx->ox && wp->xoff + wp->sx <= ctx->ox + ctx->sx) {
8070c21bfbSnicm 		/* All visible. */
8170c21bfbSnicm 		xoff = wp->xoff - ctx->ox;
8270c21bfbSnicm 		sx = wp->sx;
8370c21bfbSnicm 	} else if (wp->xoff < ctx->ox &&
8470c21bfbSnicm 	    wp->xoff + wp->sx > ctx->ox + ctx->sx) {
8570c21bfbSnicm 		/* Both left and right not visible. */
8670c21bfbSnicm 		xoff = 0;
8770c21bfbSnicm 		sx = ctx->sx;
8870c21bfbSnicm 	} else if (wp->xoff < ctx->ox) {
8970c21bfbSnicm 		/* Left not visible. */
9070c21bfbSnicm 		xoff = 0;
9170c21bfbSnicm 		sx = wp->sx - (ctx->ox - wp->xoff);
9270c21bfbSnicm 	} else {
9370c21bfbSnicm 		/* Right not visible. */
9470c21bfbSnicm 		xoff = wp->xoff - ctx->ox;
9570c21bfbSnicm 		sx = wp->sx - xoff;
963b2d01c0Snicm 	}
9770c21bfbSnicm 	if (wp->yoff >= ctx->oy && wp->yoff + wp->sy <= ctx->oy + ctx->sy) {
9870c21bfbSnicm 		/* All visible. */
9970c21bfbSnicm 		yoff = wp->yoff - ctx->oy;
10070c21bfbSnicm 		sy = wp->sy;
10170c21bfbSnicm 	} else if (wp->yoff < ctx->oy &&
10270c21bfbSnicm 	    wp->yoff + wp->sy > ctx->oy + ctx->sy) {
10370c21bfbSnicm 		/* Both top and bottom not visible. */
10470c21bfbSnicm 		yoff = 0;
10570c21bfbSnicm 		sy = ctx->sy;
10670c21bfbSnicm 	} else if (wp->yoff < ctx->oy) {
10770c21bfbSnicm 		/* Top not visible. */
10870c21bfbSnicm 		yoff = 0;
10970c21bfbSnicm 		sy = wp->sy - (ctx->oy - wp->yoff);
11070c21bfbSnicm 	} else {
11170c21bfbSnicm 		/* Bottom not visible. */
11270c21bfbSnicm 		yoff = wp->yoff - ctx->oy;
11370c21bfbSnicm 		sy = wp->sy - yoff;
11470c21bfbSnicm 	}
115669c539cSnicm 
11670c21bfbSnicm 	if (ctx->statustop)
11770c21bfbSnicm 		yoff += ctx->statuslines;
11870c21bfbSnicm 	px = sx / 2;
11970c21bfbSnicm 	py = sy / 2;
12070c21bfbSnicm 
121cf629db8Snicm 	if (window_pane_index(wp, &pane) != 0)
12270c21bfbSnicm 		fatalx("index not found");
123cf629db8Snicm 	len = xsnprintf(buf, sizeof buf, "%u", pane);
12470c21bfbSnicm 
12570c21bfbSnicm 	if (sx < len)
12670c21bfbSnicm 		return;
12770c21bfbSnicm 	colour = options_get_number(oo, "display-panes-colour");
12870c21bfbSnicm 	active_colour = options_get_number(oo, "display-panes-active-colour");
12970c21bfbSnicm 
130cf629db8Snicm 	memcpy(&fgc, &grid_default_cell, sizeof fgc);
131cf629db8Snicm 	memcpy(&bgc, &grid_default_cell, sizeof bgc);
132cf629db8Snicm 	if (w->active == wp) {
133cf629db8Snicm 		fgc.fg = active_colour;
134cf629db8Snicm 		bgc.bg = active_colour;
135cf629db8Snicm 	} else {
136cf629db8Snicm 		fgc.fg = colour;
137cf629db8Snicm 		bgc.bg = colour;
138cf629db8Snicm 	}
139cf629db8Snicm 
140cf629db8Snicm 	rlen = xsnprintf(rbuf, sizeof rbuf, "%ux%u", wp->sx, wp->sy);
141cf629db8Snicm 	if (pane > 9 && pane < 35)
142cf629db8Snicm 		llen = xsnprintf(lbuf, sizeof lbuf, "%c", 'a' + (pane - 10));
143cf629db8Snicm 	else
144cf629db8Snicm 		llen = 0;
145cf629db8Snicm 
14670c21bfbSnicm 	if (sx < len * 6 || sy < 5) {
1472df6775cSnicm 		tty_attributes(tty, &fgc, &grid_default_cell, NULL, NULL);
148cf629db8Snicm 		if (sx >= len + llen + 1) {
149cf629db8Snicm 			len += llen + 1;
15070c21bfbSnicm 			tty_cursor(tty, xoff + px - len / 2, yoff + py);
151cf629db8Snicm 			tty_putn(tty, buf, len,	 len);
152cf629db8Snicm 			tty_putn(tty, " ", 1, 1);
153cf629db8Snicm 			tty_putn(tty, lbuf, llen, llen);
154cf629db8Snicm 		} else {
155cf629db8Snicm 			tty_cursor(tty, xoff + px - len / 2, yoff + py);
156cf629db8Snicm 			tty_putn(tty, buf, len, len);
157cf629db8Snicm 		}
158cf629db8Snicm 		goto out;
15970c21bfbSnicm 	}
16070c21bfbSnicm 
16170c21bfbSnicm 	px -= len * 3;
16270c21bfbSnicm 	py -= 2;
16370c21bfbSnicm 
1642df6775cSnicm 	tty_attributes(tty, &bgc, &grid_default_cell, NULL, NULL);
16570c21bfbSnicm 	for (ptr = buf; *ptr != '\0'; ptr++) {
16670c21bfbSnicm 		if (*ptr < '0' || *ptr > '9')
16770c21bfbSnicm 			continue;
16870c21bfbSnicm 		idx = *ptr - '0';
16970c21bfbSnicm 
17070c21bfbSnicm 		for (j = 0; j < 5; j++) {
17170c21bfbSnicm 			for (i = px; i < px + 5; i++) {
17270c21bfbSnicm 				tty_cursor(tty, xoff + i, yoff + py + j);
17370c21bfbSnicm 				if (window_clock_table[idx][j][i - px])
17470c21bfbSnicm 					tty_putc(tty, ' ');
17570c21bfbSnicm 			}
17670c21bfbSnicm 		}
17770c21bfbSnicm 		px += 6;
17870c21bfbSnicm 	}
17970c21bfbSnicm 
18033491e32Snicm 	if (sy <= 6)
181cf629db8Snicm 		goto out;
1822df6775cSnicm 	tty_attributes(tty, &fgc, &grid_default_cell, NULL, NULL);
183cf629db8Snicm 	if (rlen != 0 && sx >= rlen) {
184cf629db8Snicm 		tty_cursor(tty, xoff + sx - rlen, yoff);
185cf629db8Snicm 		tty_putn(tty, rbuf, rlen, rlen);
186cf629db8Snicm 	}
187cf629db8Snicm 	if (llen != 0) {
188cf629db8Snicm 		tty_cursor(tty, xoff + sx / 2 + len * 3 - llen - 1,
189cf629db8Snicm 		    yoff + py + 5);
190cf629db8Snicm 		tty_putn(tty, lbuf, llen, llen);
191cf629db8Snicm 	}
19270c21bfbSnicm 
193cf629db8Snicm out:
19470c21bfbSnicm 	tty_cursor(tty, 0, 0);
19570c21bfbSnicm }
19670c21bfbSnicm 
19770c21bfbSnicm static void
cmd_display_panes_draw(struct client * c,__unused void * data,struct screen_redraw_ctx * ctx)198f38784aeSnicm cmd_display_panes_draw(struct client *c, __unused void *data,
199f38784aeSnicm     struct screen_redraw_ctx *ctx)
20070c21bfbSnicm {
20170c21bfbSnicm 	struct window		*w = c->session->curw->window;
20270c21bfbSnicm 	struct window_pane	*wp;
20370c21bfbSnicm 
20470c21bfbSnicm 	log_debug("%s: %s @%u", __func__, c->name, w->id);
20570c21bfbSnicm 
20670c21bfbSnicm 	TAILQ_FOREACH(wp, &w->panes, entry) {
20770c21bfbSnicm 		if (window_pane_visible(wp))
20870c21bfbSnicm 			cmd_display_panes_draw_pane(ctx, wp);
20970c21bfbSnicm 	}
210669c539cSnicm }
2112413453fSnicm 
2122413453fSnicm static void
cmd_display_panes_free(__unused struct client * c,void * data)213f38784aeSnicm cmd_display_panes_free(__unused struct client *c, void *data)
2142413453fSnicm {
215f38784aeSnicm 	struct cmd_display_panes_data	*cdata = data;
21670c21bfbSnicm 
21770c21bfbSnicm 	if (cdata->item != NULL)
218780ca620Snicm 		cmdq_continue(cdata->item);
2192db6a388Snicm 	args_make_commands_free(cdata->state);
22070c21bfbSnicm 	free(cdata);
22170c21bfbSnicm }
22270c21bfbSnicm 
22370c21bfbSnicm static int
cmd_display_panes_key(struct client * c,void * data,struct key_event * event)224f38784aeSnicm cmd_display_panes_key(struct client *c, void *data, struct key_event *event)
22570c21bfbSnicm {
226f38784aeSnicm 	struct cmd_display_panes_data	*cdata = data;
2272db6a388Snicm 	char				*expanded, *error;
2282db6a388Snicm 	struct cmdq_item		*item = cdata->item, *new_item;
2292db6a388Snicm 	struct cmd_list			*cmdlist;
23070c21bfbSnicm 	struct window			*w = c->session->curw->window;
23170c21bfbSnicm 	struct window_pane		*wp;
232cf629db8Snicm 	u_int				 index;
233cf629db8Snicm 	key_code			 key;
2342413453fSnicm 
235cf629db8Snicm 	if (event->key >= '0' && event->key <= '9')
236cf629db8Snicm 		index = event->key - '0';
237cf629db8Snicm 	else if ((event->key & KEYC_MASK_MODIFIERS) == 0) {
238cf629db8Snicm 		key = (event->key & KEYC_MASK_KEY);
239cf629db8Snicm 		if (key >= 'a' && key <= 'z')
240cf629db8Snicm 			index = 10 + (key - 'a');
241cf629db8Snicm 		else
242cf629db8Snicm 			return (-1);
243cf629db8Snicm 	} else
244ab90d8c3Snicm 		return (-1);
24570c21bfbSnicm 
246cf629db8Snicm 	wp = window_pane_at_index(w, index);
247765b9a58Snicm 	if (wp == NULL)
24870c21bfbSnicm 		return (1);
249*0ad0daf4Snicm 	window_unzoom(w, 1);
250e8c2b18dSnicm 
2512413453fSnicm 	xasprintf(&expanded, "%%%u", wp->id);
2522413453fSnicm 
2532db6a388Snicm 	cmdlist = args_make_commands(cdata->state, 1, &expanded, &error);
2542db6a388Snicm 	if (cmdlist == NULL) {
2551c43462cSnicm 		cmdq_append(c, cmdq_get_error(error));
2561c43462cSnicm 		free(error);
2572db6a388Snicm 	} else if (item == NULL) {
2582db6a388Snicm 		new_item = cmdq_get_command(cmdlist, NULL);
2592db6a388Snicm 		cmdq_append(c, new_item);
2602db6a388Snicm 	} else {
2612db6a388Snicm 		new_item = cmdq_get_command(cmdlist, cmdq_get_state(item));
2622db6a388Snicm 		cmdq_insert_after(item, new_item);
2637018a461Snicm 	}
264765b9a58Snicm 
2652413453fSnicm 	free(expanded);
26670c21bfbSnicm 	return (1);
2677018a461Snicm }
268e8c2b18dSnicm 
26970c21bfbSnicm static enum cmd_retval
cmd_display_panes_exec(struct cmd * self,struct cmdq_item * item)27070c21bfbSnicm cmd_display_panes_exec(struct cmd *self, struct cmdq_item *item)
27170c21bfbSnicm {
27290d7ba38Snicm 	struct args			*args = cmd_get_args(self);
273035dc73dSnicm 	struct client			*tc = cmdq_get_target_client(item);
274035dc73dSnicm 	struct session			*s = tc->session;
27570c21bfbSnicm 	u_int				 delay;
27670c21bfbSnicm 	char				*cause;
27770c21bfbSnicm 	struct cmd_display_panes_data	*cdata;
2782db6a388Snicm 	int				 wait = !args_has(args, 'b');
279e8c2b18dSnicm 
280035dc73dSnicm 	if (tc->overlay_draw != NULL)
28170c21bfbSnicm 		return (CMD_RETURN_NORMAL);
28270c21bfbSnicm 
28370c21bfbSnicm 	if (args_has(args, 'd')) {
28470c21bfbSnicm 		delay = args_strtonum(args, 'd', 0, UINT_MAX, &cause);
28570c21bfbSnicm 		if (cause != NULL) {
28670c21bfbSnicm 			cmdq_error(item, "delay %s", cause);
28770c21bfbSnicm 			free(cause);
28870c21bfbSnicm 			return (CMD_RETURN_ERROR);
28970c21bfbSnicm 		}
29070c21bfbSnicm 	} else
29170c21bfbSnicm 		delay = options_get_number(s->options, "display-panes-time");
29270c21bfbSnicm 
2932db6a388Snicm 	cdata = xcalloc(1, sizeof *cdata);
2942db6a388Snicm 	if (wait)
29570c21bfbSnicm 		cdata->item = item;
2962db6a388Snicm 	cdata->state = args_make_commands_prepare(self, item, 0,
2972db6a388Snicm 	    "select-pane -t \"%%%\"", wait, 0);
29870c21bfbSnicm 
29988eb9092Snicm 	if (args_has(args, 'N')) {
30088eb9092Snicm 		server_client_set_overlay(tc, delay, NULL, NULL,
301c0287628Snicm 		    cmd_display_panes_draw, NULL, cmd_display_panes_free, NULL,
30288eb9092Snicm 		    cdata);
30388eb9092Snicm 	} else {
30488eb9092Snicm 		server_client_set_overlay(tc, delay, NULL, NULL,
30588eb9092Snicm 		    cmd_display_panes_draw, cmd_display_panes_key,
306c0287628Snicm 		    cmd_display_panes_free, NULL, cdata);
30788eb9092Snicm 	}
30870c21bfbSnicm 
3092db6a388Snicm 	if (!wait)
31070c21bfbSnicm 		return (CMD_RETURN_NORMAL);
31170c21bfbSnicm 	return (CMD_RETURN_WAIT);
3122413453fSnicm }
313