Coverage Report

Created: 2025-08-24 07:01

/src/tmux/cmd-display-panes.c
Line
Count
Source (jump to first uncovered line)
1
/* $OpenBSD$ */
2
3
/*
4
 * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16
 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
19
#include <sys/types.h>
20
21
#include <stdlib.h>
22
#include <string.h>
23
24
#include "tmux.h"
25
26
/*
27
 * Display panes on a client.
28
 */
29
30
static enum args_parse_type cmd_display_panes_args_parse(struct args *,
31
            u_int, char **);
32
static enum cmd_retval    cmd_display_panes_exec(struct cmd *,
33
            struct cmdq_item *);
34
35
const struct cmd_entry cmd_display_panes_entry = {
36
  .name = "display-panes",
37
  .alias = "displayp",
38
39
  .args = { "bd:Nt:", 0, 1, cmd_display_panes_args_parse },
40
  .usage = "[-bN] [-d duration] " CMD_TARGET_CLIENT_USAGE " [template]",
41
42
  .flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG,
43
  .exec = cmd_display_panes_exec
44
};
45
46
struct cmd_display_panes_data {
47
  struct cmdq_item    *item;
48
  struct args_command_state *state;
49
};
50
51
static enum args_parse_type
52
cmd_display_panes_args_parse(__unused struct args *args, __unused u_int idx,
53
    __unused char **cause)
54
0
{
55
0
  return (ARGS_PARSE_COMMANDS_OR_STRING);
56
0
}
57
58
static void
59
cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
60
    struct window_pane *wp)
