Coverage Report

Created: 2026-08-13 06:07

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tmux/window-border.c
Line
Count
Source
1
/* $OpenBSD: window-border.c,v 1.3 2026/07/23 09:38:27 nicm Exp $ */
2
3
/*
4
 * Copyright (c) 2026 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
/* Set window fill cell. */
27
static void
28
window_set_fill_cell(struct window *w, int inside, struct grid_cell *gc)
29
0
{
30
0
  struct format_tree  *ft;
31
0
  struct screen    s;
32
0
  struct screen_write_ctx  ctx;
33
0
  struct grid_cell   new_gc;
34
0
  const char    *value;
35
0
  char      *expanded;
36
37
0
  memcpy(gc, &grid_default_cell, sizeof *gc);
38
0
  gc->attr |= GRID_ATTR_CHARSET;
39
0
  utf8_set(&gc->data, CELL_BORDERS[CELL_NONE]);
40
41
0
  ft = format_create(NULL, NULL, FORMAT_WINDOW|w->id, FORMAT_NOJOBS);
42
0
  format_defaults(ft, NULL, NULL, NULL, w->active);
43
0
  format_add(ft, "is_inside", "%d", inside);
44
0
  format_add(ft, "is_outside", "%d", !inside);
45
46
0
  value = options_get_string(w->options, "fill-character");
47
0
  expanded = format_expand(ft, value);
48
0
  format_free(ft);
49
50
0
  screen_init(&s, 1, 1, 0);
51
0
  screen_write_start(&ctx, &s);
52
0
  format_draw(&ctx, &grid_default_cell, 1, expanded, NULL, 0);
53
0
  screen_write_stop(&ctx);
54
0
  free(expanded);
55
56
0
  grid_view_get_cell(s.grid, 0, 0, &new_gc);
57
0
  if (new_gc.data.width == 1)
58
0
    memcpy(gc, &new_gc, sizeof *gc);
59
0
  screen_free(&s);
60
0
}
61
62
/* Set window fill cells. */
63
void
64
window_set_fill_cells(struct window *w)
65
0
{
66
0
  window_set_fill_cell(w, 1, &w->inside_cell);
67
0
  window_set_fill_cell(w, 0, &w->outside_cell);
68
0
}
69
70
/* Merge a window fill cell over an existing style. */
71
static void
72
window_copy_fill_cell(struct grid_cell *gc, const struct grid_cell *fill)
73
0
{
74
0
  utf8_copy(&gc->data, &fill->data);
75
0
  gc->attr |= fill->attr;
76
0
  gc->flags |= fill->flags;
77
0
  if (fill->fg != 8)
78
0
    gc->fg = fill->fg;
79
0
  if (fill->bg != 8)
80
0
    gc->bg = fill->bg;
81
0
  if (fill->us != 8)
82
0
    gc->us = fill->us;
83
0
}
84
85
/* Get window fill cell. */
86
void
87
window_get_fill_cell(struct window *w, int inside, struct grid_cell *gc)
88
0
{
89
0
  if (inside)
90
0
    window_copy_fill_cell(gc, &w->inside_cell);
91
0
  else
92
0
    window_copy_fill_cell(gc, &w->outside_cell);
93
0
}
94
95
/* Get border cell. */
96
void
97
window_get_border_cell(struct window_pane *wp, enum pane_lines pane_lines,
98
    int cell_type, struct grid_cell *gc)
99
0
{
100
0
  u_int idx;
101
102
0
  switch (pane_lines) {
103
0
  case PANE_LINES_NUMBER:
104
0
    if (cell_type == CELL_NONE) {
105
0
      gc->attr |= GRID_ATTR_CHARSET;
106
0
      utf8_set(&gc->data, CELL_BORDERS[CELL_NONE]);
107
0
      break;
108
0
    }
109
0
    gc->attr &= ~GRID_ATTR_CHARSET;
110
0
    if (wp != NULL && window_pane_index(wp, &idx) == 0)
111
0
      utf8_set(&gc->data, '0' + (idx % 10));
112
0
    else
113
0
      utf8_set(&gc->data, '*');
114
0
    break;
115
0
  case PANE_LINES_DOUBLE:
116
0
    gc->attr &= ~GRID_ATTR_CHARSET;
117
0
    utf8_copy(&gc->data, tty_acs_double_borders(cell_type));
118
0
    break;
119
0
  case PANE_LINES_HEAVY:
120
0
    gc->attr &= ~GRID_ATTR_CHARSET;
121
0
    utf8_copy(&gc->data, tty_acs_heavy_borders(cell_type));
122
0
    break;
123
0
  case PANE_LINES_SIMPLE:
124
0
    gc->attr &= ~GRID_ATTR_CHARSET;
125
0
    utf8_set(&gc->data, SIMPLE_BORDERS[cell_type]);
126
0
    break;
127
0
  case PANE_LINES_NONE:
128
0
  case PANE_LINES_SPACES:
129
0
    gc->attr &= ~GRID_ATTR_CHARSET;
130
0
    utf8_set(&gc->data, ' ');
131
0
    break;
132
0
  default:
133
0
    gc->attr |= GRID_ATTR_CHARSET;
134
0
    utf8_set(&gc->data, CELL_BORDERS[cell_type]);
135
0
    break;
136
0
  }
137
0
}
138
139
/* Get pane border cell. */
140
void
141
window_pane_get_border_cell(struct window_pane *wp, int cell_type,
142
    struct grid_cell *gc)
