Coverage Report

Created: 2026-10-17 06:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tmux/window-customize.c
Line
Count
Source
1
/* $OpenBSD: window-customize.c,v 1.38 2026/10/15 08:21:11 nicm Exp $ */
2
3
/*
4
 * Copyright (c) 2020 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 <ctype.h>
22
#include <stdlib.h>
23
#include <string.h>
24
25
#include "tmux.h"
26
27
static struct screen  *window_customize_init(struct window_mode_entry *,
28
           struct cmdq_item *, struct cmd_find_state *,
29
           struct args *);
30
static void    window_customize_free(struct window_mode_entry *);
31
static void    window_customize_resize(struct window_mode_entry *,
32
            u_int, u_int);
33
static void    window_customize_update(struct window_mode_entry *);
34
static void    window_customize_key(struct window_mode_entry *,
35
           struct client *, struct session *,
36
           struct winlink *, key_code, struct mouse_event *);
37
38
#define WINDOW_CUSTOMIZE_DEFAULT_FORMAT \
39
0
  "#{?is_option," \
40
0
    "#{?option_is_global,,#[reverse](#{option_scope})#[default] }" \
41
0
    "#[fg=themelightgrey]#[ignore]#{option_value}" \
42
0
    "#{?option_unit, #{option_unit},}" \
43
0
  "," \
44
0
    "#{?is_environment," \
45
0
      "#[fg=themelightgrey]#[ignore]#{environment_value}" \
46
0
    "," \
47
0
      "#{key}" \
48
0
    "}" \
49
0
  "}"
50
51
static const struct menu_item window_customize_menu_items[] = {
52
  { "Select", '\r', NULL },
53
  { "Edit", 'e', NULL },
54
  { "Expand", KEYC_RIGHT, NULL },
55
  { "", KEYC_NONE, NULL },
56
  { "Tag", 't', NULL },
57
  { "Tag All", '\024', NULL },
58
  { "Tag None", 'T', NULL },
59
  { "", KEYC_NONE, NULL },
60
  { "Changed Only", 'C', NULL },
61
  { "", KEYC_NONE, NULL },
62
  { "Cancel", 'q', NULL },
63
64
  { NULL, KEYC_NONE, NULL }
65
};
66
67
const struct window_mode window_customize_mode = {
68
  .name = "options-mode",
69
  .default_format = WINDOW_CUSTOMIZE_DEFAULT_FORMAT,
70
71
  .init = window_customize_init,
72
  .free = window_customize_free,
73
  .resize = window_customize_resize,
74
  .update = window_customize_update,
75
  .key = window_customize_key,
76
};
77
78
enum window_customize_scope {
79
  WINDOW_CUSTOMIZE_NONE,
80
  WINDOW_CUSTOMIZE_KEY,
81
  WINDOW_CUSTOMIZE_SERVER,
82
  WINDOW_CUSTOMIZE_GLOBAL_SESSION,
83
  WINDOW_CUSTOMIZE_SESSION,
84
  WINDOW_CUSTOMIZE_GLOBAL_WINDOW,
85
  WINDOW_CUSTOMIZE_WINDOW,
86
  WINDOW_CUSTOMIZE_PANE,
87
  WINDOW_CUSTOMIZE_GLOBAL_ENVIRONMENT,
88
  WINDOW_CUSTOMIZE_SESSION_ENVIRONMENT
89
};
90
91
enum window_customize_change {
92
  WINDOW_CUSTOMIZE_UNSET,
93
  WINDOW_CUSTOMIZE_RESET,
94
};
95
96
enum window_customize_option_type {
97
  WINDOW_CUSTOMIZE_OPTIONS,
98
  WINDOW_CUSTOMIZE_HOOKS
99
};
100
101
enum window_customize_item_type {
102
  WINDOW_CUSTOMIZE_ITEM_OPTION,
103
  WINDOW_CUSTOMIZE_ITEM_KEY,
104
  WINDOW_CUSTOMIZE_ITEM_ENVIRONMENT
105
};
106
107
enum window_customize_edit_type {
108
  WINDOW_CUSTOMIZE_EDIT_OPTION,
109
  WINDOW_CUSTOMIZE_EDIT_KEY_COMMAND,
110
  WINDOW_CUSTOMIZE_EDIT_KEY_NOTE,
111
  WINDOW_CUSTOMIZE_EDIT_ENVIRONMENT
112
};
113
114
struct window_customize_itemdata {
115
  struct window_customize_modedata   *data;
116
  enum window_customize_item_type   type;
117
  enum window_customize_option_type  option_type;
118
  enum window_customize_scope     scope;
119
120
  char           *table;
121
  key_code          key;
122
123
  struct options         *oo;
124
  struct environ         *environ;
125
  int           environ_flags;
126
  char           *name;
127
  char           *array_key;
128
};
129
130
struct window_customize_modedata {
131
  struct window_pane       *wp;
132
  int           dead;
133
  int           references;
134
135
  struct mode_tree_data      *data;
136
  struct spawn_editor_state    *editor;
137
  struct window_customize_editdata   *edit;
138
  char           *format;
139
  int           hide_global;
140
  int           hide_default;
141
  int           prompt_flags;
142
143
  struct window_customize_itemdata  **item_list;
144
  u_int           item_size;
145
146
  struct cmd_find_state       fs;
147
  enum window_customize_change      change;
148
};
149
150
struct window_customize_editdata {
151
  u_int           wp_id;
152
  enum window_customize_edit_type     edit_type;
153
  struct window_customize_itemdata   *item;
154
  struct spawn_editor_state    *editor;
155
};
156
157
static uint64_t
158
window_customize_get_tag(struct options_entry *o, struct options_array_item *a,
159
    const struct options_table_entry *oe)
160
0
{
161
0
  uint64_t  offset;
162
163
0
  if (a != NULL)
164
0
    return ((uint64_t)(uintptr_t)a);
165
0
  if (oe == NULL)
166
0
    return ((uint64_t)o);
167
0
  offset = ((char *)oe - (char *)options_table) / sizeof *options_table;
168
0
  return ((2ULL << 62)|(offset << 32)|1);
169
0
}
170
171
static struct options *
172
window_customize_get_tree(enum window_customize_scope scope,
173
    struct cmd_find_state *fs)
174
0
{
175
0
  switch (scope) {
176
0
  case WINDOW_CUSTOMIZE_NONE:
177
0
  case WINDOW_CUSTOMIZE_KEY:
178
0
    return (NULL);
179
0
  case WINDOW_CUSTOMIZE_SERVER:
180
0
    return (global_options);
181
0
  case WINDOW_CUSTOMIZE_GLOBAL_SESSION:
182
0
    return (global_s_options);
183
0
  case WINDOW_CUSTOMIZE_SESSION:
184
0
    return (fs->s->options);
185
0
  case WINDOW_CUSTOMIZE_GLOBAL_WINDOW:
186
0
    return (global_w_options);
187
0
  case WINDOW_CUSTOMIZE_WINDOW:
188
0
    return (fs->w->options);
189
0
  case WINDOW_CUSTOMIZE_PANE:
190
0
    return (fs->wp->options);
191
0
  case WINDOW_CUSTOMIZE_GLOBAL_ENVIRONMENT:
192
0
  case WINDOW_CUSTOMIZE_SESSION_ENVIRONMENT:
193
0
    return (NULL);
194
0
  }
195
0
  return (NULL);
196
0
}
197
198
static struct environ *
199
window_customize_get_environment(enum window_customize_scope scope,
200
    struct cmd_find_state *fs)
201
0
{
202
0
  switch (scope) {
203
0
  case WINDOW_CUSTOMIZE_GLOBAL_ENVIRONMENT:
204
0
    return (global_environ);
205
0
  case WINDOW_CUSTOMIZE_SESSION_ENVIRONMENT:
206
0
    return (fs->s->environ);
207
0
  default:
208
0
    return (NULL);
209
0
  }
210
0
}
211
212
static int
213
window_customize_check_item(struct window_customize_modedata *data,
214
    struct window_customize_itemdata *item, struct cmd_find_state *fsp)
215
0
{
216
0
  struct cmd_find_state fs;
217
218
0
  if (fsp == NULL)
219
0
    fsp = &fs;
220
221
0
  if (cmd_find_valid_state(&data->fs))
222
0
    cmd_find_copy_state(fsp, &data->fs);
223
0
  else
224
0
    cmd_find_from_pane(fsp, data->wp, 0);
225
0
  if (item->type == WINDOW_CUSTOMIZE_ITEM_ENVIRONMENT) {
226
0
    return (item->environ ==
227
0
        window_customize_get_environment(item->scope, fsp));
228
0
  }
229
0
  return (item->oo == window_customize_get_tree(item->scope, fsp));
230
0
}
231
232
static int
233
window_customize_get_key(struct window_customize_itemdata *item,
234
    struct key_table **ktp, struct key_binding **bdp)
235
0
{
236
0
  struct key_table  *kt;
237
0
  struct key_binding  *bd;
238
239
0
  kt = key_bindings_get_table(item->table, 0);
240
0
  if (kt == NULL)
241
0
    return (0);
242
0
  bd = key_bindings_get(kt, item->key);
243
0
  if (bd == NULL)
244
0
    return (0);
245
246
0
  if (ktp != NULL)
247
0
    *ktp = kt;
248
0
  if (bdp != NULL)
249
0
    *bdp = bd;
250
0
  return (1);
251
0
}
252
253
static char *
254
window_customize_scope_text(enum window_customize_scope scope,
255
    struct cmd_find_state *fs)
256
0
{
257
0
  char  *s;
258
0
  u_int  idx;
259
260
0
  switch (scope) {
261
0
  case WINDOW_CUSTOMIZE_PANE:
262
0
    window_pane_index(fs->wp, &idx);
263
0
    xasprintf(&s, "pane %u", idx);
264
0
    break;
265
0
  case WINDOW_CUSTOMIZE_SESSION:
266
0
  case WINDOW_CUSTOMIZE_SESSION_ENVIRONMENT:
267
0
    xasprintf(&s, "session %s", fs->s->name);
268
0
    break;
269
0
  case WINDOW_CUSTOMIZE_WINDOW:
270
0
    xasprintf(&s, "window %u", fs->wl->idx);
271
0
    break;
272
0
  default:
273
0
    s = xstrdup("");
274
0
    break;
275
0
  }
276
0
  return (s);
277
0
}
278
279
static int
280
window_customize_write_hook_fire(struct screen_write_ctx *ctx, u_int cx,
281
    u_int sx, u_int sy, struct options_entry *o)
282
0
{
283
0
  char  *fire_time_string;
284
0
  u_int  fire_count;
285
0
  time_t   fire_time;
286
287
0
  if (options_get_monitor_data(o) != NULL) {
288
0
    fire_count = hooks_monitor_get_fire_count(o);
289
0
    fire_time = hooks_monitor_get_fire_time(o);
290
0
  } else {
291
0
    fire_count = options_get_fire_count(o);
292
0
    fire_time = options_get_fire_time(o);
293
0
  }
294
0
  if (fire_time != 0) {
295
0
    fire_time_string = format_pretty_time(fire_time, 0);
296
0
    if (!screen_write_text(ctx, cx, sx, sy, 0, &grid_default_cell,
297
0
        "This hook has been fired %u times, last %s.", fire_count,
298
0
        fire_time_string)) {
299
0
      free(fire_time_string);
300
0
      return (0);
301
0
    }
302
0
    free(fire_time_string);
303
0
    return (1);
304
0
  }
305
0
  return (screen_write_text(ctx, cx, sx, sy, 0, &grid_default_cell,
306
0
      "This hook has been fired %u times.", fire_count));
307
0
}
308
309
static struct window_customize_itemdata *
310
window_customize_add_item(struct window_customize_modedata *data)
311
0
{
312
0
  struct window_customize_itemdata  *item;
313
314
0
  data->item_list = xreallocarray(data->item_list, data->item_size + 1,
315
0
      sizeof *data->item_list);
316
0
  item = data->item_list[data->item_size++] = xcalloc(1, sizeof *item);
317
0
  return (item);
318
0
}
319
320
static int printflike(7, 8)
321
window_customize_write_value(struct screen_write_ctx *ctx, u_int cx,
322
    u_int sx, u_int sy, int more, const char *label, const char *fmt, ...)
323
0
{
324
0
  struct screen   *s = ctx->s;
325
0
  struct grid_cell   gc;
326
0
  va_list      ap;
327
0
  char      *value;
328
0
  u_int      cy = s->cy;
329
0
  int      retval;
330
331
0
  if (sy == 0)
332
0
    return (0);
333
0
  if (!screen_write_text(ctx, cx, sx, sy, 1, &grid_default_cell, "%s",
334
0
      label))
335
0
    return (0);
336
0
  if (s->cy - cy >= sy)
337
0
    return (0);
338
0
  sy -= s->cy - cy;
339
340
0
  memcpy(&gc, &grid_default_cell, sizeof gc);
341
0
  gc.fg = COLOUR_THEME_LIGHT_GREY|COLOUR_FLAG_THEME;
342
343
0
  va_start(ap, fmt);
344
0
  xvasprintf(&value, fmt, ap);
345
0
  va_end(ap);
346
347
0
  retval = screen_write_text(ctx, cx, sx, sy, more, &gc, "%s", value);
348
0
  free(value);
349
0
  return (retval);
350
0
}
351
352
static void
353
window_customize_free_item(struct window_customize_itemdata *item)
354
0
{
355
0
  free(item->table);
356
0
  free(item->name);
357
0
  free(item->array_key);
358
0
  free(item);
359
0
}
360
361
static struct window_customize_itemdata *
362
window_customize_copy_item(struct window_customize_itemdata *item)
363
0
{
364
0
  struct window_customize_itemdata  *new_item;
365
366
0
  new_item = xcalloc(1, sizeof *new_item);
367
0
  new_item->data = item->data;
368
0
  new_item->type = item->type;
369
0
  new_item->option_type = item->option_type;
370
0
  new_item->scope = item->scope;
371
0
  new_item->key = item->key;
372
0
  new_item->oo = item->oo;
373
0
  new_item->environ = item->environ;
374
0
  new_item->environ_flags = item->environ_flags;
375
0
  if (item->table != NULL)
376
0
    new_item->table = xstrdup(item->table);
377
0
  if (item->name != NULL)
378
0
    new_item->name = xstrdup(item->name);
379
0
  if (item->array_key != NULL)
380
0
    new_item->array_key = xstrdup(item->array_key);
381
0
  return (new_item);
382
0
}
383
384
static void
385
window_customize_finish_edit(struct window_customize_editdata *ed)
386
0
{
387
0
  window_customize_free_item(ed->item);
388
0
  free(ed);
389
0
}
390
391
static void
392
window_customize_draw_waiting(struct window_customize_modedata *data)
393
0
{
394
0
  struct screen_write_ctx  ctx;
395
0
  struct screen   *s = data->wp->screen;
396
0
  struct grid_cell   gc;
397
0
  char       text[128];
398
0
  u_int      sx, sy, box_w, box_h, x, y, text_x;
399
0
  size_t       textlen;
400
0
  pid_t      pid;
401
402
0
  if (data->editor == NULL)
403
0
    return;
404
0
  sx = screen_size_x(s);
405
0
  sy = screen_size_y(s);
406
0
  if (sx == 0 || sy == 0)
407
0
    return;
408
409
0
  pid = spawn_get_editor_pid(data->editor);
410
0
  if (pid == -1)
411
0
    xsnprintf(text, sizeof text, "WAITING FOR EDITOR");
412
0
  else {
413
0
    xsnprintf(text, sizeof text, "WAITING FOR EDITOR (PID %ld)",
414
0
        (long)pid);
415
0
  }
416
417
0
  textlen = strlen(text);
418
0
  box_w = textlen + 4;
419
0
  box_h = 3;
420
0
  if (sx < box_w || sy < box_h)
421
0
    return;
422
0
  x = (sx - box_w) / 2;
423
0
  y = (sy - box_h) / 2;
424
0
  text_x = x + (box_w - textlen) / 2;
425
426
0
  memcpy(&gc, &grid_default_cell, sizeof gc);
427
0
  screen_write_start(&ctx, s);
428
0
  screen_write_cursormove(&ctx, x, y, 0);
429
0
  screen_write_box(&ctx, box_w, box_h, BOX_LINES_DEFAULT, &gc, NULL);
430
0
  screen_write_cursormove(&ctx, x + 1, y + 1, 0);
431
0
  screen_write_clearcharacter(&ctx, box_w - 2, gc.bg);
432
0
  screen_write_cursormove(&ctx, text_x, y + 1, 0);
433
0
  screen_write_nputs(&ctx, box_w - 2, &gc, "%s", text);
434
0
  screen_write_stop(&ctx);
435
0
}
436
437
static int
438
window_customize_set_option_value(struct window_customize_itemdata *item,
439
    const char *s, char **cause)
440
0
{
441
0
  struct options_entry      *o;
442
0
  const struct options_table_entry  *oe;
443
0
  struct options        *oo = item->oo;
444
0
  const char        *name = item->name;
445
0
  const char        *array_key = item->array_key;
446
0
  u_int          idx;
447
0
  char           keybuf[32];
448
449
0
  o = options_get(oo, name);
450
0
  if (o == NULL)
451
0
    return (-1);
452
0
  oe = options_table_entry(o);
453
454
0
  if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_ARRAY)) {
455
0
    if (array_key == NULL) {
456
0
      for (idx = 0; idx < INT_MAX; idx++) {
457
0
        if (options_array_getv(o, "%u", idx) == NULL)
458
0
          break;
459
0
      }
460
0
      xsnprintf(keybuf, sizeof keybuf, "%u", idx);
461
0
      array_key = keybuf;
462
0
    }
463
0
    if (options_array_set(o, array_key, s, 0, cause) != 0)
464
0
      return (-1);
465
0
  } else {
466
0
    if (options_from_string(oo, oe, name, s, 0, cause) != 0)
467
0
      return (-1);
468
0
  }
469
0
  if (item->option_type == WINDOW_CUSTOMIZE_HOOKS && *name == '@')
470
0
    hooks_add_event(name);
471
472
0
  options_push_changes(item->name);
473
0
  return (0);
474
0
}
475
476
static int
477
window_customize_option_editable(struct window_customize_modedata *data,
478
    struct window_customize_itemdata *item)
479
0
{
480
0
  struct options_entry      *o;
481
0
  const struct options_table_entry  *oe;
482
483
0
  if (item->type != WINDOW_CUSTOMIZE_ITEM_OPTION ||
484
0
      !window_customize_check_item(data, item, NULL))
485
0
    return (0);
486
487
0
  o = options_get(item->oo, item->name);
488
0
  if (o == NULL)
489
0
    return (0);
490
0
  oe = options_table_entry(o);
491
0
  if (oe == NULL)
492
0
    return (1);
493
0
  if (oe->type == OPTIONS_TABLE_FLAG || oe->type == OPTIONS_TABLE_CHOICE)
494
0
    return (0);
495
0
  return (1);
496
0
}
497
498
static int
499
window_customize_set_command_value(struct window_customize_itemdata *item,
500
    const char *s, char **cause)
501
0
{
502
0
  struct key_binding    *bd;
503
0
  struct cmd_parse_result   *pr;
504
505
0
  if (!window_customize_get_key(item, NULL, &bd))
506
0
    return (-1);
507
508
0
  pr = cmd_parse_from_string(s, NULL);
509
0
  switch (pr->status) {
510
0
  case CMD_PARSE_ERROR:
511
0
    *cause = pr->error;
512
0
    return (-1);
513
0
  case CMD_PARSE_SUCCESS:
514
0
    break;
515
0
  }
516
0
  cmd_list_free(bd->cmdlist);
517
0
  bd->cmdlist = pr->cmdlist;
518
0
  return (0);
519
0
}
520
521
static int
522
window_customize_set_note_value(struct window_customize_itemdata *item,
523
    const char *s)
524
0
{
525
0
  struct key_binding  *bd;
526
527
0
  if (!window_customize_get_key(item, NULL, &bd))
528
0
    return (-1);
529
530
0
  free((void *)bd->note);
531
0
  if (*s == '\0')
532
0
    bd->note = NULL;
533
0
  else
534
0
    bd->note = xstrdup(s);
535
0
  return (0);
536
0
}
537
538
static void
539
window_customize_set_environment_value(struct window_customize_itemdata *item,
540
    const char *s)
541
0
{
542
0
  struct environ_entry  *envent;
543
0
  int      flags;
544
545
0
  flags = item->environ_flags;
546
0
  envent = environ_find(item->environ, item->name);
547
0
  if (envent != NULL)
548
0
    flags = envent->flags;
549
0
  environ_set(item->environ, item->name, flags, "%s", s);
550
0
}
551
552
static int
553
window_customize_option_is_changed(struct options_entry *o,
554
    const char *array_key)
555
0
{
556
0
  const struct options_table_entry  *oe = options_table_entry(o);
557
0
  struct options      *oo;
558
0
  struct options_entry    *defaults;
559
0
  union options_value   *ov, *default_ov;
560
0
  char        *value, *default_value;
561
0
  int        changed;
562
563
0
  if (oe == NULL || options_get_monitor_data(o) != NULL)
564
0
    return (1);
565
0
  if (*options_name(o) == '@' && hooks_is_event(options_name(o)))
566
0
    return (1);
567
568
0
  if (oe->flags & OPTIONS_TABLE_IS_ARRAY) {
569
0
    oo = options_create(NULL);
570
0
    defaults = options_default(oo, oe);
571
0
    if (array_key != NULL) {
572
0
      ov = options_array_get(o, array_key);
573
0
      default_ov = options_array_get(defaults, array_key);
574
0
      if (ov == NULL || default_ov == NULL) {
575
0
        changed = (ov != default_ov);
576
0
        options_free(oo);
577
0
        return (changed);
578
0
      }
579
0
    }
580
0
    value = options_to_string(o, array_key, 0);
581
0
    default_value = options_to_string(defaults, array_key, 0);
582
0
    changed = (strcmp(value, default_value) != 0);
583
0
    free(value);
584
0
    free(default_value);
585
0
    options_free(oo);
586
0
    return (changed);
587
0
  }
588
589
0
  value = options_to_string(o, NULL, 0);
590
0
  default_value = options_default_to_string(oe);
591
0
  changed = (strcmp(value, default_value) != 0);
592
0
  free(value);
593
0
  free(default_value);
594
0
  return (changed);
595
0
}
596
597
static int
598
window_customize_key_is_changed(struct key_table *kt, struct key_binding *bd)
599
0
{
600
0
  struct key_binding  *default_bd;
601
0
  char      *cmd, *default_cmd;
602
0
  int      changed;
603
604
0
  default_bd = key_bindings_get_default(kt, bd->key);
605
0
  if (default_bd == NULL)
606
0
    return (1);
607
0
  if (bd->flags != default_bd->flags)
608
0
    return (1);
609
0
  if ((bd->note == NULL) != (default_bd->note == NULL))
610
0
    return (1);
611
0
  if (bd->note != NULL && strcmp(bd->note, default_bd->note) != 0)
612
0
    return (1);
613
614
0
  cmd = cmd_list_print(bd->cmdlist, 0);
615
0
  default_cmd = cmd_list_print(default_bd->cmdlist, 0);
616
0
  changed = (strcmp(cmd, default_cmd) != 0);
617
0
  free(cmd);
618
0
  free(default_cmd);
619
0
  return (changed);
620
0
}
621
622
static u_int
623
window_customize_build_array(struct window_customize_modedata *data,
624
    struct mode_tree_item *top, enum window_customize_scope scope,
625
    struct options_entry *o, struct format_tree *ft)
626
0
{
627
0
  const struct options_table_entry  *oe = options_table_entry(o);
628
0
  struct options        *oo = options_owner(o);
629
0
  struct window_customize_itemdata  *item;
630
0
  struct options_array_item   *ai;
631
0
  char          *name, *value, *text;
632
0
  uint64_t         tag;
633
0
  const char        *array_key;
634
0
  u_int          count = 0;
635
636
0
  ai = options_array_first(o);
637
0
  while (ai != NULL) {
638
0
    array_key = options_array_item_key(ai);
639
0
    if (data->hide_default &&
640
0
        !window_customize_option_is_changed(o, array_key)) {
641
0
      ai = options_array_next(ai);
642
0
      continue;
643
0
    }
644
645
0
    xasprintf(&name, "%s[%s]", options_name(o), array_key);
646
0
    format_add(ft, "option_name", "%s", name);
647
0
    value = options_to_string(o, array_key, 0);
648
0
    format_add(ft, "option_value", "%s", value);
649
650
0
    item = window_customize_add_item(data);
651
0
    item->type = WINDOW_CUSTOMIZE_ITEM_OPTION;
652
0
    if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_HOOK))
653
0
      item->option_type = WINDOW_CUSTOMIZE_HOOKS;
654
0
    item->scope = scope;
655
0
    item->oo = oo;
656
0
    item->name = xstrdup(options_name(o));
657
0
    item->array_key = xstrdup(array_key);
658
659
0
    text = format_expand(ft, data->format);
660
0
    tag = window_customize_get_tag(o, ai, oe);
661
0
    mode_tree_add(data->data, top, item, tag, name, text, -1);
662
0
    free(text);
663
664
0
    free(name);
665
0
    free(value);
666
0
    count++;
667
668
0
    ai = options_array_next(ai);
669
0
  }
670
0
  return (count);
671
0
}
672
673
static u_int
674
window_customize_build_option(struct window_customize_modedata *data,
675
    struct mode_tree_item *top, enum window_customize_scope scope,
676
    struct options_entry *o, struct format_tree *ft,
677
    const char *filter, struct cmd_find_state *fs,
678
    enum window_customize_option_type type)
679
0
{
680
0
  const struct options_table_entry  *oe = options_table_entry(o);
681
0
  struct options        *oo = options_owner(o);
682
0
  const char        *name = options_name(o);
683
0
  struct window_customize_itemdata  *item;
684
0
  char          *text, *expanded, *value;
685
0
  int          global = 0, array = 0;
686
0
  int          is_hook = 0, is_monitor = 0;
687
0
  int          is_user_hook = 0, is_any_hook;
688
0
  uint64_t         tag;
689
690
0
  if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_HOOK))
691
0
    is_hook = 1;
692
0
  if (options_get_monitor_data(o) != NULL)
693
0
    is_monitor = 1;
694
0
  if (*name == '@' && hooks_is_event(name))
695
0
    is_user_hook = 1;
696
0
  is_any_hook = (is_hook || is_monitor || is_user_hook);
697
0
  switch (type) {
698
0
  case WINDOW_CUSTOMIZE_OPTIONS:
699
0
    if (is_any_hook)
700
0
      return (0);
701
0
    break;
702
0
  case WINDOW_CUSTOMIZE_HOOKS:
703
0
    if (!is_any_hook)
704
0
      return (0);
705
0
    break;
706
0
  }
707
0
  if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_ARRAY))
708
0
    array = 1;
709
710
0
  if (scope == WINDOW_CUSTOMIZE_SERVER ||
711
0
      scope == WINDOW_CUSTOMIZE_GLOBAL_SESSION ||
712
0
      scope == WINDOW_CUSTOMIZE_GLOBAL_WINDOW)
713
0
    global = 1;
714
0
  if (data->hide_global && global)
715
0
    return (0);
716
0
  if (data->hide_default && !window_customize_option_is_changed(o, NULL))
717
0
    return (0);
718
719
0
  format_add(ft, "option_name", "%s", name);
720
0
  format_add(ft, "option_is_global", "%d", global);
721
0
  format_add(ft, "option_is_array", "%d", array);
722
0
  format_add(ft, "option_is_hook", "%d", is_hook);
723
0
  format_add(ft, "option_is_monitor", "%d", is_monitor);
724
725
0
  text = window_customize_scope_text(scope, fs);
726
0
  format_add(ft, "option_scope", "%s", text);
727
0
  free(text);
728
729
0
  if (oe != NULL && oe->unit != NULL)
730
0
    format_add(ft, "option_unit", "%s", oe->unit);
731
0
  else
732
0
    format_add(ft, "option_unit", "%s", "");
733
734
0
  if (is_monitor) {
735
0
    value = hooks_monitor_to_string(o);
736
0
    if (value != NULL) {
737
0
      format_add(ft, "option_monitor", "%s", value);
738
0
      free(value);
739
0
    } else
740
0
      format_add(ft, "option_monitor", "%s", "");
741
0
  } else
742
0
    format_add(ft, "option_monitor", "%s", "");
743
744
0
  if (!array) {
745
0
    value = options_to_string(o, NULL, 0);
746
0
    format_add(ft, "option_value", "%s", value);
747
0
    free(value);
748
0
  }
749
750
0
  if (filter != NULL) {
751
0
    expanded = format_expand(ft, filter);
752
0
    if (!format_true(expanded)) {
753
0
      free(expanded);
754
0
      return (0);
755
0
    }
756
0
    free(expanded);
757
0
  }
758
0
  item = window_customize_add_item(data);
759
0
  item->type = WINDOW_CUSTOMIZE_ITEM_OPTION;
760
0
  item->option_type = type;
761
0
  item->oo = oo;
762
0
  item->scope = scope;
763
0
  item->name = xstrdup(name);
764
765
0
  if (array)
766
0
    text = NULL;
767
0
  else
768
0
    text = format_expand(ft, data->format);
769
0
  tag = window_customize_get_tag(o, NULL, oe);
770
0
  top = mode_tree_add(data->data, top, item, tag, name, text, 0);
771
0
  free(text);
772
773
0
  if (!array)
774
0
    return (1);
775
0
  return (1 + window_customize_build_array(data, top, scope, o, ft));
776
0
}
777
778
static void
779
window_customize_find_user_options(struct options *oo, const char ***list,
780
    u_int *size)
781
0
{
782
0
  struct options_entry  *o;
783
0
  const char    *name;
784
0
  u_int      i;
785
786
0
  o = options_first(oo);
787
0
  while (o != NULL) {
788
0
    name = options_name(o);
789
0
    if (*name != '@') {
790
0
      o = options_next(o);
791
0
      continue;
792
0
    }
793
0
    for (i = 0; i < *size; i++) {
794
0
      if (strcmp((*list)[i], name) == 0)
795
0
        break;
796
0
    }
797
0
    if (i != *size) {
798
0
      o = options_next(o);
799
0
      continue;
800
0
    }
801
0
    *list = xreallocarray(*list, (*size) + 1, sizeof **list);
802
0
    (*list)[(*size)++] = name;
803
804
0
    o = options_next(o);
805
0
  }
806
0
}
807
808
static void
809
window_customize_build_options(struct window_customize_modedata *data,
810
    const char *title, uint64_t tag,
811
    enum window_customize_scope scope0, struct options *oo0,
812
    enum window_customize_scope scope1, struct options *oo1,
813
    enum window_customize_scope scope2, struct options *oo2,
814
    struct format_tree *ft, const char *filter, struct cmd_find_state *fs,
815
    enum window_customize_option_type type)
816
0
{
817
0
  struct mode_tree_item    *top;
818
0
  struct options_entry     *o = NULL, *loop;
819
0
  const char      **list = NULL, *name;
820
0
  u_int         size = 0, i, count = 0;
821
0
  enum window_customize_scope   scope;
822
823
0
  top = mode_tree_add(data->data, NULL, NULL, tag, title, NULL, 0);
824
0
  mode_tree_no_tag(top);
825
826
  /*
827
   * We get the options from the first tree, but build it using the
828
   * values from the other two. Any tree can have user options so we need
829
   * to build a separate list of them.
830
   */