61
0
{
62
0
  struct client   *c = ctx->c;
63
0
  struct tty    *tty = &c->tty;
64
0
  struct session    *s = c->session;
65
0
  struct options    *oo = s->options;
66
0
  struct window   *w = wp->window;
67
0
  struct grid_cell   fgc, bgc;
68
0
  u_int      pane, idx, px, py, i, j, xoff, yoff, sx, sy;
69
0
  int      colour, active_colour;
70
0
  char       buf[16], lbuf[16], rbuf[16], *ptr;
71
0
  size_t       len, llen, rlen;
72
73
0
  if (wp->xoff + wp->sx <= ctx->ox ||
74
0
      wp->xoff >= ctx->ox + ctx->sx ||
75
0
      wp->yoff + wp->sy <= ctx->oy ||
76
0
      wp->yoff >= ctx->oy + ctx->sy)
77
0
    return;
78
79
0
  if (wp->xoff >= ctx->ox && wp->xoff + wp->sx <= ctx->ox + ctx->sx) {
80
    /* All visible. */
81
0
    xoff = wp->xoff - ctx->ox;
82
0
    sx = wp->sx;
83
0
  } else if (wp->xoff < ctx->ox &&
84
0
      wp->xoff + wp->sx > ctx->ox + ctx->sx) {
85
    /* Both left and right not visible. */
86
0
    xoff = 0;
87
0
    sx = ctx->sx;
88
0
  } else if (wp->xoff < ctx->ox) {
89
    /* Left not visible. */
90
0
    xoff = 0;
91
0
    sx = wp->sx - (ctx->ox - wp->xoff);
92
0
  } else {
93
    /* Right not visible. */
94
0
    xoff = wp->xoff - ctx->ox;
95
0
    sx = wp->sx - xoff;
96
0
  }
97
0
  if (wp->yoff >= ctx->oy && wp->yoff + wp->sy <= ctx->oy + ctx->sy) {
98
    /* All visible. */
99
0
    yoff = wp->yoff - ctx->oy;
100
0
    sy = wp->sy;
101
0
  } else if (wp->yoff < ctx->oy &&
102
0
      wp->yoff + wp->sy > ctx->oy + ctx->sy) {
103
    /* Both top and bottom not visible. */
104
0
    yoff = 0;
105
0
    sy = ctx->sy;
106
0
  } else if (wp->yoff < ctx->oy) {
107
    /* Top not visible. */
108
0
    yoff = 0;
109
0
    sy = wp->sy - (ctx->oy - wp->yoff);
110
0
  } else {
111
    /* Bottom not visible. */
112
0
    yoff = wp->yoff - ctx->oy;
113
0
    sy = wp->sy - yoff;
114
0
  }
115
116
0
  if (ctx->statustop)
117
0
    yoff += ctx->statuslines;
118
0
  px = sx / 2;
119
0
  py = sy / 2;
120
121
0
  if (window_pane_index(wp, &pane) != 0)
122
0
    fatalx("index not found");
123
0
  len = xsnprintf(buf, sizeof buf, "%u", pane);
124
125
0
  if (sx < len)
126
0
    return;
127
0
  colour = options_get_number(oo, "display-panes-colour");
128
0
  active_colour = options_get_number(oo, "display-panes-active-colour");
129
130
0
  memcpy(&fgc, &grid_default_cell, sizeof fgc);
131
0
  memcpy(&bgc, &grid_default_cell, sizeof bgc);
132
0
  if (w->active == wp) {
133
0
    fgc.fg = active_colour;
134
0
    bgc.bg = active_colour;
135
0
  } else {
136
0
    fgc.fg = colour;
137
0
    bgc.bg = colour;
138
0
  }
139
140
0
  rlen = xsnprintf(rbuf, sizeof rbuf, "%ux%u", wp->sx, wp->sy);
141
0
  if (pane > 9 && pane < 35)
142
0
    llen = xsnprintf(lbuf, sizeof lbuf, "%c", 'a' + (pane - 10));
143
0
  else
144
0
    llen = 0;
145
146
0
  if (sx < len * 6 || sy < 5) {
147
0
    tty_attributes(tty, &fgc, &grid_default_cell, NULL, NULL);
148
0
    if (sx >= len + llen + 1) {
149
0
      len += llen + 1;
150
0
      tty_cursor(tty, xoff + px - len / 2, yoff + py);
151
0
      tty_putn(tty, buf, len,  len);
152
0
      tty_putn(tty, " ", 1, 1);
153
0
      tty_putn(tty, lbuf, llen, llen);
154
0
    } else {
155
0
      tty_cursor(tty, xoff + px - len / 2, yoff + py);
156
0
      tty_putn(tty, buf, len, len);
157
0
    }
158
0
    goto out;
159
0
  }
160
161
0
  px -= len * 3;
162
0
  py -= 2;
163
164
0
  tty_attributes(tty, &bgc, &grid_default_cell, NULL, NULL);
165
0
  for (ptr = buf; *ptr != '\0'; ptr++) {
166
0
    if (*ptr < '0' || *ptr > '9')
167
0
      continue;
168
0
    idx = *ptr - '0';
169
170
0
    for (j = 0; j < 5; j++) {
171
0
      for (i = px; i < px + 5; i++) {
172
0
        tty_cursor(tty, xoff + i, yoff + py + j);
173
0
        if (window_clock_table[idx][j][i - px])
174
0
          tty_putc(tty, ' ');
175
0
      }
176
0
    }
177
0
    px += 6;
178
0
  }
179
180
0
  if (sy <= 6)
181
0
    goto out;
182
0
  tty_attributes(tty, &fgc, &grid_default_cell, NULL, NULL);
183
0
  if (rlen != 0 && sx >= rlen) {
184
0
    tty_cursor(tty, xoff + sx - rlen, yoff);
185
0
    tty_putn(tty, rbuf, rlen, rlen);
186
0
  }
187
0
  if (llen != 0) {
188
0
    tty_cursor(tty, xoff + sx / 2 + len * 3 - llen - 1,
189
0
        yoff + py + 5);
190
0
    tty_putn(tty, lbuf, llen, llen);
191
0
  }
192
193
0
out:
194
0
  tty_cursor(tty, 0, 0);
195
0
}
196
197
static void
198
cmd_display_panes_draw(struct client *c, __unused void *data,
199
    struct screen_redraw_ctx *ctx)