143
0
{
144
0
  enum pane_lines pane_lines = window_pane_get_pane_lines(wp);
145
146
0
  window_get_border_cell(wp, pane_lines, cell_type, gc);
147
0
}
148
149
/* Get pane border style. */
150
void
151
window_pane_get_border_style(struct window_pane *wp, struct client *c,
152
    struct grid_cell *gc)
153
0
{
154
0
  struct session    *s = c->session;
155
0
  struct format_tree  *ft;
156
0
  const char    *option;
157
0
  struct grid_cell  *saved;
158
0
  int     *flag;
159
160
0
  if (wp == c->session->curw->window->active) {
161
0
    flag = &wp->active_border_gc_set;
162
0
    saved = &wp->active_border_gc;
163
0
    option = "pane-active-border-style";
164
0
  } else {
165
0
    flag = &wp->border_gc_set;
166
0
    saved = &wp->border_gc;
167
0
    option = "pane-border-style";
168
0
  }
169
170
0
  if (!*flag) {
171
0
    ft = format_create_defaults(NULL, c, s, s->curw, wp);
172
0
    style_apply(saved, wp->options, option, ft);
173
0
    format_free(ft);
174
0
    *flag = 1;
175
0
  }
176
0
  memcpy(gc, saved, sizeof *gc);
177
0
}
178
179
/* Build pane status line. */
180
int
181
window_make_pane_status(struct window_pane *wp, struct client *c, u_int width,
182
    struct redraw_span *span)
183
0
{
184
0
  struct grid_cell   gc;
185
0
  const char    *fmt;
186
0
  struct format_tree  *ft;
187
0
  struct style_line_entry *sle = &wp->border_status_line;
188
0
  struct screen_write_ctx  ctx;
189
0
  struct screen    old;
190
0
  char      *expanded;
191
0
  u_int      i;
192
0
  enum pane_lines    pane_lines;
193
0
  int      pane_status, cell_type;
194
195
0
  pane_status = window_pane_get_pane_status(wp);
196
0
  if (pane_status == PANE_STATUS_OFF || width == 0)
197
0
    return (0);
198
199
0
  ft = format_create(c, NULL, FORMAT_PANE|wp->id, FORMAT_STATUS);
200
0
  format_defaults(ft, c, c->session, c->session->curw, wp);
201
202
0
  fmt = options_get_string(wp->options, "pane-border-format");
203
0
  expanded = format_expand_time(ft, fmt);
204
205
0
  memcpy(&old, &wp->status_screen, sizeof old);
206
0
  screen_init(&wp->status_screen, width, 1, 0);
207
0
  wp->status_screen.mode = 0;
208
0
  screen_write_start(&ctx, &wp->status_screen);
209
210
0
  window_pane_get_border_style(wp, c, &gc);
211
0
  pane_lines = window_pane_get_pane_lines(wp);
212
0
  for (i = 0; i < width; i++) {
213
0
    cell_type = redraw_get_status_border_cell_type(&span, i);
214
0
    window_get_border_cell(wp, pane_lines, cell_type, &gc);
215
0
    screen_write_cell(&ctx, &gc);
216
0
  }
217
0
  gc.attr &= ~GRID_ATTR_CHARSET;
218
219
0
  screen_write_cursormove(&ctx, 0, 0, 0);
220
0
  style_ranges_free(&sle->ranges);
221
0
  format_draw(&ctx, &gc, width, expanded, &sle->ranges, 0);
222
223
0
  screen_write_stop(&ctx);
224
0
  format_free(ft);
225
226
0
  free(sle->expanded);
227
0
  sle->expanded = expanded;
228
229
0
  if (grid_compare(wp->status_screen.grid, old.grid) == 0) {
230
0
    screen_free(&old);
231
0
    return (0);
232
0
  }
233
0
  screen_free(&old);
234
0
  return (1);
235
0
}