831
832
0
  window_customize_find_user_options(oo0, &list, &size);
833
0
  if (oo1 != NULL)
834
0
    window_customize_find_user_options(oo1, &list, &size);
835
0
  if (oo2 != NULL)
836
0
    window_customize_find_user_options(oo2, &list, &size);
837
838
0
  for (i = 0; i < size; i++) {
839
0
    o = NULL;
840
0
    if (oo2 != NULL)
841
0
      o = options_get(oo2, list[i]);
842
0
    if (o == NULL && oo1 != NULL)
843
0
      o = options_get(oo1, list[i]);
844
0
    if (o == NULL)
845
0
      o = options_get(oo0, list[i]);
846
0
    if (options_owner(o) == oo2)
847
0
      scope = scope2;
848
0
    else if (options_owner(o) == oo1)
849
0
      scope = scope1;
850
0
    else
851
0
      scope = scope0;
852
0
    count += window_customize_build_option(data, top, scope, o, ft,
853
0
        filter, fs, type);
854
0
  }
855
0
  free(list);
856
857
0
  loop = options_first(oo0);
858
0
  while (loop != NULL) {
859
0
    name = options_name(loop);
860
0
    if (*name == '@') {
861
0
      loop = options_next(loop);
862
0
      continue;
863
0
    }
864
0
    if (oo2 != NULL)
865
0
      o = options_get(oo2, name);
866
0
    else if (oo1 != NULL)
867
0
      o = options_get(oo1, name);
868
0
    else
869
0
      o = loop;
870
0
    if (options_owner(o) == oo2)
871
0
      scope = scope2;
872
0
    else if (options_owner(o) == oo1)
873
0
      scope = scope1;
874
0
    else
875
0
      scope = scope0;
876
0
    count += window_customize_build_option(data, top, scope, o, ft,
877
0
        filter, fs, type);
878
0
    loop = options_next(loop);
879
0
  }