200
0
{
201
0
  struct window   *w = c->session->curw->window;
202
0
  struct window_pane  *wp;
203
204
0
  log_debug("%s: %s @%u", __func__, c->name, w->id);
205
206
0
  TAILQ_FOREACH(wp, &w->panes, entry) {
207
0
    if (window_pane_visible(wp))
208
0
      cmd_display_panes_draw_pane(ctx, wp);
209
0
  }
210
0
}
211
212
static void
213
cmd_display_panes_free(__unused struct client *c, void *data)
214
0
{
215
0
  struct cmd_display_panes_data *cdata = data;
216
217
0
  if (cdata->item != NULL)
218
0
    cmdq_continue(cdata->item);
219
0
  args_make_commands_free(cdata->state);
220
0
  free(cdata);
221
0
}
222
223
static int
224
cmd_display_panes_key(struct client *c, void *data, struct key_event *event)
225
0
{
226
0
  struct cmd_display_panes_data *cdata = data;
227
0
  char        *expanded, *error;
228
0
  struct cmdq_item    *item = cdata->item, *new_item;
229
0
  struct cmd_list     *cmdlist;
230
0
  struct window     *w = c->session->curw->window;
231
0
  struct window_pane    *wp;
232
0
  u_int        index;
233
0
  key_code       key;
234
235
0
  if (event->key >= '0' && event->key <= '9')
236
0
    index = event->key - '0';
237
0
  else if ((event->key & KEYC_MASK_MODIFIERS) == 0) {
238
0
    key = (event->key & KEYC_MASK_KEY);
239
0
    if (key >= 'a' && key <= 'z')
240
0
      index = 10 + (key - 'a');
241
0
    else
242
0
      return (-1);
243
0
  } else
244
0
    return (-1);
245
246
0
  wp = window_pane_at_index(w, index);
247
0
  if (wp == NULL)
248
0
    return (1);
249
0
  window_unzoom(w, 1);
250
251
0
  xasprintf(&expanded, "%%%u", wp->id);
252
253
0
  cmdlist = args_make_commands(cdata->state, 1, &expanded, &error);
254
0
  if (cmdlist == NULL) {
255
0
    cmdq_append(c, cmdq_get_error(error));
256
0
    free(error);
257
0
  } else if (item == NULL) {
258
0
    new_item = cmdq_get_command(cmdlist, NULL);
259
0
    cmdq_append(c, new_item);
260
0
  } else {
261
0
    new_item = cmdq_get_command(cmdlist, cmdq_get_state(item));
262
0
    cmdq_insert_after(item, new_item);
263
0
  }
264
265
0
  free(expanded);
266
0
  return (1);
267
0
}
268
269
static enum cmd_retval
270
cmd_display_panes_exec(struct cmd *self, struct cmdq_item *item)
271
0
{
272
0
  struct args     *args = cmd_get_args(self);
273
0
  struct client     *tc = cmdq_get_target_client(item);
274
0
  struct session      *s = tc->session;
275
0
  u_int        delay;
276
0
  char        *cause;
277
0
  struct cmd_display_panes_data *cdata;
278
0
  int        wait = !args_has(args, 'b');
279
280
0
  if (tc->overlay_draw != NULL)
281
0
    return (CMD_RETURN_NORMAL);
282
283
0
  if (args_has(args, 'd')) {
284
0
    delay = args_strtonum(args, 'd', 0, UINT_MAX, &cause);
285
0
    if (cause != NULL) {
286
0
      cmdq_error(item, "delay %s", cause);
287
0
      free(cause);
288
0
      return (CMD_RETURN_ERROR);
289
0
    }
290
0
  } else
291
0
    delay = options_get_number(s->options, "display-panes-time");
292
293
0
  cdata = xcalloc(1, sizeof *cdata);
294
0
  if (wait)
295
0
    cdata->item = item;
296
0
  cdata->state = args_make_commands_prepare(self, item, 0,
297
0
      "select-pane -t \"%%%\"", wait, 0);
298
299
0
  if (args_has(args, 'N')) {
300
0
    server_client_set_overlay(tc, delay, NULL, NULL,
301
0
        cmd_display_panes_draw, NULL, cmd_display_panes_free, NULL,
302
0
        cdata);
303
0
  } else {
304
0
    server_client_set_overlay(tc, delay, NULL, NULL,
305
0
        cmd_display_panes_draw, cmd_display_panes_key,
306
0
        cmd_display_panes_free, NULL, cdata);
307
0
  }
308
309
0
  if (!wait)
310
0
    return (CMD_RETURN_NORMAL);
311
0
  return (CMD_RETURN_WAIT);
312
0
}