880
0
  if (data->hide_default && count == 0)
881
0
    mode_tree_remove(data->data, top);
882
0
}
883
884
static uint64_t
885
window_customize_key_tag(const void *ptr, u_int type)
886
0
{
887
0
  return ((uint64_t)(uintptr_t)ptr|type);
888
0
}
889
890
static void
891
window_customize_build_keys(struct window_customize_modedata *data,
892
    struct key_table *kt, struct format_tree *ft, const char *filter,
893
    struct cmd_find_state *fs)
894
0
{
895
0
  struct mode_tree_item     *top, *child, *mti;
896
0
  struct window_customize_itemdata  *item;
897
0
  struct key_binding      *bd;
898
0
  char          *title, *text, *tmp, *expanded;
899
0
  const char        *flag;
900
0
  u_int          count = 0;
901
902
0
  xasprintf(&title, "Key Table - %s", kt->name);
903
0
  top = mode_tree_add(data->data, NULL, NULL,
904
0
      window_customize_key_tag(kt, 0), title, NULL, 0);
905
0
  mode_tree_no_tag(top);
906
0
  free(title);
907
908
0
  ft = format_create_from_state(NULL, NULL, fs);
909
0
  format_add(ft, "is_option", "0");
910
0
  format_add(ft, "is_key", "1");
911
0
  format_add(ft, "is_environment", "0");
912
913
0
  bd = key_bindings_first(kt);
914
0
  while (bd != NULL) {
915
0
    if (data->hide_default &&
916
0
        !window_customize_key_is_changed(kt, bd)) {
917
0
      bd = key_bindings_next(kt, bd);
918
0
      continue;
919
0
    }
920
921
0
    format_add(ft, "key", "%s", key_string_lookup_key(bd->key, 0));
922
0
    if (bd->note != NULL)
923
0
      format_add(ft, "key_note", "%s", bd->note);
924
0
    if (filter != NULL) {
925
0
      expanded = format_expand(ft, filter);
926
0
      if (!format_true(expanded)) {
927
0
        free(expanded);
928
0
        bd = key_bindings_next(kt, bd);
929
0
        continue;
930
0
      }
931
0
      free(expanded);
932
0
    }
933
934
0
    item = window_customize_add_item(data);
935
0
    item->type = WINDOW_CUSTOMIZE_ITEM_KEY;
936
0
    item->scope = WINDOW_CUSTOMIZE_KEY;
937
0
    item->table = xstrdup(kt->name);
938
0
    item->key = bd->key;
939
0
    item->name = xstrdup(key_string_lookup_key(item->key, 0));
940
941
0
    expanded = format_expand(ft, data->format);
942
0
    child = mode_tree_add(data->data, top, item,
943
0
        window_customize_key_tag(bd, 0), expanded, NULL, 0);
944
0
    free(expanded);
945
946
0
    tmp = cmd_list_print(bd->cmdlist, 0);
947
0
    xasprintf(&text, "#[fg=themelightgrey]#[ignore]%s", tmp);
948
0
    free(tmp);
949
0
    mti = mode_tree_add(data->data, child, item,
950
0
        window_customize_key_tag(bd, 1), "Command", text, -1);
951
0
    mode_tree_draw_as_parent(mti);
952
0
    mode_tree_no_tag(mti);
953
0
    free(text);
954
955
0
    if (bd->note != NULL) {
956
0
      xasprintf(&text, "#[fg=themelightgrey]#[ignore]%s",
957
0
          bd->note);
958
0
    } else
959
0
      text = xstrdup("");
960
0
    mti = mode_tree_add(data->data, child, item,
961
0
        window_customize_key_tag(bd, 2), "Note", text, -1);
962
0
    mode_tree_draw_as_parent(mti);
963
0
    mode_tree_no_tag(mti);
964
0
    free(text);
965
966
0
    if (bd->flags & KEY_BINDING_REPEAT)
967
0
      flag = "on";
968
0
    else
969
0
      flag = "off";
970
0
    xasprintf(&text, "#[fg=themelightgrey]#[ignore]%s", flag);
971
0
    mti = mode_tree_add(data->data, child, item,
972
0
        window_customize_key_tag(bd, 3), "Repeat", text, -1);
973
0
    mode_tree_draw_as_parent(mti);
974
0
    mode_tree_no_tag(mti);
975
0
    free(text);
976
977
0
    count++;
978
0
    bd = key_bindings_next(kt, bd);
979
0
  }
980
981
0
  format_free(ft);
982
0
  if (data->hide_default && count == 0)
983
0
    mode_tree_remove(data->data, top);
984
0
}
985
986
static void
987
window_customize_build_environment(struct window_customize_modedata *data,
988
    const char *title, uint64_t tag, enum window_customize_scope scope,
989
    struct environ *env, struct format_tree *ft, const char *filter,
990
    struct cmd_find_state *fs)
991
0
{
992
0
  struct mode_tree_item   *top;
993
0
  struct window_customize_itemdata  *item;
994
0
  struct environ_entry    *envent;
995
0
  char        *name, *text, *expanded, *value;
996
0
  uint64_t       item_tag;
997
0
  int        global;
998
999
0
  if (data->hide_default)
1000
0
    return;
1001
1002
0
  top = mode_tree_add(data->data, NULL, NULL, tag, title, NULL, 0);
1003
0
  mode_tree_no_tag(top);
1004
1005
0
  global = (scope == WINDOW_CUSTOMIZE_GLOBAL_ENVIRONMENT);
1006
0
  format_add(ft, "is_option", "0");
1007
0
  format_add(ft, "is_key", "0");
1008
0
  format_add(ft, "is_environment", "1");
1009
0
  format_add(ft, "environment_is_global", "%d", global);
1010
1011
0
  text = window_customize_scope_text(scope, fs);
1012
0
  format_add(ft, "environment_scope", "%s", text);
1013
0
  free(text);
1014
1015
0
  envent = environ_first(env);
1016
0
  while (envent != NULL) {
1017
0
    format_add(ft, "environment_name", "%s", envent->name);
1018
0
    format_add(ft, "environment_hidden", "%d",
1019
0
        !!(envent->flags & ENVIRON_HIDDEN));
1020
0
    format_add(ft, "environment_removed", "%d",
1021
0
        envent->value == NULL);
1022
0
    if (envent->value == NULL)
1023
0
      value = xstrdup("");
1024
0
    else
1025
0
      value = xstrdup(envent->value);
1026
0
    format_add(ft, "environment_value", "%s", value);
1027
1028
0
    if (filter != NULL) {
1029
0
      expanded = format_expand(ft, filter);
1030
0
      if (!format_true(expanded)) {
1031
0
        free(expanded);
1032
0
        free(value);
1033
0
        envent = environ_next(envent);
1034
0
        continue;
1035
0
      }
1036
0
      free(expanded);
1037
0
    }
1038
1039
0
    item = window_customize_add_item(data);
1040
0
    item->type = WINDOW_CUSTOMIZE_ITEM_ENVIRONMENT;
1041
0
    item->scope = scope;
1042
0
    item->environ = env;
1043
0
    item->environ_flags = envent->flags;
1044
0
    item->name = xstrdup(envent->name);
1045
1046
0
    if (envent->value == NULL) {
1047
0
      xasprintf(&name, "-%s", envent->name);
1048
0
      text = NULL;
1049
0
    } else {
1050
0
      name = xstrdup(envent->name);
1051
0
      text = format_expand(ft, data->format);
1052
0
    }
1053
0
    item_tag = (2ULL << 62)|((uint64_t)(uintptr_t)envent);
1054
0
    mode_tree_add(data->data, top, item, item_tag, name, text, 0);
1055
0
    free(name);
1056
0
    free(text);
1057
0
    free(value);
1058
1059
0
    envent = environ_next(envent);
1060
0
  }
1061
0
}
1062
1063
static void
1064
window_customize_build(void *modedata,
1065
    __unused struct sort_criteria *sort_crit, __unused uint64_t *tag,
1066
    const char *filter)
1067
0
{
1068
0
  struct window_customize_modedata  *data = modedata;
1069
0
  struct cmd_find_state      fs;
1070
0
  struct format_tree      *ft;
1071
0
  u_int          i;
1072
0
  struct key_table      *kt;
1073
1074
0
  for (i = 0; i < data->item_size; i++)
1075
0
    window_customize_free_item(data->item_list[i]);
1076
0
  free(data->item_list);
1077
0
  data->item_list = NULL;
1078
0
  data->item_size = 0;
1079
1080
0
  if (cmd_find_valid_state(&data->fs))
1081
0
    cmd_find_copy_state(&fs, &data->fs);
1082
0
  else
1083
0
    cmd_find_from_pane(&fs, data->wp, 0);
1084
1085
0
  ft = format_create_from_state(NULL, NULL, &fs);
1086
0
  format_add(ft, "is_option", "1");
1087
0
  format_add(ft, "is_key", "0");
1088
0
  format_add(ft, "is_environment", "0");
1089
1090
0
  window_customize_build_options(data, "Server Options",
1091
0
      (3ULL << 62)|(OPTIONS_TABLE_SERVER << 1)|1,
1092
0
      WINDOW_CUSTOMIZE_SERVER, global_options,
1093
0
      WINDOW_CUSTOMIZE_NONE, NULL,
1094
0
      WINDOW_CUSTOMIZE_NONE, NULL,
1095
0
      ft, filter, &fs, WINDOW_CUSTOMIZE_OPTIONS);
1096
0
  window_customize_build_options(data, "Session Options",
1097
0
      (3ULL << 62)|(OPTIONS_TABLE_SESSION << 1)|1,
1098
0
      WINDOW_CUSTOMIZE_GLOBAL_SESSION, global_s_options,
1099
0
      WINDOW_CUSTOMIZE_SESSION, fs.s->options,
1100
0
      WINDOW_CUSTOMIZE_NONE, NULL,
1101
0
      ft, filter, &fs, WINDOW_CUSTOMIZE_OPTIONS);
1102
0
  window_customize_build_options(data, "Window & Pane Options",
1103
0
      (3ULL << 62)|(OPTIONS_TABLE_WINDOW << 1)|1,
1104
0
      WINDOW_CUSTOMIZE_GLOBAL_WINDOW, global_w_options,
1105
0
      WINDOW_CUSTOMIZE_WINDOW, fs.w->options,
1106
0
      WINDOW_CUSTOMIZE_PANE, fs.wp->options,
1107
0
      ft, filter, &fs, WINDOW_CUSTOMIZE_OPTIONS);
1108
0
  window_customize_build_options(data, "Session Hooks",
1109
0
      (3ULL << 62)|(1ULL << 8)|(OPTIONS_TABLE_SESSION << 1)|1,
1110
0
      WINDOW_CUSTOMIZE_GLOBAL_SESSION, global_s_options,
1111
0
      WINDOW_CUSTOMIZE_SESSION, fs.s->options,
1112
0
      WINDOW_CUSTOMIZE_NONE, NULL,
1113
0
      ft, filter, &fs, WINDOW_CUSTOMIZE_HOOKS);
1114
0
  window_customize_build_options(data, "Window & Pane Hooks",
1115
0
      (3ULL << 62)|(1ULL << 8)|(OPTIONS_TABLE_WINDOW << 1)|1,
1116
0
      WINDOW_CUSTOMIZE_GLOBAL_WINDOW, global_w_options,
1117
0
      WINDOW_CUSTOMIZE_WINDOW, fs.w->options,
1118
0
      WINDOW_CUSTOMIZE_PANE, fs.wp->options,
1119
0
      ft, filter, &fs, WINDOW_CUSTOMIZE_HOOKS);
1120
0
  window_customize_build_environment(data, "Global Environment",
1121
0
      (3ULL << 62)|(2ULL << 8)|1,
1122
0
      WINDOW_CUSTOMIZE_GLOBAL_ENVIRONMENT, global_environ, ft, filter,
1123
0
      &fs);
1124
0
  window_customize_build_environment(data, "Session Environment",
1125
0
      (3ULL << 62)|(2ULL << 8)|3,
1126
0
      WINDOW_CUSTOMIZE_SESSION_ENVIRONMENT, fs.s->environ, ft, filter,
1127
0
      &fs);
1128
1129
0
  format_free(ft);
1130
0
  ft = format_create_from_state(NULL, NULL, &fs);
1131
0
  format_add(ft, "is_environment", "0");
1132
1133
0
  kt = key_bindings_first_table();
1134
0
  while (kt != NULL) {
1135
0
    if (!RB_EMPTY(&kt->key_bindings))
1136
0
      window_customize_build_keys(data, kt, ft, filter, &fs);
1137
0
    kt = key_bindings_next_table(kt);
1138
0
  }
1139
1140
0
  format_free(ft);
1141
0
}
1142
1143
static void
1144
window_customize_draw_key(__unused struct window_customize_modedata *data,
1145
    struct window_customize_itemdata *item, struct screen_write_ctx *ctx,
1146
    u_int sx, u_int sy)
1147
0
{
1148
0
  struct screen   *s = ctx->s;
1149
0
  u_int      cx = s->cx, cy = s->cy;
1150
0
  struct key_table  *kt;
1151
0
  struct key_binding  *bd, *default_bd;
1152
0
  const char    *note, *period = "";
1153
0
  char      *cmd, *default_cmd;
1154
1155
0
  if (item == NULL || !window_customize_get_key(item, &kt, &bd))
1156
0
    return;
1157
1158
0
  note = bd->note;
1159
0
  if (note == NULL)
1160
0
    note = "There is no note for this key.";
1161
0
  if (*note != '\0' && note[strlen (note) - 1] != '.')
1162
0
    period = ".";
1163
0
  if (!screen_write_text(ctx, cx, sx, sy, 0, &grid_default_cell, "%s%s",
1164
0
      note, period))
1165
0
    return;
1166
0
  screen_write_cursormove(ctx, cx, s->cy + 1, 0); /* skip line */
1167
0
  if (s->cy >= cy + sy - 1)
1168
0
    return;
1169
1170
0
  if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 0,
1171
0
      &grid_default_cell, "This key is in the %s table.", kt->name))
1172
0
    return;
1173
0
  if (!window_customize_write_value(ctx, cx, sx, sy - (s->cy - cy), 0,
1174
0
      "Repeat: ", "%s", (bd->flags & KEY_BINDING_REPEAT) ? "on" : "off"))
1175
0
    return;
1176
0
  screen_write_cursormove(ctx, cx, s->cy + 1, 0); /* skip line */
1177
0
  if (s->cy >= cy + sy - 1)
1178
0
    return;
1179
1180
0
  cmd = cmd_list_print(bd->cmdlist, 0);
1181
0
  if (!window_customize_write_value(ctx, cx, sx, sy - (s->cy - cy), 0,
1182
0
      "Command: ", "%s", cmd)) {
1183
0
    free(cmd);
1184
0
    return;
1185
0
  }
1186
0
  default_bd = key_bindings_get_default(kt, bd->key);
1187
0
  if (default_bd != NULL) {
1188
0
    default_cmd = cmd_list_print(default_bd->cmdlist, 0);
1189
0
    if (strcmp(cmd, default_cmd) != 0 &&
1190
0
        !window_customize_write_value(ctx, cx, sx, sy - (s->cy - cy),
1191
0
        0, "The default is: ", "%s", default_cmd)) {
1192
0
      free(default_cmd);
1193
0
      free(cmd);
1194
0
      return;
1195
0
    }
1196
0
    free(default_cmd);
1197
0
  }
1198
0
  free(cmd);
1199
0
}
1200
1201
static void
1202
window_customize_draw_option(struct window_customize_modedata *data,
1203
    struct window_customize_itemdata *item, struct screen_write_ctx *ctx,
1204
    u_int sx, u_int sy)
1205
0
{
1206
0
  struct screen        *s = ctx->s;
1207
0
  u_int           cx = s->cx, cy = s->cy;
1208
0
  struct options_entry       *o, *parent;
1209
0
  struct options         *go, *wo;
1210
0
  const struct options_table_entry   *oe;
1211
0
  struct grid_cell        gc;
1212
0
  const char        **choice, *text, *name;
1213
0
  const char         *array_key;
1214
0
  const char         *space = "", *unit = "";
1215
0
  char           *value = NULL, *expanded;
1216
0
  char           *monitor, label[64];
1217
0
  char           *default_value = NULL;
1218
0
  char            choices[256] = "";
1219
0
  struct cmd_find_state       fs;
1220
0
  struct format_tree       *ft;
1221
0
  int           is_hook, is_monitor, is_user_hook;
1222
0
  int           is_any_hook;
1223
1224
0
  if (!window_customize_check_item(data, item, &fs))
1225
0
    return;
1226
0
  name = item->name;
1227
0
  array_key = item->array_key;
1228
1229
0
  o = options_get(item->oo, name);
1230
0
  if (o == NULL)
1231
0
    return;
1232
0
  oe = options_table_entry(o);
1233
0
  is_hook = (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_HOOK));
1234
0
  is_monitor = (options_get_monitor_data(o) != NULL);
1235
0
  is_user_hook = (*name == '@' && hooks_is_event(name));
1236
0
  is_any_hook = (is_hook || is_monitor || is_user_hook);
1237
1238
0
  if (oe != NULL && oe->unit != NULL) {
1239
0
    space = " ";
1240
0
    unit = oe->unit;
1241
0
  }
1242
0
  ft = format_create_from_state(NULL, NULL, &fs);
1243
1244
0
  if (oe == NULL || oe->text == NULL) {
1245
0
    if (is_monitor)
1246
0
      text = "This hook runs when a monitor changes.";
1247
0
    else if (is_user_hook)
1248
0
      text = "This hook doesn't have a description.";
1249
0
    else
1250
0
      text = "This option doesn't have a description.";
1251
0
  } else
1252
0
    text = oe->text;
1253
0
  if (!screen_write_text(ctx, cx, sx, sy, 0, &grid_default_cell, "%s",
1254
0
      text))
1255
0
    goto out;
1256
0
  screen_write_cursormove(ctx, cx, s->cy + 1, 0); /* skip line */
1257
0
  if (s->cy >= cy + sy - 1)
1258
0
    goto out;
1259
1260
0
  if (is_monitor) {
1261
0
    if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 0,
1262
0
        &grid_default_cell, "This is a monitor hook."))
1263
0
      goto out;
1264
0
    goto monitor;
1265
0
  }
1266
0
  if (oe == NULL)
1267
0
    text = "user";
1268
0
  else if ((oe->scope & (OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE)) ==
1269
0
      (OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE))
1270
0
    text = "window and pane";
1271
0
  else if (oe->scope & OPTIONS_TABLE_WINDOW)
1272
0
    text = "window";
1273
0
  else if (oe->scope & OPTIONS_TABLE_SESSION)
1274
0
    text = "session";
1275
0
  else
1276
0
    text = "server";
1277
0
  if (is_user_hook) {
1278
0
    if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 0,
1279
0
        &grid_default_cell, "This is a user hook."))
1280
0
      goto out;
1281
0
  } else if (is_hook) {
1282
0
    if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 0,
1283
0
        &grid_default_cell, "This is a %s hook.", text))
1284
0
      goto out;
1285
0
  } else {
1286
0
    if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 0,
1287
0
        &grid_default_cell, "This is a %s option.", text))
1288
0
      goto out;
1289
0
  }
1290
1291
0
monitor:
1292
0
  monitor = hooks_monitor_to_string(o);
1293
0
  if (monitor != NULL) {
1294
0
    if (!window_customize_write_value(ctx, cx, sx, sy - (s->cy - cy),
1295
0
        0, "Monitor: ", "%s", monitor)) {
1296
0
      free(monitor);
1297
0
      goto out;
1298
0
    }
1299
0
    free(monitor);
1300
0
  }
1301
0
  if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_ARRAY)) {
1302
0
    if (is_hook) {
1303
0
      if (array_key == NULL) {
1304
0
        if (!screen_write_text(ctx, cx, sx,
1305
0
            sy - (s->cy - cy), 0, &grid_default_cell,
1306
0
            "This is an array hook."))
1307
0
          goto out;
1308
0
        if (!window_customize_write_hook_fire(ctx, cx,
1309
0
            sx, sy - (s->cy - cy), o))
1310
0
          goto out;
1311
0
        goto out;
1312
0
      }
1313
0
    } else if (array_key != NULL) {
1314
0
      if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy),
1315
0
          0, &grid_default_cell,
1316
0
          "This is an array option, key %s.", array_key))
1317
0
        goto out;
1318
0
    } else {
1319
0
      if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy),
1320
0
          0, &grid_default_cell, "This is an array option."))
1321
0
        goto out;
1322
0
    }
1323
0
    if (array_key == NULL)
1324
0
      goto out;
1325
0
  }
1326
0
  screen_write_cursormove(ctx, cx, s->cy + 1, 0); /* skip line */
1327
0
  if (s->cy >= cy + sy - 1)
1328
0
    goto out;
1329
1330
0
  value = options_to_string(o, array_key, 0);
1331
0
  if (oe != NULL && array_key == NULL) {
1332
0
    default_value = options_default_to_string(oe);
1333
0
    if (strcmp(default_value, value) == 0) {
1334
0
      free(default_value);
1335
0
      default_value = NULL;
1336
0
    }
1337
0
  }
1338
0
  if (is_any_hook) {
1339
0
    if (!window_customize_write_value(ctx, cx, sx, sy - (s->cy - cy),
1340
0
        0, "Hook command: ", "%s%s%s", value, space, unit))
1341
0
      goto out;
1342
0
    if (!window_customize_write_hook_fire(ctx, cx, sx,
1343
0
        sy - (s->cy - cy), o))
1344
0
      goto out;
1345
0
  } else {
1346
0
    if (!window_customize_write_value(ctx, cx, sx, sy - (s->cy - cy),
1347
0
        0, "Option value: ", "%s%s%s", value, space, unit))
1348
0
      goto out;
1349
0
  }
1350
0
  if (oe == NULL || oe->type == OPTIONS_TABLE_STRING) {
1351
0
    expanded = format_expand(ft, value);
1352
0
    if (strcmp(expanded, value) != 0) {
1353
0
      if (!window_customize_write_value(ctx, cx, sx,
1354
0
          sy - (s->cy - cy), 0, "This expands to: ", "%s",
1355
0
          expanded)) {
1356
0
        free(expanded);
1357
0
        goto out;
1358
0
      }
1359
0
    }
1360
0
    free(expanded);
1361
0
  }
1362
0
  if (oe != NULL && oe->type == OPTIONS_TABLE_CHOICE) {
1363
0
    for (choice = oe->choices; *choice != NULL; choice++) {
1364
0
      strlcat(choices, *choice, sizeof choices);
1365
0
      strlcat(choices, ", ", sizeof choices);
1366
0
    }
1367
0
    choices[strlen(choices) - 2] = '\0';
1368
0
    if (!window_customize_write_value(ctx, cx, sx,
1369
0
        sy - (s->cy - cy), 0, "Available values are: ", "%s",
1370
0
        choices))
1371
0
      goto out;
1372
0
  }
1373
0
  if (oe != NULL && oe->type == OPTIONS_TABLE_COLOUR) {
1374
0
    if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 1,
1375
0
        &grid_default_cell, "This is a colour option: "))
1376
0
      goto out;
1377
0
    memcpy(&gc, &grid_default_cell, sizeof gc);
1378
0
    gc.fg = options_get_number(item->oo, name);
1379
0
    if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 0, &gc,
1380
0
        "EXAMPLE"))
1381
0
      goto out;
1382
0
  }
1383
0
  if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_COLOUR)) {
1384
0
    if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 1,
1385
0
        &grid_default_cell, "This is a colour option: "))
1386
0
      goto out;
1387
0
    style_apply(&gc, item->oo, name, ft);
1388
0
    if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 0, &gc,
1389
0
        "EXAMPLE"))
1390
0
      goto out;
1391
0
  }
1392
0
  if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_STYLE)) {
1393
0
    if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 1,
1394
0
        &grid_default_cell, "This is a style option: "))
1395
0
      goto out;
1396
0
    style_apply(&gc, item->oo, name, ft);
1397
0
    if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 0, &gc,
1398
0
        "EXAMPLE"))
1399
0
      goto out;
1400
0
  }
1401
0
  if (default_value != NULL) {
1402
0
    if (!window_customize_write_value(ctx, cx, sx, sy - (s->cy - cy),
1403
0
        0, "The default is: ", "%s%s%s", default_value, space, unit))
1404
0
      goto out;
1405
0
  }
1406
1407
0
  screen_write_cursormove(ctx, cx, s->cy + 1, 0); /* skip line */
1408
0
  if (s->cy > cy + sy - 1)
1409
0
    goto out;
1410
0
  if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_ARRAY)) {
1411
0
    wo = NULL;
1412
0
    go = NULL;
1413
0
  } else {
1414
0
    switch (item->scope) {
1415
0
    case WINDOW_CUSTOMIZE_PANE:
1416
0
      wo = options_get_parent(item->oo);
1417
0
      go = options_get_parent(wo);
1418
0
      break;
1419
0
    case WINDOW_CUSTOMIZE_WINDOW:
1420
0
    case WINDOW_CUSTOMIZE_SESSION:
1421
0
      wo = NULL;
1422
0
      go = options_get_parent(item->oo);
1423
0
      break;
1424
0
    default:
1425
0
      wo = NULL;
1426
0
      go = NULL;
1427
0
      break;
1428
0
    }
1429
0
  }
1430
0
  if (wo != NULL && options_owner(o) != wo) {
1431
0
    parent = options_get_only(wo, name);
1432
0
    if (parent != NULL) {
1433
0
      free(value);
1434
0
      value = options_to_string(parent, NULL, 0);
1435
0
      xsnprintf(label, sizeof label,
1436
0
          "Window value (from window %u): ", fs.wl->idx);
1437
0
      if (!window_customize_write_value(ctx, s->cx, sx,
1438
0
          sy - (s->cy - cy), 0, label, "%s%s%s", value, space,
1439
0
          unit))
1440
0
        goto out;
1441
0
    }
1442
0
  }
1443
0
  if (go != NULL && options_owner(o) != go) {
1444
0
    parent = options_get_only(go, name);
1445
0
    if (parent != NULL) {
1446
0
      free(value);
1447
0
      value = options_to_string(parent, NULL, 0);
1448
0
      if (!window_customize_write_value(ctx, s->cx, sx,
1449
0
          sy - (s->cy - cy), 0, "Global value: ", "%s%s%s",
1450
0
          value, space, unit))
1451
0
        goto out;
1452
0
    }
1453
0
  }
1454
1455
0
out:
1456
0
  free(value);
1457
0
  free(default_value);
1458
0
  format_free(ft);
1459
0
}
1460
1461
static void
1462
window_customize_draw_environment(struct window_customize_modedata *data,
1463
    struct window_customize_itemdata *item, struct screen_write_ctx *ctx,
1464
    u_int sx, u_int sy)
1465
0
{
1466
0
  struct screen    *s = ctx->s;
1467
0
  u_int       cx = s->cx, cy = s->cy;
1468
0
  struct environ_entry   *envent, *parent;
1469
0
  struct cmd_find_state   fs;
1470
0
  const char     *text;
1471
1472
0
  if (!window_customize_check_item(data, item, &fs))
1473
0
    return;
1474
0
  envent = environ_find(item->environ, item->name);
1475
0
  if (envent == NULL)
1476
0
    return;
1477
1478
0
  if (item->scope == WINDOW_CUSTOMIZE_GLOBAL_ENVIRONMENT)
1479
0
    text = "global";
1480
0
  else
1481
0
    text = "session";
1482
0
  if (!screen_write_text(ctx, cx, sx, sy, 0, &grid_default_cell,
1483
0
      "This is a %s environment variable.", text))
1484
0
    return;
1485
0
  if (envent->flags & ENVIRON_HIDDEN) {
1486
0
    if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 0,
1487
0
        &grid_default_cell, "This variable is hidden."))
1488
0
      return;
1489
0
  }
1490
1491
0
  screen_write_cursormove(ctx, cx, s->cy + 1, 0); /* skip line */
1492
0
  if (s->cy >= cy + sy - 1)
1493
0
    return;
1494
1495
0
  if (envent->value == NULL) {
1496
0
    if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 0,
1497
0
        &grid_default_cell, "Variable is removed."))
1498
0
      return;
1499
0
  } else {
1500
0
    if (!window_customize_write_value(ctx, cx, sx, sy - (s->cy - cy),
1501
0
        0, "Variable value: ", "%s", envent->value))
1502
0
      return;
1503
0
  }
1504
1505
0
  if (item->scope != WINDOW_CUSTOMIZE_SESSION_ENVIRONMENT)
1506
0
    return;
1507
1508
0
  parent = environ_find(global_environ, item->name);
1509
0
  if (parent == NULL)
1510
0
    return;
1511
0
  if (parent->value == NULL) {
1512
0
    if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 0,
1513
0
        &grid_default_cell, "Global variable is removed."))
1514
0
      return;
1515
0
  } else {
1516
0
    if (!window_customize_write_value(ctx, cx, sx, sy - (s->cy - cy),
1517
0
        0, "Global value: ", "%s", parent->value))
1518
0
      return;
1519
0
  }
1520
0
}
1521
1522
static void
1523
window_customize_draw(void *modedata, void *itemdata,
1524
    struct screen_write_ctx *ctx, u_int sx, u_int sy)
1525
0
{
1526
0
  struct window_customize_modedata  *data = modedata;
1527
0
  struct window_customize_itemdata  *item = itemdata;
1528
1529
0
  if (item == NULL)
1530
0
    return;
1531
1532
0
  if (item->type == WINDOW_CUSTOMIZE_ITEM_KEY)
1533
0
    window_customize_draw_key(data, item, ctx, sx, sy);
1534
0
  else if (item->type == WINDOW_CUSTOMIZE_ITEM_ENVIRONMENT)
1535
0
    window_customize_draw_environment(data, item, ctx, sx, sy);
1536
0
  else
1537
0
    window_customize_draw_option(data, item, ctx, sx, sy);
1538
0
}
1539
1540
static void
1541
window_customize_menu(void *modedata, struct client *c, key_code key)
1542
0
{
1543
0
  struct window_customize_modedata  *data = modedata;
1544
0
  struct window_pane      *wp = data->wp;
1545
0
  struct window_mode_entry    *wme;
1546
1547
0
  wme = TAILQ_FIRST(&wp->modes);
1548
0
  if (wme == NULL || wme->data != modedata)
1549
0
    return;
1550
0
  window_customize_key(wme, c, NULL, NULL, key, NULL);
1551
0
}
1552
1553
static u_int
1554
window_customize_height(__unused void *modedata, __unused u_int height)
1555
0
{
1556
0
  return (12);
1557
0
}
1558
1559
static const char* window_customize_help_lines[] = {
1560
  "#[fg=themelightgrey]"
1561
  "   Enter, s #[#{E:tree-mode-border-style},acs]x#[default] Set %1 value",
1562
  "#[fg=themelightgrey]"
1563
  "          S #[#{E:tree-mode-border-style},acs]x#[default] Set global %1 value",
1564
  "#[fg=themelightgrey]"
1565
  "          w #[#{E:tree-mode-border-style},acs]x#[default] Set window %1 value",
1566
  "#[fg=themelightgrey]"
1567
  "          d #[#{E:tree-mode-border-style},acs]x#[default] Set to default value",
1568
  "#[fg=themelightgrey]"
1569
  "          D #[#{E:tree-mode-border-style},acs]x#[default] Set tagged %1s to default value",
1570
  "#[fg=themelightgrey]"
1571
  "          u #[#{E:tree-mode-border-style},acs]x#[default] Unset an %1",
1572
  "#[fg=themelightgrey]"
1573
  "          U #[#{E:tree-mode-border-style},acs]x#[default] Unset tagged %1s",
1574
  "#[fg=themelightgrey]"
1575
  "          a #[#{E:tree-mode-border-style},acs]x#[default] Change array key",
1576
  "#[fg=themelightgrey]"
1577
  "          e #[#{E:tree-mode-border-style},acs]x#[default] Open %1 value in editor",
1578
  "#[fg=themelightgrey]"
1579
  "          f #[#{E:tree-mode-border-style},acs]x#[default] Enter a filter",
1580
  "#[fg=themelightgrey]"
1581
  "          C #[#{E:tree-mode-border-style},acs]x#[default] Toggle only changed items",
1582
  "#[fg=themelightgrey]"
1583
  "          v #[#{E:tree-mode-border-style},acs]x#[default] Toggle information",
1584
  NULL
1585
};
1586
1587
static const char**
1588
window_customize_help(u_int *width, const char **item)
1589
0
{
1590
0
  *width = 52;
1591
0
  *item = "item";
1592
0
  return (window_customize_help_lines);
1593
0
}
1594
1595
static struct screen *
1596
window_customize_init(struct window_mode_entry *wme,
1597
    __unused struct cmdq_item *item, struct cmd_find_state *fs,
1598
    struct args *args)
1599
0
{
1600
0
  struct window_pane      *wp = wme->wp;
1601
0
  struct window_customize_modedata  *data;
1602
0
  struct screen       *s;
1603
1604
0
  wme->data = data = xcalloc(1, sizeof *data);
1605
0
  data->wp = wp;
1606
0
  data->references = 1;
1607
1608
0
  memcpy(&data->fs, fs, sizeof data->fs);
1609
1610
0
  if (args == NULL || !args_has(args, 'F'))
1611
0
    data->format = xstrdup(WINDOW_CUSTOMIZE_DEFAULT_FORMAT);
1612
0
  else
1613
0
    data->format = xstrdup(args_get(args, 'F'));
1614
0
  if (args_has(args, 'y'))
1615
0
    data->prompt_flags = PROMPT_ACCEPT;
1616
1617
0
  data->data = mode_tree_start(wp, args, window_customize_build,
1618
0
      window_customize_draw, NULL, window_customize_menu,
1619
0
      window_customize_height, NULL, NULL, NULL, window_customize_help,
1620
0
      data, window_customize_menu_items, &s);
1621
0
  mode_tree_zoom(data->data, args);
1622
1623
0
  mode_tree_build(data->data);
1624
0
  mode_tree_draw(data->data);
1625
1626
0
  return (s);
1627
0
}
1628
1629
static void
1630
window_customize_destroy(struct window_customize_modedata *data)
1631
0
{
1632
0
  u_int i;
1633
1634
0
  if (--data->references != 0)
1635
0
    return;
1636
1637
0
  for (i = 0; i < data->item_size; i++)
1638
0
    window_customize_free_item(data->item_list[i]);
1639
0
  free(data->item_list);
1640
1641
0
  free(data->format);
1642
1643
0
  free(data);
1644
0
}
1645
1646
static void
1647
window_customize_free(struct window_mode_entry *wme)
1648
0
{
1649
0
  struct window_customize_modedata *data = wme->data;
1650
1651
0
  if (data == NULL)
1652
0
    return;
1653
1654
0
  data->dead = 1;
1655
0
  if (data->editor != NULL) {
1656
0
    spawn_cancel_editor(data->editor);
1657
0
    window_customize_finish_edit(data->edit);
1658
0
  }
1659
0
  mode_tree_free(data->data);
1660
0
  window_customize_destroy(data);
1661
0
}
1662
1663
static void
1664
window_customize_resize(struct window_mode_entry *wme, u_int sx, u_int sy)
1665
0
{
1666
0
  struct window_customize_modedata  *data = wme->data;
1667
1668
0
  mode_tree_resize(data->data, sx, sy);
1669
0
}
1670
1671
static void
1672
window_customize_update(struct window_mode_entry *wme)
1673
0
{
1674
0
  struct window_customize_modedata  *data = wme->data;
1675
1676
0
  window_customize_draw_waiting(data);
1677
0
}
1678
1679
static void
1680
window_customize_free_callback(void *modedata)
1681
0
{
1682
0
  window_customize_destroy(modedata);
1683
0
}
1684
1685
static void
1686
window_customize_free_item_callback(void *itemdata)
1687
0
{
1688
0
  struct window_customize_itemdata  *item = itemdata;
1689
0
  struct window_customize_modedata  *data = item->data;
1690
1691
0
  window_customize_free_item(item);
1692
0
  window_customize_destroy(data);
1693
0
}
1694
1695
static enum prompt_result
1696
window_customize_set_option_callback(struct client *c, void *itemdata,
1697
    const char *s, __unused enum prompt_key_result key)
1698
0
{
1699
0
  struct window_customize_itemdata  *item = itemdata;
1700
0
  struct window_customize_modedata  *data = item->data;
1701
0
  struct options_entry      *o;
1702
0
  const struct options_table_entry  *oe;
1703
0
  struct options        *oo = item->oo;
1704
0
  const char        *name = item->name;
1705
0
  const char        *array_key = item->array_key;
1706
0
  char          *cause;
1707
0
  u_int          idx;
1708
0
  char           keybuf[32];
1709
1710
0
  if (s == NULL || *s == '\0' || data->dead)
1711
0
    return (PROMPT_CLOSE);
1712
0
  if (item == NULL || !window_customize_check_item(data, item, NULL))
1713
0
    return (PROMPT_CLOSE);
1714
0
  o = options_get(oo, name);
1715
0
  if (o == NULL)
1716
0
    return (PROMPT_CLOSE);
1717
0
  oe = options_table_entry(o);
1718
1719
0
  if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_ARRAY)) {
1720
0
    if (array_key == NULL) {
1721
0
      for (idx = 0; idx < INT_MAX; idx++) {
1722
0
        if (options_array_getv(o, "%u", idx) == NULL)
1723
0
          break;
1724
0
      }
1725
0
      xsnprintf(keybuf, sizeof keybuf, "%u", idx);
1726
0
      array_key = keybuf;
1727
0
    }
1728
0
    if (options_array_set(o, array_key, s, 0, &cause) != 0)
1729
0
      goto fail;
1730
0
  } else {
1731
0
    if (options_from_string(oo, oe, name, s, 0, &cause) != 0)
1732
0
      goto fail;
1733
0
  }
1734
0
  if (item->option_type == WINDOW_CUSTOMIZE_HOOKS && *name == '@')
1735
0
    hooks_add_event(name);
1736
1737
0
  options_push_changes(item->name);
1738
0
  mode_tree_build(data->data);
1739
0
  mode_tree_draw(data->data);
1740
0
  data->wp->flags |= PANE_REDRAW;
1741
1742
0
  return (PROMPT_CLOSE);
1743
1744
0
fail:
1745
0
  *cause = toupper((u_char)*cause);
1746
0
  status_message_set(c, -1, 1, 0, 0, "%s", cause);
1747
0
  free(cause);
1748
0
  return (PROMPT_CLOSE);
1749
0
}
1750
1751
static enum prompt_result
1752
window_customize_set_environment_callback(__unused struct client *c,
1753
    void *itemdata, const char *s, __unused enum prompt_key_result key)
1754
0
{
1755
0
  struct window_customize_itemdata  *item = itemdata;
1756
0
  struct window_customize_modedata  *data = item->data;
1757
0
  struct environ_entry    *envent;
1758
0
  int        flags;
1759
1760
0
  if (s == NULL || data->dead)
1761
0
    return (PROMPT_CLOSE);
1762
0
  if (item == NULL || !window_customize_check_item(data, item, NULL))
1763
0
    return (PROMPT_CLOSE);
1764
1765
0
  flags = item->environ_flags;
1766
0
  envent = environ_find(item->environ, item->name);
1767
0
  if (envent != NULL)
1768
0
    flags = envent->flags;
1769
0
  environ_set(item->environ, item->name, flags, "%s", s);
1770
1771
0
  mode_tree_build(data->data);
1772
0
  mode_tree_draw(data->data);
1773
0
  data->wp->flags |= PANE_REDRAW;
1774
1775
0
  return (PROMPT_CLOSE);
1776
0
}
1777
1778
static void
1779
window_customize_set_environment(struct client *c,
1780
    struct window_customize_modedata *data,
1781
    struct window_customize_itemdata *item, int global)
1782
0
{
1783
0
  struct window_customize_itemdata  *new_item;
1784
0
  struct environ_entry    *envent;
1785
0
  struct environ      *env;
1786
0
  enum window_customize_scope  scope;
1787
0
  struct cmd_find_state    fs;
1788
0
  const char      *space = "";
1789
0
  char        *prompt, *text;
1790
1791
0
  if (item == NULL || !window_customize_check_item(data, item, &fs))
1792
0
    return;
1793
0
  envent = environ_find(item->environ, item->name);
1794
0
  if (envent == NULL)
1795
0
    return;
1796
1797
0
  if (global) {
1798
0
    scope = WINDOW_CUSTOMIZE_GLOBAL_ENVIRONMENT;
1799
0
    env = global_environ;
1800
0
  } else {
1801
0
    scope = item->scope;
1802
0
    env = item->environ;
1803
0
  }
1804
1805
0
  text = window_customize_scope_text(scope, &fs);
1806
0
  if (*text != '\0')
1807
0
    space = ", for ";
1808
0
  else if (scope == WINDOW_CUSTOMIZE_GLOBAL_ENVIRONMENT)
1809
0
    space = ", global";
1810
0
  xasprintf(&prompt, "(%s%s%s) ", item->name, space, text);
1811
0
  free(text);
1812
1813
0
  new_item = xcalloc(1, sizeof *new_item);
1814
0
  new_item->data = data;
1815
0
  new_item->type = WINDOW_CUSTOMIZE_ITEM_ENVIRONMENT;
1816
0
  new_item->scope = scope;
1817
0
  new_item->environ = env;
1818
0
  new_item->environ_flags = envent->flags;
1819
0
  new_item->name = xstrdup(item->name);
1820
1821
0
  data->references++;
1822
0
  mode_tree_set_prompt(data->data, c, prompt,
1823
0
      envent->value == NULL ? "" : envent->value, PROMPT_TYPE_COMMAND,
1824
0
      PROMPT_NOFORMAT, window_customize_set_environment_callback,
1825
0
      window_customize_free_item_callback, new_item);
1826
1827
0
  free(prompt);
1828
0
}
1829
1830
static enum prompt_result
1831
window_customize_add_option_callback(struct client *c, void *itemdata,
1832
    const char *s, __unused enum prompt_key_result key)
1833
0
{
1834
0
  struct window_customize_itemdata  *item = itemdata;
1835
0
  struct window_customize_modedata  *data = item->data;
1836
0
  char        *copy, *name, *array_key;
1837
0
  const char      *value;
1838
0
  const char      *what;
1839
0
  int        ambiguous;
1840
0
  size_t         namelen;
1841
1842
0
  if (s == NULL || *s == '\0' || data->dead)
1843
0
    return (PROMPT_CLOSE);
1844
0
  if (item == NULL || !window_customize_check_item(data, item, NULL))
1845
0
    return (PROMPT_CLOSE);
1846
1847
0
  namelen = strcspn(s, " \t");
1848
0
  if (namelen == 0 || s[namelen] == '\0') {
1849
0
    status_message_set(c, -1, 1, 0, 0,
1850
0
        "User option must be @name value");
1851
0
    return (PROMPT_CLOSE);
1852
0
  }
1853
1854
0
  value = s + namelen;
1855
0
  while (*value == ' ' || *value == '\t')
1856
0
    value++;
1857
0
  if (*value == '\0') {
1858
0
    status_message_set(c, -1, 1, 0, 0,
1859
0
        "User option must be @name value");
1860
0
    return (PROMPT_CLOSE);
1861
0
  }
1862
1863
0
  copy = xstrndup(s, namelen);
1864
0
  name = options_match(copy, &array_key, &ambiguous);
1865
0
  free(copy);
1866
0
  if (name == NULL || *name != '@' || array_key != NULL) {
1867
0
    what = (item->option_type == WINDOW_CUSTOMIZE_HOOKS) ?
1868
0
        "hook" : "option";
1869
0
    status_message_set(c, -1, 1, 0, 0,
1870
0
        "User %s name must start with @", what);
1871
0
    free(name);
1872
0
    free(array_key);
1873
0
    return (PROMPT_CLOSE);
1874
0
  }
1875
1876
0
  options_set_string(item->oo, name, 0, "%s", value);
1877
0
  if (item->option_type == WINDOW_CUSTOMIZE_HOOKS)
1878
0
    hooks_add_event(name);
1879
0
  options_push_changes(name);
1880
1881
0
  mode_tree_build(data->data);
1882
0
  mode_tree_draw(data->data);
1883
0
  data->wp->flags |= PANE_REDRAW;
1884
1885
0
  free(name);
1886
0
  free(array_key);
1887
0
  return (PROMPT_CLOSE);
1888
0
}
1889
1890
static void
1891
window_customize_add_option(struct client *c,
1892
    struct window_customize_modedata *data, enum window_customize_scope scope,
1893
    struct options *oo, enum window_customize_option_type type)
1894
0
{
1895
0
  struct window_customize_itemdata  *new_item;
1896
0
  char        *prompt;
1897
0
  const char      *what;
1898
1899
0
  what = (type == WINDOW_CUSTOMIZE_HOOKS) ? "hook" : "option";
1900
0
  xasprintf(&prompt, "New user %s: ", what);
1901
1902
0
  new_item = xcalloc(1, sizeof *new_item);
1903
0
  new_item->data = data;
1904
0
  new_item->type = WINDOW_CUSTOMIZE_ITEM_OPTION;
1905
0
  new_item->option_type = type;
1906
0
  new_item->scope = scope;
1907
0
  new_item->oo = oo;
1908
1909
0
  data->references++;
1910
0
  mode_tree_set_prompt(data->data, c, prompt, "@", PROMPT_TYPE_COMMAND,
1911
0
      PROMPT_NOFORMAT, window_customize_add_option_callback,
1912
0
      window_customize_free_item_callback, new_item);
1913
1914
0
  free(prompt);
1915
0
}
1916
1917
static enum prompt_result
1918
window_customize_add_environment_callback(struct client *c, void *itemdata,
1919
    const char *s, __unused enum prompt_key_result key)
1920
0
{
1921
0
  struct window_customize_itemdata  *item = itemdata;
1922
0
  struct window_customize_modedata  *data = item->data;
1923
0
  char        *name;
1924
0
  const char      *value;
1925
1926
0
  if (s == NULL || *s == '\0' || data->dead)
1927
0
    return (PROMPT_CLOSE);
1928
0
  if (item == NULL || !window_customize_check_item(data, item, NULL))
1929
0
    return (PROMPT_CLOSE);
1930
1931
0
  if (*s == '-') {
1932
0
    if (s[1] == '\0' || strchr(s + 1, '=') != NULL) {
1933
0
      status_message_set(c, -1, 1, 0, 0,
1934
0
          "Bad environment variable: %s", s);
1935
0
      return (PROMPT_CLOSE);
1936
0
    }
1937
0
    environ_clear(item->environ, s + 1);
1938
0
  } else {
1939
0
    value = strchr(s, '=');
1940
0
    if (value == NULL || value == s) {
1941
0
      status_message_set(c, -1, 1, 0, 0,
1942
0
          "Environment variable must be NAME=value");
1943
0
      return (PROMPT_CLOSE);
1944
0
    }
1945
1946
0
    name = xstrdup(s);
1947
0
    name[strcspn(name, "=")] = '\0';
1948
0
    environ_set(item->environ, name, 0, "%s", value + 1);
1949
0
    free(name);
1950
0
  }
1951
1952
0
  mode_tree_build(data->data);
1953
0
  mode_tree_draw(data->data);
1954
0
  data->wp->flags |= PANE_REDRAW;
1955
1956
0
  return (PROMPT_CLOSE);
1957
0
}
1958
1959
static void
1960
window_customize_add_environment(struct client *c,
1961
    struct window_customize_modedata *data, enum window_customize_scope scope,
1962
    struct environ *env)
1963
0
{
1964
0
  struct window_customize_itemdata  *new_item;
1965
1966
0
  new_item = xcalloc(1, sizeof *new_item);
1967
0
  new_item->data = data;
1968
0
  new_item->type = WINDOW_CUSTOMIZE_ITEM_ENVIRONMENT;
1969
0
  new_item->scope = scope;
1970
0
  new_item->environ = env;
1971
1972
0
  data->references++;
1973
0
  mode_tree_set_prompt(data->data, c, "New environment: ", "",
1974
0
      PROMPT_TYPE_COMMAND, PROMPT_NOFORMAT,
1975
0
      window_customize_add_environment_callback,
1976
0
      window_customize_free_item_callback, new_item);
1977
0
}
1978
1979
static void
1980
window_customize_edit_close_cb(char *buf, size_t len, void *arg)
1981
0
{
1982
0
  struct window_customize_editdata    *ed = arg;
1983
0
  struct window_customize_itemdata    *item = ed->item;
1984
0
  struct window_pane      *wp;
1985
0
  struct window_mode_entry    *wme;
1986
0
  struct window_customize_modedata  *data = NULL;
1987
0
  char          *value, *cause = NULL;
1988
1989
0
  wp = window_pane_find_by_id(ed->wp_id);
1990
0
  if (wp != NULL) {
1991
0
    wme = TAILQ_FIRST(&wp->modes);
1992
0
    if (wme != NULL && wme->mode == &window_customize_mode) {
1993
0
      data = wme->data;
1994
0
      if (data->editor == ed->editor) {
1995
0
        data->editor = NULL;
1996
0
        data->edit = NULL;
1997
0
      }
1998
0
    }
1999
0
  }
2000
2001
0
  if (buf == NULL || len == 0 || data == NULL || data->dead) {
2002
0
    free(buf);
2003
0
    window_customize_finish_edit(ed);
2004
0
    return;
2005
0
  }
2006
0
  if (buf[len - 1] == '\n')
2007
0
    len--;
2008
0
  value = xmalloc(len + 1);
2009
0
  memcpy(value, buf, len);
2010
0
  value[len] = '\0';
2011
0
  free(buf);
2012
2013
0
  switch (ed->edit_type) {
2014
0
  case WINDOW_CUSTOMIZE_EDIT_OPTION:
2015
0
    if (window_customize_option_editable(data, item) &&
2016
0
        window_customize_set_option_value(item, value,
2017
0
        &cause) != 0) {
2018
0
      free(cause);
2019
0
      goto out;
2020
0
    }
2021
0
    break;
2022
0
  case WINDOW_CUSTOMIZE_EDIT_KEY_COMMAND:
2023
0
    if (window_customize_set_command_value(item, value,
2024
0
        &cause) != 0) {
2025
0
      free(cause);
2026
0
      goto out;
2027
0
    }
2028
0
    break;
2029
0
  case WINDOW_CUSTOMIZE_EDIT_KEY_NOTE:
2030
0
    if (window_customize_set_note_value(item, value) != 0)
2031
0
      goto out;
2032
0
    break;
2033
0
  case WINDOW_CUSTOMIZE_EDIT_ENVIRONMENT:
2034
0
    if (!window_customize_check_item(data, item, NULL))
2035
0
      goto out;
2036
0
    window_customize_set_environment_value(item, value);
2037
0
    break;
2038
0
  }
2039
2040
0
  mode_tree_build(data->data);
2041
0
  mode_tree_draw(data->data);
2042
0
  wp->flags |= PANE_REDRAW;
2043
2044
0
out:
2045
0
  free(value);
2046
0
  window_customize_finish_edit(ed);
2047
0
}
2048
2049
static void
2050
window_customize_start_edit(struct window_customize_modedata *data,
2051
    struct window_customize_itemdata *item, struct client *c)
2052
0
{
2053
0
  struct window_customize_editdata  *ed;
2054
0
  struct options_entry    *o;
2055
0
  struct environ_entry    *envent;
2056
0
  struct key_binding    *bd;
2057
0
  const char      *name;
2058
0
  const char      *buf;
2059
0
  char        *value;
2060
0
  size_t         len;
2061
0
  enum window_customize_edit_type  edit_type;
2062
2063
0
  if (data->editor != NULL || item == NULL)
2064
0
    return;
2065
2066
0
  if (item->type == WINDOW_CUSTOMIZE_ITEM_OPTION) {
2067
0
    if (!window_customize_option_editable(data, item))
2068
0
      return;
2069
0
    o = options_get(item->oo, item->name);
2070
0
    if (o == NULL)
2071
0
      return;
2072
0
    value = options_to_string(o, item->array_key, 0);
2073
0
    edit_type = WINDOW_CUSTOMIZE_EDIT_OPTION;
2074
0
  } else if (item->type == WINDOW_CUSTOMIZE_ITEM_KEY) {
2075
0
    name = mode_tree_get_current_name(data->data);
2076
0
    if (!window_customize_get_key(item, NULL, &bd))
2077
0
      return;
2078
0
    if (strcmp(name, "Command") == 0) {
2079
0
      value = cmd_list_print(bd->cmdlist, 0);
2080
0
      edit_type = WINDOW_CUSTOMIZE_EDIT_KEY_COMMAND;
2081
0
    } else if (strcmp(name, "Note") == 0) {
2082
0
      if (bd->note == NULL)
2083
0
        value = xstrdup("");
2084
0
      else
2085
0
        value = xstrdup(bd->note);
2086
0
      edit_type = WINDOW_CUSTOMIZE_EDIT_KEY_NOTE;
2087
0
    } else
2088
0
      return;
2089
0
  } else if (item->type == WINDOW_CUSTOMIZE_ITEM_ENVIRONMENT) {
2090
0
    if (!window_customize_check_item(data, item, NULL))
2091
0
      return;
2092
0
    envent = environ_find(item->environ, item->name);
2093
0
    if (envent == NULL || envent->value == NULL)
2094
0
      return;
2095
0
    value = xstrdup(envent->value);
2096
0
    edit_type = WINDOW_CUSTOMIZE_EDIT_ENVIRONMENT;
2097
0
  } else
2098
0
    return;
2099
2100
0
  ed = xcalloc(1, sizeof *ed);
2101
0
  ed->wp_id = data->wp->id;
2102
0
  ed->edit_type = edit_type;
2103
0
  ed->item = window_customize_copy_item(item);
2104
2105
0
  buf = value;
2106
0
  len = strlen(value);
2107
0
  if (len == 0) {
2108
0
    buf = "\n";
2109
0
    len = 1;
2110
0
  }
2111
0
  ed->editor = spawn_editor(c, buf, len, NULL,
2112
0
      window_customize_edit_close_cb, ed);
2113
0
  free(value);
2114
0
  if (ed->editor == NULL)
2115
0
    window_customize_finish_edit(ed);
2116
0
  else {
2117
0
    data->editor = ed->editor;
2118
0
    data->edit = ed;
2119
0
  }
2120
0
}
2121
2122
static void
2123
window_customize_set_option(struct client *c,
2124
    struct window_customize_modedata *data,
2125
    struct window_customize_itemdata *item, int global, int pane)
2126
0
{
2127
0
  struct options_entry      *o;
2128
0
  const struct options_table_entry  *oe;
2129
0
  struct options        *oo;
2130
0
  struct window_customize_itemdata  *new_item;
2131
0
  int          flag;
2132
0
  enum window_customize_scope    scope = WINDOW_CUSTOMIZE_NONE;
2133
0
  u_int          choice;
2134
0
  const char        *name = item->name, *space = "";
2135
0
  const char        *array_key = item->array_key;
2136
0
  char          *prompt, *value, *text;
2137
0
  struct cmd_find_state      fs;
2138
2139
0
  if (item == NULL || !window_customize_check_item(data, item, &fs))
2140
0
    return;
2141
0
  o = options_get(item->oo, name);
2142
0
  if (o == NULL)
2143
0
    return;
2144
2145
0
  oe = options_table_entry(o);
2146
0
  if (oe != NULL && ~oe->scope & OPTIONS_TABLE_PANE)
2147
0
    pane = 0;
2148
0
  if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_ARRAY)) {
2149
0
    scope = item->scope;
2150
0
    oo = item->oo;
2151
0
  } else {
2152
0
    if (global) {
2153
0
      switch (item->scope) {
2154
0
      case WINDOW_CUSTOMIZE_NONE:
2155
0
      case WINDOW_CUSTOMIZE_KEY:
2156
0
      case WINDOW_CUSTOMIZE_SERVER:
2157
0
      case WINDOW_CUSTOMIZE_GLOBAL_SESSION:
2158
0
      case WINDOW_CUSTOMIZE_GLOBAL_WINDOW:
2159
0
      case WINDOW_CUSTOMIZE_GLOBAL_ENVIRONMENT:
2160
0
      case WINDOW_CUSTOMIZE_SESSION_ENVIRONMENT:
2161
0
        scope = item->scope;
2162
0
        break;
2163
0
      case WINDOW_CUSTOMIZE_SESSION:
2164
0
        scope = WINDOW_CUSTOMIZE_GLOBAL_SESSION;
2165
0
        break;
2166
0
      case WINDOW_CUSTOMIZE_WINDOW:
2167
0
      case WINDOW_CUSTOMIZE_PANE:
2168
0
        scope = WINDOW_CUSTOMIZE_GLOBAL_WINDOW;
2169
0
        break;
2170
0
      }
2171
0
    } else {
2172
0
      switch (item->scope) {
2173
0
      case WINDOW_CUSTOMIZE_NONE:
2174
0
      case WINDOW_CUSTOMIZE_KEY:
2175
0
      case WINDOW_CUSTOMIZE_SERVER:
2176
0
      case WINDOW_CUSTOMIZE_SESSION:
2177
0
        scope = item->scope;
2178
0
        break;
2179
0
      case WINDOW_CUSTOMIZE_WINDOW:
2180
0
      case WINDOW_CUSTOMIZE_PANE:
2181
0
        if (pane)
2182
0
          scope = WINDOW_CUSTOMIZE_PANE;
2183
0
        else
2184
0
          scope = WINDOW_CUSTOMIZE_WINDOW;
2185
0
        break;
2186
0
      case WINDOW_CUSTOMIZE_GLOBAL_SESSION:
2187
0
        scope = WINDOW_CUSTOMIZE_SESSION;
2188
0
        break;
2189
0
      case WINDOW_CUSTOMIZE_GLOBAL_WINDOW:
2190
0
        if (pane)
2191
0
          scope = WINDOW_CUSTOMIZE_PANE;
2192
0
        else
2193
0
          scope = WINDOW_CUSTOMIZE_WINDOW;
2194
0
        break;
2195
0
      case WINDOW_CUSTOMIZE_GLOBAL_ENVIRONMENT:
2196
0
      case WINDOW_CUSTOMIZE_SESSION_ENVIRONMENT:
2197
0
        scope = item->scope;
2198
0
        break;
2199
0
      }
2200
0
    }
2201
0
    if (scope == item->scope)
2202
0
      oo = item->oo;
2203
0
    else
2204
0
      oo = window_customize_get_tree(scope, &fs);
2205
0
  }
2206
2207
0
  if (oe != NULL && oe->type == OPTIONS_TABLE_FLAG) {
2208
0
    flag = options_get_number(oo, name);
2209
0
    options_set_number(oo, name, !flag);
2210
0
  } else if (oe != NULL && oe->type == OPTIONS_TABLE_CHOICE) {
2211
0
    choice = options_get_number(oo, name);
2212
0
    if (oe->choices[choice + 1] == NULL)
2213
0
      choice = 0;
2214
0
    else
2215
0
      choice++;
2216
0
    options_set_number(oo, name, choice);
2217
0
  } else {
2218
0
    text = window_customize_scope_text(scope, &fs);
2219
0
    if (*text != '\0')
2220
0
      space = ", for ";
2221
0
    else if (scope != WINDOW_CUSTOMIZE_SERVER)
2222
0
      space = ", global";
2223
0
    if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_ARRAY)) {
2224
0
      if (array_key == NULL) {
2225
0
        xasprintf(&prompt, "(%s[+]%s%s) ", name, space,
2226
0
            text);
2227
0
      } else {
2228
0
        xasprintf(&prompt, "(%s[%s]%s%s) ", name,
2229
0
            array_key, space, text);
2230
0
      }
2231
0
    } else
2232
0
      xasprintf(&prompt, "(%s%s%s) ", name, space, text);
2233
0
    free(text);
2234
2235
0
    value = options_to_string(o, array_key, 0);
2236
2237
0
    new_item = xcalloc(1, sizeof *new_item);
2238
0
    new_item->data = data;
2239
0
    new_item->type = WINDOW_CUSTOMIZE_ITEM_OPTION;
2240
0
    new_item->option_type = item->option_type;
2241
0
    new_item->scope = scope;
2242
0
    new_item->oo = oo;
2243
0
    new_item->name = xstrdup(name);
2244
0
    if (array_key != NULL)
2245
0
      new_item->array_key = xstrdup(array_key);
2246
2247
0
    data->references++;
2248
0
    mode_tree_set_prompt(data->data, c, prompt, value,
2249
0
        PROMPT_TYPE_COMMAND, PROMPT_NOFORMAT,
2250
0
        window_customize_set_option_callback,
2251
0
        window_customize_free_item_callback, new_item);
2252
2253
0
    free(prompt);
2254
0
    free(value);
2255
0
  }
2256
0
}
2257
2258
static enum prompt_result
2259
window_customize_set_array_key_callback(struct client *c, void *itemdata,
2260
    const char *s, __unused enum prompt_key_result key)
2261
0
{
2262
0
  struct window_customize_itemdata  *item = itemdata;
2263
0
  struct window_customize_modedata  *data;
2264
0
  struct options_entry      *o;
2265
0
  const char        *name, *array_key;
2266
0
  char          *value, *cause;
2267
2268
0
  if (item == NULL)
2269
0
    return (PROMPT_CLOSE);
2270
0
  data = item->data;
2271
0
  if (s == NULL || *s == '\0' || data->dead)
2272
0
    return (PROMPT_CLOSE);
2273
0
  name = item->name;
2274
0
  array_key = item->array_key;
2275
0
  if (array_key == NULL || !window_customize_check_item(data, item, NULL))
2276
0
    return (PROMPT_CLOSE);
2277
2278
0
  o = options_get(item->oo, name);
2279
0
  if (o == NULL)
2280
0
    return (PROMPT_CLOSE);
2281
0
  if (options_array_get(o, s) != NULL)
2282
0
    return (PROMPT_CLOSE);
2283
2284
0
  value = options_to_string(o, array_key, 0);
2285
0
  if (options_array_set(o, s, value, 0, &cause) != 0)
2286
0
    goto fail;
2287
0
  free(value);
2288
2289
0
  options_array_set(o, array_key, NULL, 0, NULL);
2290
0
  options_push_changes(item->name);
2291
0
  mode_tree_build(data->data);
2292
0
  mode_tree_draw(data->data);
2293
0
  data->wp->flags |= PANE_REDRAW;
2294
2295
0
  return (PROMPT_CLOSE);
2296
2297
0
fail:
2298
0
  free(value);
2299
0
  *cause = toupper((u_char)*cause);
2300
0
  status_message_set(c, -1, 1, 0, 0, "%s", cause);
2301
0
  free(cause);
2302
0
  return (PROMPT_CLOSE);
2303
0
}
2304
2305
static void
2306
window_customize_set_array_key(struct client *c,
2307
    struct window_customize_modedata *data,
2308
    struct window_customize_itemdata *item)
2309
0
{
2310
0
  struct window_customize_itemdata  *new_item;
2311
0
  char        *prompt;
2312
2313
0
  if (item == NULL ||
2314
0
      item->array_key == NULL ||
2315
0
      !window_customize_check_item(data, item, NULL))
2316
0
    return;
2317
2318
0
  xasprintf(&prompt, "(%s[%s]) ", item->name, item->array_key);
2319
2320
0
  new_item = xcalloc(1, sizeof *new_item);
2321
0
  new_item->data = data;
2322
0
  new_item->type = WINDOW_CUSTOMIZE_ITEM_OPTION;
2323
0
  new_item->option_type = item->option_type;
2324
0
  new_item->scope = item->scope;
2325
0
  new_item->oo = item->oo;
2326
0
  new_item->name = xstrdup(item->name);
2327
0
  new_item->array_key = xstrdup(item->array_key);
2328
2329
0
  data->references++;
2330
0
  mode_tree_set_prompt(data->data, c, prompt, item->array_key,
2331
0
      PROMPT_TYPE_COMMAND, PROMPT_NOFORMAT,
2332
0
      window_customize_set_array_key_callback,
2333
0
      window_customize_free_item_callback, new_item);
2334
2335
0
  free(prompt);
2336
0
}
2337
2338
static void
2339
window_customize_unset_environment(struct window_customize_modedata *data,
2340
    struct window_customize_itemdata *item)
2341
0
{
2342
0
  if (item == NULL || !window_customize_check_item(data, item, NULL))
2343
0
    return;
2344
0
  if (environ_find(item->environ, item->name) == NULL)
2345
0
    return;
2346
0
  if (item == mode_tree_get_current(data->data))
2347
0
    mode_tree_up(data->data, 0);
2348
0
  environ_unset(item->environ, item->name);
2349
0
}
2350
2351
static void
2352
window_customize_unset_option(struct window_customize_modedata *data,
2353
    struct window_customize_itemdata *item)
2354
0
{
2355
0
  struct options_entry  *o;
2356
2357
0
  if (item == NULL || !window_customize_check_item(data, item, NULL))
2358
0
    return;
2359
2360
0
  o = options_get(item->oo, item->name);
2361
0
  if (o == NULL)
2362
0
    return;
2363
0
  if (item->array_key != NULL &&
2364
0
      item == mode_tree_get_current(data->data))
2365
0
    mode_tree_up(data->data, 0);
2366
0
  options_remove_or_default(o, item->array_key, NULL);
2367
0
}
2368
2369
static void
2370
window_customize_reset_option(struct window_customize_modedata *data,
2371
    struct window_customize_itemdata *item)
2372
0
{
2373
0
  struct options    *oo;
2374
0
  struct options_entry  *o;
2375
2376
0
  if (item == NULL || !window_customize_check_item(data, item, NULL))
2377
0
    return;
2378
0
  if (item->array_key != NULL)
2379
0
    return;
2380
2381
0
  oo = item->oo;
2382
0
  while (oo != NULL) {
2383
0
    o = options_get_only(oo, item->name);
2384
0
    if (o != NULL)
2385
0
      options_remove_or_default(o, NULL, NULL);
2386
0
    oo = options_get_parent(oo);
2387
0
  }
2388
0
}
2389
2390
static enum prompt_result
2391
window_customize_set_command_callback(struct client *c, void *itemdata,
2392
    const char *s, __unused enum prompt_key_result key)
2393
0
{
2394
0
  struct window_customize_itemdata  *item = itemdata;
2395
0
  struct window_customize_modedata  *data = item->data;
2396
0
  struct key_binding      *bd;
2397
0
  struct cmd_parse_result     *pr;
2398
0
  char          *error;
2399
2400
0
  if (s == NULL || *s == '\0' || data->dead)
2401
0
    return (PROMPT_CLOSE);
2402
0
  if (item == NULL || !window_customize_get_key(item, NULL, &bd))
2403
0
    return (PROMPT_CLOSE);
2404
2405
0
  pr = cmd_parse_from_string(s, NULL);
2406
0
  switch (pr->status) {
2407
0
  case CMD_PARSE_ERROR:
2408
0
    error = pr->error;
2409
0
    goto fail;
2410
0
  case CMD_PARSE_SUCCESS:
2411
0
    break;
2412
0
  }
2413
0
  cmd_list_free(bd->cmdlist);
2414
0
  bd->cmdlist = pr->cmdlist;
2415
2416
0
  mode_tree_build(data->data);
2417
0
  mode_tree_draw(data->data);
2418
0
  data->wp->flags |= PANE_REDRAW;
2419
2420
0
  return (PROMPT_CLOSE);
2421
2422
0
fail:
2423
0
  *error = toupper((u_char)*error);
2424
0
  status_message_set(c, -1, 1, 0, 0, "%s", error);
2425
0
  free(error);
2426
0
  return (PROMPT_CLOSE);
2427
0
}
2428
2429
static enum prompt_result
2430
window_customize_set_note_callback(__unused struct client *c, void *itemdata,
2431
    const char *s, __unused enum prompt_key_result key)
2432
0
{
2433
0
  struct window_customize_itemdata  *item = itemdata;
2434
0
  struct window_customize_modedata  *data = item->data;
2435
0
  struct key_binding      *bd;
2436
2437
0
  if (s == NULL || *s == '\0' || data->dead)
2438
0
    return (PROMPT_CLOSE);
2439
0
  if (item == NULL || !window_customize_get_key(item, NULL, &bd))
2440
0
    return (PROMPT_CLOSE);
2441
2442
0
  free((void *)bd->note);
2443
0
  bd->note = xstrdup(s);
2444
2445
0
  mode_tree_build(data->data);
2446
0
  mode_tree_draw(data->data);
2447
0
  data->wp->flags |= PANE_REDRAW;
2448
2449
0
  return (PROMPT_CLOSE);
2450
0
}
2451
2452
static void
2453
window_customize_set_key(struct client *c,
2454
    struct window_customize_modedata *data,
2455
    struct window_customize_itemdata *item)
2456
0
{
2457
0
  key_code         key = item->key;
2458
0
  struct key_binding      *bd;
2459
0
  const char        *s;
2460
0
  char          *prompt, *value;
2461
0
  struct window_customize_itemdata  *new_item;
2462
2463
0
  if (item == NULL || !window_customize_get_key(item, NULL, &bd))
2464
0
    return;
2465
2466
0
  s = mode_tree_get_current_name(data->data);
2467
0
  if (strcmp(s, "Repeat") == 0)
2468
0
    bd->flags ^= KEY_BINDING_REPEAT;
2469
0
  else if (strcmp(s, "Command") == 0) {
2470
0
    xasprintf(&prompt, "(%s) ", key_string_lookup_key(key, 0));
2471
0
    value = cmd_list_print(bd->cmdlist, 0);
2472
2473
0
    new_item = xcalloc(1, sizeof *new_item);
2474
0
    new_item->data = data;
2475
0
    new_item->type = WINDOW_CUSTOMIZE_ITEM_KEY;
2476
0
    new_item->scope = item->scope;
2477
0
    new_item->table = xstrdup(item->table);
2478
0
    new_item->key = key;
2479
2480
0
    data->references++;
2481
0
    mode_tree_set_prompt(data->data, c, prompt, value,
2482
0
        PROMPT_TYPE_COMMAND, PROMPT_NOFORMAT,
2483
0
        window_customize_set_command_callback,
2484
0
        window_customize_free_item_callback, new_item);
2485
0
    free(prompt);
2486
0
    free(value);
2487
0
  } else if (strcmp(s, "Note") == 0) {
2488
0
    xasprintf(&prompt, "(%s) ", key_string_lookup_key(key, 0));
2489
2490
0
    new_item = xcalloc(1, sizeof *new_item);
2491
0
    new_item->data = data;
2492
0
    new_item->type = WINDOW_CUSTOMIZE_ITEM_KEY;
2493
0
    new_item->scope = item->scope;
2494
0
    new_item->table = xstrdup(item->table);
2495
0
    new_item->key = key;
2496
2497
0
    data->references++;
2498
0
    mode_tree_set_prompt(data->data, c, prompt,
2499
0
        (bd->note == NULL ? "" : bd->note),
2500
0
        PROMPT_TYPE_COMMAND, PROMPT_NOFORMAT,
2501
0
        window_customize_set_note_callback,
2502
0
        window_customize_free_item_callback, new_item);
2503
0
    free(prompt);
2504
0
  }
2505
0
}
2506
2507
static enum prompt_result
2508
window_customize_add_key_callback(struct client *c, void *itemdata,
2509
    const char *s, __unused enum prompt_key_result key0)
2510
0
{
2511
0
  struct window_customize_itemdata  *item = itemdata;
2512
0
  struct window_customize_modedata  *data = item->data;
2513
0
  key_code       key;
2514
0
  struct cmd_parse_result   *pr;
2515
0
  const char      *command;
2516
0
  char        *error, *keystr;
2517
0
  size_t         keylen;
2518
2519
0
  if (s == NULL || *s == '\0' || data->dead)
2520
0
    return (PROMPT_CLOSE);
2521
2522
0
  keylen = strcspn(s, " \t");
2523
0
  if (keylen == 0 || s[keylen] == '\0') {
2524
0
    status_message_set(c, -1, 1, 0, 0,
2525
0
        "Key binding must be key command");
2526
0
    return (PROMPT_CLOSE);
2527
0
  }
2528
2529
0
  command = s + keylen;
2530
0
  while (*command == ' ' || *command == '\t')
2531
0
    command++;
2532
0
  if (*command == '\0') {
2533
0
    status_message_set(c, -1, 1, 0, 0,
2534
0
        "Key binding must be key command");
2535
0
    return (PROMPT_CLOSE);
2536
0
  }
2537
2538
0
  keystr = xstrndup(s, keylen);
2539
0
  key = key_string_lookup_string(keystr);
2540
0
  if (key == KEYC_NONE || key == KEYC_UNKNOWN) {
2541
0
    status_message_set(c, -1, 1, 0, 0, "Unknown key: %s", keystr);
2542
0
    free(keystr);
2543
0
    return (PROMPT_CLOSE);
2544
0
  }
2545
0
  free(keystr);
2546
2547
0
  pr = cmd_parse_from_string(command, NULL);
2548
0
  switch (pr->status) {
2549
0
  case CMD_PARSE_ERROR:
2550
0
    error = pr->error;
2551
0
    goto fail;
2552
0
  case CMD_PARSE_SUCCESS:
2553
0
    break;
2554
0
  }
2555
0
  key_bindings_add(item->table, key, NULL, 0, pr->cmdlist);
2556
2557
0
  mode_tree_build(data->data);
2558
0
  mode_tree_draw(data->data);
2559
0
  data->wp->flags |= PANE_REDRAW;
2560
2561
0
  return (PROMPT_CLOSE);
2562
2563
0
fail:
2564
0
  *error = toupper((u_char)*error);
2565
0
  status_message_set(c, -1, 1, 0, 0, "%s", error);
2566
0
  free(error);
2567
0
  return (PROMPT_CLOSE);
2568
0
}
2569
2570
static void
2571
window_customize_add_key(struct client *c,
2572
    struct window_customize_modedata *data, const char *table)
2573
0
{
2574
0
  struct window_customize_itemdata  *new_item;
2575
0
  char        *prompt;
2576
2577
0
  xasprintf(&prompt, "New key in %s: ", table);
2578
2579
0
  new_item = xcalloc(1, sizeof *new_item);
2580
0
  new_item->data = data;
2581
0
  new_item->type = WINDOW_CUSTOMIZE_ITEM_KEY;
2582
0
  new_item->scope = WINDOW_CUSTOMIZE_KEY;
2583
0
  new_item->table = xstrdup(table);
2584
2585
0
  data->references++;
2586
0
  mode_tree_set_prompt(data->data, c, prompt, "", PROMPT_TYPE_COMMAND,
2587
0
      PROMPT_NOFORMAT, window_customize_add_key_callback,
2588
0
      window_customize_free_item_callback, new_item);
2589
2590
0
  free(prompt);
2591
0
}
2592
2593
static void
2594
window_customize_unset_key(struct window_customize_modedata *data,
2595
    struct window_customize_itemdata *item)
2596
0
{
2597
0
  struct key_table  *kt;
2598
0
  struct key_binding  *bd;
2599
2600
0
  if (item == NULL || !window_customize_get_key(item, &kt, &bd))
2601
0
    return;
2602
2603
0
  if (item == mode_tree_get_current(data->data))
2604
0
    mode_tree_up(data->data, 0);
2605
0
  key_bindings_remove(kt->name, bd->key);
2606
0
}
2607
2608
static void
2609
window_customize_reset_key(struct window_customize_modedata *data,
2610
    struct window_customize_itemdata *item)
2611
0
{
2612
0
  struct key_table  *kt;
2613
0
  struct key_binding  *dd, *bd;
2614
2615
0
  if (item == NULL || !window_customize_get_key(item, &kt, &bd))
2616
0
    return;
2617
2618
0
  dd = key_bindings_get_default(kt, bd->key);
2619
0
  if (dd != NULL && bd->cmdlist == dd->cmdlist)
2620
0
    return;
2621
0
  if (dd == NULL && item == mode_tree_get_current(data->data))
2622
0
    mode_tree_up(data->data, 0);
2623
0
  key_bindings_reset(kt->name, bd->key);
2624
0
}
2625
2626
static void
2627
window_customize_change_each(void *modedata, void *itemdata,
2628
    __unused struct client *c, __unused key_code key)
2629
0
{
2630
0
  struct window_customize_modedata  *data = modedata;
2631
0
  struct window_customize_itemdata  *item = itemdata;
2632
0
  enum window_customize_item_type  type = item->type;
2633
0
  char        *name = NULL;
2634
2635
0
  if (type == WINDOW_CUSTOMIZE_ITEM_OPTION)
2636
0
    name = xstrdup(item->name);
2637
0
  switch (data->change) {
2638
0
  case WINDOW_CUSTOMIZE_UNSET:
2639
0
    if (type == WINDOW_CUSTOMIZE_ITEM_KEY)
2640
0
      window_customize_unset_key(data, item);
2641
0
    else if (type == WINDOW_CUSTOMIZE_ITEM_ENVIRONMENT)
2642
0
      window_customize_unset_environment(data, item);
2643
0
    else
2644
0
      window_customize_unset_option(data, item);
2645
0
    break;
2646
0
  case WINDOW_CUSTOMIZE_RESET:
2647
0
    if (type == WINDOW_CUSTOMIZE_ITEM_KEY)
2648
0
      window_customize_reset_key(data, item);
2649
0
    else if (type == WINDOW_CUSTOMIZE_ITEM_OPTION)
2650
0
      window_customize_reset_option(data, item);
2651
0
    break;
2652
0
  }
2653
0
  if (type == WINDOW_CUSTOMIZE_ITEM_OPTION)
2654
0
    options_push_changes(name);
2655
0
  free(name);
2656
0
}
2657
2658
static enum prompt_result
2659
window_customize_change_current_callback(__unused struct client *c,
2660
    void *modedata, const char *s, __unused enum prompt_key_result key)
2661
0
{
2662
0
  struct window_customize_modedata  *data = modedata;
2663
0
  struct window_customize_itemdata  *item;
2664
0
  enum window_customize_item_type  type;
2665
0
  char        *name = NULL;
2666
2667
0
  if (s == NULL || *s == '\0' || data->dead)
2668
0
    return (PROMPT_CLOSE);
2669
0
  if (tolower((u_char) s[0]) != 'y' || s[1] != '\0')
2670
0
    return (PROMPT_CLOSE);
2671
2672
0
  item = mode_tree_get_current(data->data);
2673
0
  if (item == NULL)
2674
0
    return (PROMPT_CLOSE);
2675
0
  type = item->type;
2676
0
  if (type == WINDOW_CUSTOMIZE_ITEM_OPTION)
2677
0
    name = xstrdup(item->name);
2678
0
  switch (data->change) {
2679
0
  case WINDOW_CUSTOMIZE_UNSET:
2680
0
    if (type == WINDOW_CUSTOMIZE_ITEM_KEY)
2681
0
      window_customize_unset_key(data, item);
2682
0
    else if (type == WINDOW_CUSTOMIZE_ITEM_ENVIRONMENT)
2683
0
      window_customize_unset_environment(data, item);
2684
0
    else
2685
0
      window_customize_unset_option(data, item);
2686
0
    break;
2687
0
  case WINDOW_CUSTOMIZE_RESET:
2688
0
    if (type == WINDOW_CUSTOMIZE_ITEM_KEY)
2689
0
      window_customize_reset_key(data, item);
2690
0
    else if (type == WINDOW_CUSTOMIZE_ITEM_OPTION)
2691
0
      window_customize_reset_option(data, item);
2692
0
    break;
2693
0
  }
2694
0
  if (type == WINDOW_CUSTOMIZE_ITEM_OPTION)
2695
0
    options_push_changes(name);
2696
0
  free(name);
2697
0
  mode_tree_build(data->data);
2698
0
  mode_tree_draw(data->data);
2699
0
  data->wp->flags |= PANE_REDRAW;
2700
2701
0
  return (PROMPT_CLOSE);
2702
0
}
2703
2704
static enum prompt_result
2705
window_customize_change_tagged_callback(struct client *c, void *modedata,
2706
    const char *s, __unused enum prompt_key_result key)
2707
0
{
2708
0
  struct window_customize_modedata  *data = modedata;
2709
2710
0
  if (s == NULL || *s == '\0' || data->dead)
2711
0
    return (PROMPT_CLOSE);
2712
0
  if (tolower((u_char) s[0]) != 'y' || s[1] != '\0')
2713
0
    return (PROMPT_CLOSE);
2714
2715
0
  mode_tree_each_tagged(data->data, window_customize_change_each, c,
2716
0
      KEYC_NONE, 0);
2717
0
  mode_tree_build(data->data);
2718
0
  mode_tree_draw(data->data);
2719
0
  data->wp->flags |= PANE_REDRAW;
2720
2721
0
  return (PROMPT_CLOSE);
2722
0
}
2723
2724
static int
2725
window_customize_add_current(struct client *c,
2726
    struct window_customize_modedata *data)
2727
0
{
2728
0
  struct cmd_find_state  fs;
2729
0
  const char    *name, *table;
2730
2731
0
  name = mode_tree_get_current_name(data->data);
2732
0
  if (cmd_find_valid_state(&data->fs))
2733
0
    cmd_find_copy_state(&fs, &data->fs);
2734
0
  else
2735
0
    cmd_find_from_pane(&fs, data->wp, 0);
2736
2737
0
  if (strcmp(name, "Server Options") == 0) {
2738
0
    window_customize_add_option(c, data, WINDOW_CUSTOMIZE_SERVER,
2739
0
        global_options, WINDOW_CUSTOMIZE_OPTIONS);
2740
0
    return (1);
2741
0
  }
2742
0
  if (strcmp(name, "Session Options") == 0) {
2743
0
    window_customize_add_option(c, data, WINDOW_CUSTOMIZE_SESSION,
2744
0
        fs.s->options, WINDOW_CUSTOMIZE_OPTIONS);
2745
0
    return (1);
2746
0
  }
2747
0
  if (strcmp(name, "Window & Pane Options") == 0) {
2748
0
    window_customize_add_option(c, data, WINDOW_CUSTOMIZE_PANE,
2749
0
        fs.wp->options, WINDOW_CUSTOMIZE_OPTIONS);
2750
0
    return (1);
2751
0
  }
2752
0
  if (strcmp(name, "Session Hooks") == 0) {
2753
0
    window_customize_add_option(c, data, WINDOW_CUSTOMIZE_SESSION,
2754
0
        fs.s->options, WINDOW_CUSTOMIZE_HOOKS);
2755
0
    return (1);
2756
0
  }
2757
0
  if (strcmp(name, "Window & Pane Hooks") == 0) {
2758
0
    window_customize_add_option(c, data, WINDOW_CUSTOMIZE_PANE,
2759
0
        fs.wp->options, WINDOW_CUSTOMIZE_HOOKS);
2760
0
    return (1);
2761
0
  }
2762
0
  if (strcmp(name, "Global Environment") == 0) {
2763
0
    window_customize_add_environment(c, data,
2764
0
        WINDOW_CUSTOMIZE_GLOBAL_ENVIRONMENT, global_environ);
2765
0
    return (1);
2766
0
  }
2767
0
  if (strcmp(name, "Session Environment") == 0) {
2768
0
    window_customize_add_environment(c, data,
2769
0
        WINDOW_CUSTOMIZE_SESSION_ENVIRONMENT, fs.s->environ);
2770
0
    return (1);
2771
0
  }
2772
2773
0
  if (strncmp(name, "Key Table - ", 12) == 0) {
2774
0
    table = name + 12;
2775
0
    window_customize_add_key(c, data, table);
2776
0
    return (1);
2777
0
  }
2778
0
  return (0);
2779
0
}
2780
2781
static void
2782
window_customize_key(struct window_mode_entry *wme, struct client *c,
2783
    __unused struct session *s, __unused struct winlink *wl, key_code key,
2784
    struct mouse_event *m)
2785
0
{
2786
0
  struct window_pane      *wp = wme->wp;
2787
0
  struct window_customize_modedata  *data = wme->data;
2788
0
  struct window_customize_itemdata  *item, *new_item;
2789
0
  int          finished;
2790
0
  char          *prompt;
2791
0
  u_int          tagged;
2792
2793
0
  item = mode_tree_get_current(data->data);
2794
0
  if (data->editor != NULL) {
2795
0
    if (key == 'q' || key == '\033' || key == '\003')
2796
0
      finished = 1;
2797
0
    else
2798
0
      finished = 0;
2799
0
    goto out;
2800
0
  }
2801
2802
0
  finished = mode_tree_key(data->data, c, &key, m, NULL, NULL);
2803
0
  if (item != (new_item = mode_tree_get_current(data->data)))
2804
0
    item = new_item;
2805
2806
0
  switch (key) {
2807
0
  case 'e':
2808
0
    window_customize_start_edit(data, item, c);
2809
0
    break;
2810
0
  case 'a':
2811
0
    if (item == NULL || item->type != WINDOW_CUSTOMIZE_ITEM_OPTION)
2812
0
      break;
2813
0
    window_customize_set_array_key(c, data, item);
2814
0
    break;
2815
0
  case '\r':
2816
0
  case 's':
2817
0
    if (item == NULL) {
2818
0
      if (window_customize_add_current(c, data))
2819
0
        mode_tree_build(data->data);
2820
0
      break;
2821
0
    }
2822
0
    if (item->type == WINDOW_CUSTOMIZE_ITEM_KEY)
2823
0
      window_customize_set_key(c, data, item);
2824
0
    else if (item->type == WINDOW_CUSTOMIZE_ITEM_ENVIRONMENT)
2825
0
      window_customize_set_environment(c, data, item, 0);
2826
0
    else {
2827
0
      window_customize_set_option(c, data, item, 0, 1);
2828
0
      options_push_changes(item->name);
2829
0
    }
2830
0
    mode_tree_build(data->data);
2831
0
    break;
2832
0
  case 'w':
2833
0
    if (item == NULL || item->type != WINDOW_CUSTOMIZE_ITEM_OPTION)
2834
0
      break;
2835
0
    window_customize_set_option(c, data, item, 0, 0);
2836
0
    options_push_changes(item->name);
2837
0
    mode_tree_build(data->data);
2838
0
    break;
2839
0
  case 'S':
2840
0
  case 'W':
2841
0
    if (item == NULL || item->type == WINDOW_CUSTOMIZE_ITEM_KEY)
2842
0
      break;
2843
0
    if (item->type == WINDOW_CUSTOMIZE_ITEM_ENVIRONMENT)
2844
0
      window_customize_set_environment(c, data, item, 1);
2845
0
    else {
2846
0
      window_customize_set_option(c, data, item, 1, 0);
2847
0
      options_push_changes(item->name);
2848
0
    }
2849
0
    mode_tree_build(data->data);
2850
0
    break;
2851
0
  case 'd':
2852
0
    if (item == NULL ||
2853
0
        (item->type == WINDOW_CUSTOMIZE_ITEM_OPTION &&
2854
0
        item->array_key != NULL) ||
2855
0
        item->type == WINDOW_CUSTOMIZE_ITEM_ENVIRONMENT)
2856
0
      break;
2857
0
    xasprintf(&prompt, "Reset %s to default? ", item->name);
2858
0
    data->references++;
2859
0
    data->change = WINDOW_CUSTOMIZE_RESET;
2860
0
    mode_tree_set_prompt(data->data, c, prompt, "",
2861
0
        PROMPT_TYPE_COMMAND,
2862
0
        PROMPT_SINGLE|PROMPT_NOFORMAT|data->prompt_flags,
2863
0
        window_customize_change_current_callback,
2864
0
        window_customize_free_callback, data);
2865
0
    free(prompt);
2866
0
    break;
2867
0
  case 'D':
2868
0
    tagged = mode_tree_count_tagged(data->data);
2869
0
    if (tagged == 0)
2870
0
      break;
2871
0
    xasprintf(&prompt, "Reset %u tagged to default? ", tagged);
2872
0
    data->references++;
2873
0
    data->change = WINDOW_CUSTOMIZE_RESET;
2874
0
    mode_tree_set_prompt(data->data, c, prompt, "",
2875
0
        PROMPT_TYPE_COMMAND,
2876
0
        PROMPT_SINGLE|PROMPT_NOFORMAT|data->prompt_flags,
2877
0
        window_customize_change_tagged_callback,
2878
0
        window_customize_free_callback, data);
2879
0
    free(prompt);
2880
0
    break;
2881
0
  case 'u':
2882
0
    if (item == NULL)
2883
0
      break;
2884
0
    if (item->array_key != NULL) {
2885
0
      xasprintf(&prompt, "Unset %s[%s]? ", item->name,
2886
0
          item->array_key);
2887
0
    } else
2888
0
      xasprintf(&prompt, "Unset %s? ", item->name);
2889
0
    data->references++;
2890
0
    data->change = WINDOW_CUSTOMIZE_UNSET;
2891
0
    mode_tree_set_prompt(data->data, c, prompt, "",
2892
0
        PROMPT_TYPE_COMMAND,
2893
0
        PROMPT_SINGLE|PROMPT_NOFORMAT|data->prompt_flags,
2894
0
        window_customize_change_current_callback,
2895
0
        window_customize_free_callback, data);
2896
0
    free(prompt);
2897
0
    break;
2898
0
  case 'U':
2899
0
    tagged = mode_tree_count_tagged(data->data);
2900
0
    if (tagged == 0)
2901
0
      break;
2902
0
    xasprintf(&prompt, "Unset %u tagged? ", tagged);
2903
0
    data->references++;
2904
0
    data->change = WINDOW_CUSTOMIZE_UNSET;
2905
0
    mode_tree_set_prompt(data->data, c, prompt, "",
2906
0
        PROMPT_TYPE_COMMAND,
2907
0
        PROMPT_SINGLE|PROMPT_NOFORMAT|data->prompt_flags,
2908
0
        window_customize_change_tagged_callback,
2909
0
        window_customize_free_callback, data);
2910
0
    free(prompt);
2911
0
    break;
2912
0
  case 'H':
2913
0
    data->hide_global = !data->hide_global;
2914
0
    mode_tree_build(data->data);
2915
0
    break;
2916
0
  case 'C':
2917
0
    data->hide_default = !data->hide_default;
2918
0
    mode_tree_build(data->data);
2919
0
    break;
2920
0
  }
2921
2922
0
out:
2923
0
  if (finished)
2924
0
    window_pane_reset_mode(wp);
2925
0
  else {
2926
0
    mode_tree_draw(data->data);
2927
0
    window_customize_draw_waiting(data);
2928
0
    wp->flags |= PANE_REDRAW;
2929
0
  }
2930
0
}