mirror of
https://github.com/tmux/tmux.git
synced 2026-08-03 14:08:59 +00:00
Resolve merge conflicts.
This commit is contained in:
8
.github/workflows/regress.yml
vendored
8
.github/workflows/regress.yml
vendored
@@ -77,3 +77,11 @@ jobs:
|
||||
cd regress
|
||||
export ASAN_OPTIONS="abort_on_error=1:detect_leaks=0"
|
||||
${{ matrix.make }}
|
||||
|
||||
- name: logs
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: regress-logs-${{ matrix.name }}
|
||||
path: regress/logs/*.log
|
||||
if-no-files-found: ignore
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -21,6 +21,7 @@ configure
|
||||
core
|
||||
etc/
|
||||
fuzz/*-fuzzer
|
||||
regress/logs/
|
||||
tags
|
||||
tmux
|
||||
tmux.1.*
|
||||
|
||||
@@ -51,10 +51,9 @@ cmd_break_pane_float(struct cmdq_item *item, struct args *args,
|
||||
struct window *w, struct window_pane *wp)
|
||||
{
|
||||
struct layout_cell *lc = wp->layout_cell;
|
||||
u_int sx = lc->saved_sx, sy = lc->saved_sy;
|
||||
int ox = lc->saved_xoff, oy = lc->saved_yoff;
|
||||
char *cause = NULL;
|
||||
enum pane_lines lines = window_get_pane_lines(w);
|
||||
struct layout_geometry *fg = &lc->fg;
|
||||
|
||||
if (window_pane_is_floating(wp)) {
|
||||
cmdq_error(item, "pane is already floating");
|
||||
@@ -65,14 +64,13 @@ cmd_break_pane_float(struct cmdq_item *item, struct args *args,
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
if (layout_floating_args_parse(item, args, lines, w, &sx, &sy, &ox, &oy,
|
||||
&cause) != 0) {
|
||||
if (layout_floating_args_parse(item, args, lines, w, fg, &cause) != 0) {
|
||||
cmdq_error(item, "failed to float pane: %s", cause);
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
layout_remove_tile(w, lc);
|
||||
layout_set_size(lc, sx, sy, ox, oy);
|
||||
layout_set_size(lc, fg->sx, fg->sy, fg->xoff, fg->yoff);
|
||||
|
||||
lc->flags |= LAYOUT_CELL_FLOATING;
|
||||
TAILQ_REMOVE(&w->z_index, wp, zentry);
|
||||
|
||||
@@ -126,6 +126,10 @@ cmd_display_menu_get_pos(struct client *tc, struct cmdq_item *item,
|
||||
format_add(ft, "popup_mouse_y", "%u", event->m.y);
|
||||
}
|
||||
|
||||
/* Position of the previous menu, for -x/-y L. */
|
||||
format_add(ft, "popup_last_x", "%u", tc->menu_last_px);
|
||||
format_add(ft, "popup_last_y", "%u", tc->menu_last_py + h);
|
||||
|
||||
/*
|
||||
* If there are any status lines, add this window position and the
|
||||
* status line position.
|
||||
@@ -238,6 +242,8 @@ cmd_display_menu_get_pos(struct client *tc, struct cmdq_item *item,
|
||||
xp = "#{popup_pane_left}";
|
||||
else if (strcmp(xp, "M") == 0)
|
||||
xp = "#{popup_mouse_centre_x}";
|
||||
else if (strcmp(xp, "L") == 0)
|
||||
xp = "#{popup_last_x}";
|
||||
else if (strcmp(xp, "W") == 0)
|
||||
xp = "#{popup_window_status_line_x}";
|
||||
p = format_expand(ft, xp);
|
||||
@@ -258,6 +264,8 @@ cmd_display_menu_get_pos(struct client *tc, struct cmdq_item *item,
|
||||
yp = "#{popup_pane_bottom}";
|
||||
else if (strcmp(yp, "M") == 0)
|
||||
yp = "#{popup_mouse_top}";
|
||||
else if (strcmp(yp, "L") == 0)
|
||||
yp = "#{popup_last_y}";
|
||||
else if (strcmp(yp, "S") == 0)
|
||||
yp = "#{popup_status_line_y}";
|
||||
else if (strcmp(yp, "W") == 0)
|
||||
|
||||
@@ -71,8 +71,9 @@ cmd_join_pane_place(struct cmdq_item *item, struct winlink *wl,
|
||||
struct window *w = wl->window;
|
||||
struct layout_cell *lc = wp->layout_cell;
|
||||
struct window_pane *owp;
|
||||
int wx = w->sx, wy = w->sy, px = lc->sx;
|
||||
int py = lc->sy, xoff = lc->xoff, yoff = lc->yoff;
|
||||
int wx = w->sx, wy = w->sy;
|
||||
int px = lc->g.sx, py = lc->g.sy;
|
||||
int xoff = lc->g.xoff, yoff = lc->g.yoff;
|
||||
int border = 1;
|
||||
|
||||
if (window_pane_get_pane_lines(wp) == PANE_LINES_NONE)
|
||||
@@ -180,9 +181,9 @@ cmd_join_pane_place(struct cmdq_item *item, struct winlink *wl,
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
if (xoff != lc->xoff || yoff != lc->yoff) {
|
||||
lc->xoff = xoff;
|
||||
lc->yoff = yoff;
|
||||
if (xoff != lc->g.xoff || yoff != lc->g.yoff) {
|
||||
lc->g.xoff = xoff;
|
||||
lc->g.yoff = yoff;
|
||||
layout_fix_panes(w, NULL);
|
||||
}
|
||||
notify_window("window-layout-changed", w);
|
||||
@@ -200,7 +201,7 @@ cmd_join_pane_move(struct cmdq_item *item, struct args *args,
|
||||
const char *errstr, *argval;
|
||||
const char flags[] = { 'U', 'D', 'L', 'R' };
|
||||
char *cause = NULL, flag;
|
||||
int xoff = lc->xoff, yoff = lc->yoff, adjust;
|
||||
int xoff = lc->g.xoff, yoff = lc->g.yoff, adjust;
|
||||
u_int i;
|
||||
enum pane_lines lines = window_pane_get_pane_lines(wp);
|
||||
|
||||
@@ -251,9 +252,9 @@ cmd_join_pane_move(struct cmdq_item *item, struct args *args,
|
||||
xoff += adjust;
|
||||
}
|
||||
|
||||
if (xoff != lc->xoff || yoff != lc->yoff) {
|
||||
lc->xoff = xoff;
|
||||
lc->yoff = yoff;
|
||||
if (xoff != lc->g.xoff || yoff != lc->g.yoff) {
|
||||
lc->g.xoff = xoff;
|
||||
lc->g.yoff = yoff;
|
||||
layout_fix_panes(w, NULL);
|
||||
notify_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
@@ -319,8 +320,8 @@ cmd_join_pane_mouse_move(struct client *c, struct mouse_event *m)
|
||||
ly = m->statusat - 1;
|
||||
|
||||
if (x != lx || y != ly) {
|
||||
lc->xoff += x - lx;
|
||||
lc->yoff += y - ly;
|
||||
lc->g.xoff += x - lx;
|
||||
lc->g.yoff += y - ly;
|
||||
layout_fix_panes(w, NULL);
|
||||
server_redraw_window(w);
|
||||
server_redraw_window_borders(w);
|
||||
@@ -378,10 +379,11 @@ cmd_join_pane_tile(struct cmdq_item *item, struct args *args, struct window *w,
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
lc->saved_sx = lc->sx;
|
||||
lc->saved_sy = lc->sy;
|
||||
lc->saved_xoff = lc->xoff;
|
||||
lc->saved_yoff = lc->yoff;
|
||||
lc->fg.sx = lc->g.sx;
|
||||
lc->fg.sy = lc->g.sy;
|
||||
lc->fg.xoff = lc->g.xoff;
|
||||
lc->fg.yoff = lc->g.yoff;
|
||||
|
||||
if (layout_insert_tile(w, lc) != 0) {
|
||||
cmdq_error(item, "no space for a new pane");
|
||||
return (CMD_RETURN_ERROR);
|
||||
|
||||
@@ -270,10 +270,10 @@ cmd_resize_pane_mouse_resize_move_floating(struct client *c,
|
||||
|
||||
if ((lx == left || lx == left + 1) && ly == wp->yoff - 1) {
|
||||
/* Top left corner. */
|
||||
new_sx = lc->sx + (lx - x);
|
||||
new_sx = lc->g.sx + (lx - x);
|
||||
if (new_sx < PANE_MINIMUM)
|
||||
new_sx = PANE_MINIMUM;
|
||||
new_sy = lc->sy + (ly - y);
|
||||
new_sy = lc->g.sy + (ly - y);
|
||||
if (new_sy < PANE_MINIMUM)
|
||||
new_sy = PANE_MINIMUM;
|
||||
new_xoff = x + 1; /* because mouse is on border at xoff - 1 */
|
||||
@@ -283,65 +283,65 @@ cmd_resize_pane_mouse_resize_move_floating(struct client *c,
|
||||
} else if ((lx == right + 1 || lx == right) &&
|
||||
ly == wp->yoff - 1) {
|
||||
/* Top right corner. */
|
||||
new_sx = x - lc->xoff;
|
||||
new_sx = x - lc->g.xoff;
|
||||
if (new_sx < PANE_MINIMUM)
|
||||
new_sx = PANE_MINIMUM;
|
||||
new_sy = lc->sy + (ly - y);
|
||||
new_sy = lc->g.sy + (ly - y);
|
||||
if (new_sy < PANE_MINIMUM)
|
||||
new_sy = PANE_MINIMUM;
|
||||
new_yoff = y + 1;
|
||||
layout_set_size(lc, new_sx, new_sy, lc->xoff, new_yoff);
|
||||
layout_set_size(lc, new_sx, new_sy, lc->g.xoff, new_yoff);
|
||||
resizes++;
|
||||
} else if ((lx == left || lx == left + 1) &&
|
||||
ly == wp->yoff + sy) {
|
||||
/* Bottom left corner. */
|
||||
new_sx = lc->sx + (lx - x);
|
||||
new_sx = lc->g.sx + (lx - x);
|
||||
if (new_sx < PANE_MINIMUM)
|
||||
new_sx = PANE_MINIMUM;
|
||||
new_sy = y - lc->yoff;
|
||||
new_sy = y - lc->g.yoff;
|
||||
if (new_sy < PANE_MINIMUM)
|
||||
return;
|
||||
new_xoff = x + 1;
|
||||
layout_set_size(lc, new_sx, new_sy, new_xoff, lc->yoff);
|
||||
layout_set_size(lc, new_sx, new_sy, new_xoff, lc->g.yoff);
|
||||
resizes++;
|
||||
} else if ((lx == right + 1 || lx == right) &&
|
||||
ly == wp->yoff + sy) {
|
||||
/* Bottom right corner. */
|
||||
new_sx = x - lc->xoff;
|
||||
new_sx = x - lc->g.xoff;
|
||||
if (new_sx < PANE_MINIMUM)
|
||||
new_sx = PANE_MINIMUM;
|
||||
new_sy = y - lc->yoff;
|
||||
new_sy = y - lc->g.yoff;
|
||||
if (new_sy < PANE_MINIMUM)
|
||||
new_sy = PANE_MINIMUM;
|
||||
layout_set_size(lc, new_sx, new_sy, lc->xoff, lc->yoff);
|
||||
layout_set_size(lc, new_sx, new_sy, lc->g.xoff, lc->g.yoff);
|
||||
resizes++;
|
||||
} else if (lx == right) {
|
||||
/* Right border. */
|
||||
new_sx = x - lc->xoff;
|
||||
new_sx = x - lc->g.xoff;
|
||||
if (new_sx < PANE_MINIMUM)
|
||||
return;
|
||||
layout_set_size(lc, new_sx, lc->sy, lc->xoff, lc->yoff);
|
||||
layout_set_size(lc, new_sx, lc->g.sy, lc->g.xoff, lc->g.yoff);
|
||||
resizes++;
|
||||
} else if (lx == left) {
|
||||
/* Left border. */
|
||||
new_sx = lc->sx + (lx - x);
|
||||
new_sx = lc->g.sx + (lx - x);
|
||||
if (new_sx < PANE_MINIMUM)
|
||||
return;
|
||||
new_xoff = x + 1;
|
||||
layout_set_size(lc, new_sx, lc->sy, new_xoff, lc->yoff);
|
||||
layout_set_size(lc, new_sx, lc->g.sy, new_xoff, lc->g.yoff);
|
||||
resizes++;
|
||||
} else if (ly == wp->yoff + sy) {
|
||||
/* Bottom border. */
|
||||
new_sy = y - lc->yoff;
|
||||
new_sy = y - lc->g.yoff;
|
||||
if (new_sy < PANE_MINIMUM)
|
||||
return;
|
||||
layout_set_size(lc, lc->sx, new_sy, lc->xoff, lc->yoff);
|
||||
layout_set_size(lc, lc->g.sx, new_sy, lc->g.xoff, lc->g.yoff);
|
||||
resizes++;
|
||||
} else if (ly == wp->yoff - 1) {
|
||||
/* Top border (move instead of resize). */
|
||||
new_xoff = lc->xoff + (x - lx);
|
||||
new_xoff = lc->g.xoff + (x - lx);
|
||||
new_yoff = y + 1;
|
||||
layout_set_size(lc, lc->sx, lc->sy, new_xoff, new_yoff);
|
||||
layout_set_size(lc, lc->g.sx, lc->g.sy, new_xoff, new_yoff);
|
||||
resizes++;
|
||||
}
|
||||
if (resizes != 0) {
|
||||
|
||||
@@ -178,10 +178,10 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct window_pane *loop;
|
||||
struct options *oo;
|
||||
struct options_entry *parent, *o, *po;
|
||||
char *name, *argument, *expanded = NULL;
|
||||
char *cause;
|
||||
char *name, *argument, *cause;
|
||||
char *expanded = NULL, *array_key = NULL;
|
||||
const char *value;
|
||||
int window, idx, already, error, ambiguous;
|
||||
int window, already, error, ambiguous;
|
||||
int scope;
|
||||
|
||||
window = (cmd_get_entry(self) == &cmd_set_window_option_entry);
|
||||
@@ -202,8 +202,8 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
/* Parse option name and index. */
|
||||
name = options_match(argument, &idx, &ambiguous);
|
||||
/* Parse option name and array key. */
|
||||
name = options_match(argument, &array_key, &ambiguous);
|
||||
if (name == NULL) {
|
||||
if (args_has(args, 'q'))
|
||||
goto out;
|
||||
@@ -235,21 +235,23 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
|
||||
o = options_get_only(oo, name);
|
||||
parent = options_get(oo, name);
|
||||
|
||||
/* Check that array options and indexes match up. */
|
||||
if (idx != -1 && (*name == '@' || !options_is_array(parent))) {
|
||||
/* Check that array options and keys match up. */
|
||||
if (array_key != NULL && (*name == '@' || !options_is_array(parent))) {
|
||||
cmdq_error(item, "not an array: %s", argument);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* With -o, check this option is not already set. */
|
||||
if (!args_has(args, 'u') && args_has(args, 'o')) {
|
||||
if (idx == -1)
|
||||
if (array_key == NULL)
|
||||
already = (o != NULL);
|
||||
else {
|
||||
if (o == NULL)
|
||||
already = 0;
|
||||
else if (options_array_get(o, array_key) != NULL)
|
||||
already = 1;
|
||||
else
|
||||
already = (options_array_get(o, idx) != NULL);
|
||||
already = 0;
|
||||
}
|
||||
if (already) {
|
||||
if (args_has(args, 'q'))
|
||||
@@ -265,7 +267,8 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
|
||||
po = options_get_only(loop->options, name);
|
||||
if (po == NULL)
|
||||
continue;
|
||||
if (options_remove_or_default(po, idx, &cause) != 0) {
|
||||
if (options_remove_or_default(po, array_key,
|
||||
&cause) != 0) {
|
||||
cmdq_error(item, "%s", cause);
|
||||
free(cause);
|
||||
goto fail;
|
||||
@@ -275,7 +278,7 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (args_has(args, 'u') || args_has(args, 'U')) {
|
||||
if (o == NULL)
|
||||
goto out;
|
||||
if (options_remove_or_default(o, idx, &cause) != 0) {
|
||||
if (options_remove_or_default(o, array_key, &cause) != 0) {
|
||||
cmdq_error(item, "%s", cause);
|
||||
free(cause);
|
||||
goto fail;
|
||||
@@ -286,7 +289,7 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
|
||||
goto fail;
|
||||
}
|
||||
options_set_string(oo, name, append, "%s", value);
|
||||
} else if (idx == -1 && !options_is_array(parent)) {
|
||||
} else if (array_key == NULL && !options_is_array(parent)) {
|
||||
error = options_from_string(oo, options_table_entry(parent),
|
||||
options_table_entry(parent)->name, value,
|
||||
args_has(args, 'a'), &cause);
|
||||
@@ -302,7 +305,7 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
|
||||
}
|
||||
if (o == NULL)
|
||||
o = options_empty(oo, options_table_entry(parent));
|
||||
if (idx == -1) {
|
||||
if (array_key == NULL) {
|
||||
if (!append)
|
||||
options_array_clear(o);
|
||||
if (options_array_assign(o, value, &cause) != 0) {
|
||||
@@ -310,7 +313,7 @@ cmd_set_option_exec(struct cmd *self, struct cmdq_item *item)
|
||||
free(cause);
|
||||
goto fail;
|
||||
}
|
||||
} else if (options_array_set(o, idx, value, append,
|
||||
} else if (options_array_set(o, array_key, value, append,
|
||||
&cause) != 0) {
|
||||
cmdq_error(item, "%s", cause);
|
||||
free(cause);
|
||||
@@ -324,11 +327,13 @@ out:
|
||||
free(argument);
|
||||
free(expanded);
|
||||
free(name);
|
||||
free(array_key);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
fail:
|
||||
free(argument);
|
||||
free(expanded);
|
||||
free(name);
|
||||
free(array_key);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
static enum cmd_retval cmd_show_options_exec(struct cmd *, struct cmdq_item *);
|
||||
|
||||
static void cmd_show_options_print(struct cmd *, struct cmdq_item *,
|
||||
struct options_entry *, int, int);
|
||||
struct options_entry *, const char *, int);
|
||||
static void cmd_show_hooks_print_monitor(struct cmdq_item *,
|
||||
struct options_entry *);
|
||||
static enum cmd_retval cmd_show_hooks_monitor(struct cmd *, struct cmdq_item *,
|
||||
@@ -84,7 +84,8 @@ cmd_show_options_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct cmd_find_state *target = cmdq_get_target(item);
|
||||
struct options *oo;
|
||||
char *argument, *name = NULL, *cause;
|
||||
int window, idx, ambiguous, parent, scope;
|
||||
char *array_key = NULL;
|
||||
int window, ambiguous, parent, scope;
|
||||
struct options_entry *o;
|
||||
|
||||
window = (cmd_get_entry(self) == &cmd_show_window_options_entry);
|
||||
@@ -106,7 +107,7 @@ cmd_show_options_exec(struct cmd *self, struct cmdq_item *item)
|
||||
}
|
||||
argument = format_single_from_target(item, args_string(args, 0));
|
||||
|
||||
name = options_match(argument, &idx, &ambiguous);
|
||||
name = options_match(argument, &array_key, &ambiguous);
|
||||
if (name == NULL) {
|
||||
if (args_has(args, 'q'))
|
||||
goto out;
|
||||
@@ -136,7 +137,7 @@ cmd_show_options_exec(struct cmd *self, struct cmdq_item *item)
|
||||
args_has(args, 'B'))
|
||||
cmd_show_hooks_print_monitor(item, o);
|
||||
else
|
||||
cmd_show_options_print(self, item, o, idx, parent);
|
||||
cmd_show_options_print(self, item, o, array_key, parent);
|
||||
}
|
||||
else if (*name == '@') {
|
||||
if (args_has(args, 'q'))
|
||||
@@ -147,26 +148,28 @@ cmd_show_options_exec(struct cmd *self, struct cmdq_item *item)
|
||||
|
||||
out:
|
||||
free(name);
|
||||
free(array_key);
|
||||
free(argument);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
fail:
|
||||
free(name);
|
||||
free(array_key);
|
||||
free(argument);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_show_options_print(struct cmd *self, struct cmdq_item *item,
|
||||
struct options_entry *o, int idx, int parent)
|
||||
struct options_entry *o, const char *array_key, int parent)
|
||||
{
|
||||
struct args *args = cmd_get_args(self);
|
||||
struct options_array_item *a;
|
||||
const char *name = options_name(o);
|
||||
char *value, *tmp = NULL, *escaped;
|
||||
|
||||
if (idx != -1) {
|
||||
xasprintf(&tmp, "%s[%d]", name, idx);
|
||||
if (array_key != NULL) {
|
||||
xasprintf(&tmp, "%s[%s]", name, array_key);
|
||||
name = tmp;
|
||||
} else {
|
||||
if (options_is_array(o)) {
|
||||
@@ -177,8 +180,8 @@ cmd_show_options_print(struct cmd *self, struct cmdq_item *item,
|
||||
return;
|
||||
}
|
||||
while (a != NULL) {
|
||||
idx = options_array_item_index(a);
|
||||
cmd_show_options_print(self, item, o, idx,
|
||||
array_key = options_array_item_key(a);
|
||||
cmd_show_options_print(self, item, o, array_key,
|
||||
parent);
|
||||
a = options_array_next(a);
|
||||
}
|
||||
@@ -186,7 +189,7 @@ cmd_show_options_print(struct cmd *self, struct cmdq_item *item,
|
||||
}
|
||||
}
|
||||
|
||||
value = options_to_string(o, idx, 0);
|
||||
value = options_to_string(o, array_key, 0);
|
||||
if (args_has(args, 'v'))
|
||||
cmdq_print(item, "%s", value);
|
||||
else if (options_is_string(o)) {
|
||||
@@ -242,15 +245,14 @@ cmd_show_options_all(struct cmd *self, struct cmdq_item *item, int scope,
|
||||
const struct options_table_entry *oe;
|
||||
struct options_entry *o;
|
||||
struct options_array_item *a;
|
||||
const char *name;
|
||||
u_int idx;
|
||||
const char *name, *array_key;
|
||||
int parent;
|
||||
|
||||
if (cmd_get_entry(self) != &cmd_show_hooks_entry) {
|
||||
o = options_first(oo);
|
||||
while (o != NULL) {
|
||||
if (options_table_entry(o) == NULL)
|
||||
cmd_show_options_print(self, item, o, -1, 0);
|
||||
cmd_show_options_print(self, item, o, NULL, 0);
|
||||
o = options_next(o);
|
||||
}
|
||||
}
|
||||
@@ -277,7 +279,7 @@ cmd_show_options_all(struct cmd *self, struct cmdq_item *item, int scope,
|
||||
parent = 0;
|
||||
|
||||
if (!options_is_array(o))
|
||||
cmd_show_options_print(self, item, o, -1, parent);
|
||||
cmd_show_options_print(self, item, o, NULL, parent);
|
||||
else if ((a = options_array_first(o)) == NULL) {
|
||||
if (!args_has(args, 'v')) {
|
||||
name = options_name(o);
|
||||
@@ -288,8 +290,8 @@ cmd_show_options_all(struct cmd *self, struct cmdq_item *item, int scope,
|
||||
}
|
||||
} else {
|
||||
while (a != NULL) {
|
||||
idx = options_array_item_index(a);
|
||||
cmd_show_options_print(self, item, o, idx,
|
||||
array_key = options_array_item_key(a);
|
||||
cmd_show_options_print(self, item, o, array_key,
|
||||
parent);
|
||||
a = options_array_next(a);
|
||||
}
|
||||
|
||||
14
colour.c
14
colour.c
@@ -1294,7 +1294,8 @@ colour_palette_from_option(struct colour_palette *p, struct options *oo)
|
||||
{
|
||||
struct options_entry *o;
|
||||
struct options_array_item *a;
|
||||
u_int i, n;
|
||||
union options_value *ov;
|
||||
u_int i;
|
||||
int c;
|
||||
|
||||
if (p == NULL)
|
||||
@@ -1312,12 +1313,11 @@ colour_palette_from_option(struct colour_palette *p, struct options *oo)
|
||||
p->default_palette = xcalloc(256, sizeof *p->default_palette);
|
||||
for (i = 0; i < 256; i++)
|
||||
p->default_palette[i] = -1;
|
||||
while (a != NULL) {
|
||||
n = options_array_item_index(a);
|
||||
if (n < 256) {
|
||||
c = options_array_item_value(a)->number;
|
||||
p->default_palette[n] = c;
|
||||
for (i = 0; i < 256; i++) {
|
||||
ov = options_array_getv(o, "%u", i);
|
||||
if (ov != NULL) {
|
||||
c = ov->number;
|
||||
p->default_palette[i] = c;
|
||||
}
|
||||
a = options_array_next(a);
|
||||
}
|
||||
}
|
||||
|
||||
33
format.c
33
format.c
@@ -4241,25 +4241,26 @@ format_find(struct format_tree *ft, const char *key, uint64_t modifiers,
|
||||
struct format_entry *fe, fe_find;
|
||||
struct environ_entry *envent;
|
||||
struct options_entry *o;
|
||||
int idx;
|
||||
char *found = NULL, *saved, s[512];
|
||||
char *array_key = NULL;
|
||||
const char *errstr;
|
||||
time_t t = 0;
|
||||
struct tm tm;
|
||||
|
||||
o = options_parse_get(global_options, key, &idx, 0);
|
||||
o = options_parse_get(global_options, key, &array_key, 0);
|
||||
if (o == NULL && ft->wp != NULL)
|
||||
o = options_parse_get(ft->wp->options, key, &idx, 0);
|
||||
o = options_parse_get(ft->wp->options, key, &array_key, 0);
|
||||
if (o == NULL && ft->w != NULL)
|
||||
o = options_parse_get(ft->w->options, key, &idx, 0);
|
||||
o = options_parse_get(ft->w->options, key, &array_key, 0);
|
||||
if (o == NULL)
|
||||
o = options_parse_get(global_w_options, key, &idx, 0);
|
||||
o = options_parse_get(global_w_options, key, &array_key, 0);
|
||||
if (o == NULL && ft->s != NULL)
|
||||
o = options_parse_get(ft->s->options, key, &idx, 0);
|
||||
o = options_parse_get(ft->s->options, key, &array_key, 0);
|
||||
if (o == NULL)
|
||||
o = options_parse_get(global_s_options, key, &idx, 0);
|
||||
o = options_parse_get(global_s_options, key, &array_key, 0);
|
||||
if (o != NULL) {
|
||||
found = options_to_string(o, idx, 1);
|
||||
found = options_to_string(o, array_key, 1);
|
||||
free(array_key);
|
||||
goto found;
|
||||
}
|
||||
|
||||
@@ -4953,7 +4954,7 @@ format_add_window_neighbour(struct format_tree *nft, struct winlink *wl,
|
||||
oname = options_name(o);
|
||||
if (*oname == '@') {
|
||||
xasprintf(&prefixed, "%s_%s", prefix, oname);
|
||||
oval = options_to_string(o, -1, 1);
|
||||
oval = options_to_string(o, NULL, 1);
|
||||
format_add(nft, prefixed, "%s", oval);
|
||||
free(oval);
|
||||
free(prefixed);
|
||||
@@ -5125,11 +5126,12 @@ format_loop_add_option(struct format_expand_state *es, const char *fmt,
|
||||
nft = format_create(ft->client, ft->item, FORMAT_NONE, ft->flags);
|
||||
|
||||
format_add(nft, "option_name", "%s", name);
|
||||
s = options_to_string(o, -1, 0);
|
||||
s = options_to_string(o, NULL, 0);
|
||||
format_add(nft, "option_value", "%s", s);
|
||||
free(s);
|
||||
|
||||
format_add(nft, "option_is_array", "%d", is_array);
|
||||
format_add(nft, "option_array_key", "%s", "");
|
||||
format_add(nft, "option_array_index", "%s", "");
|
||||
format_add(nft, "option_array_first", "%d", is_array);
|
||||
format_add(nft, "option_array_last", "%d", is_array);
|
||||
@@ -5167,20 +5169,21 @@ format_loop_add_array_item(struct format_expand_state *es, const char *fmt,
|
||||
struct format_expand_state next;
|
||||
const struct options_table_entry *oe = options_table_entry(o);
|
||||
const char *name = options_name(o);
|
||||
const char *array_key;
|
||||
char *expanded, *s;
|
||||
u_int idx;
|
||||
|
||||
idx = options_array_item_index(a);
|
||||
format_log(es, "option loop: %s[%u]", name, idx);
|
||||
array_key = options_array_item_key(a);
|
||||
format_log(es, "option loop: %s[%s]", name, array_key);
|
||||
nft = format_create(ft->client, ft->item, FORMAT_NONE, ft->flags);
|
||||
|
||||
format_add(nft, "option_name", "%s", name);
|
||||
s = options_to_string(o, idx, 0);
|
||||
s = options_to_string(o, array_key, 0);
|
||||
format_add(nft, "option_value", "%s", s);
|
||||
free(s);
|
||||
|
||||
format_add(nft, "option_is_array", "1");
|
||||
format_add(nft, "option_array_index", "%u", idx);
|
||||
format_add(nft, "option_array_key", "%s", array_key);
|
||||
format_add(nft, "option_array_index", "%s", array_key);
|
||||
if (a == options_array_first(o))
|
||||
format_add(nft, "option_array_first", "1");
|
||||
else
|
||||
|
||||
2
input.c
2
input.c
@@ -2818,7 +2818,7 @@ input_exit_rename(struct input_ctx *ictx)
|
||||
if (ictx->input_len == 0) {
|
||||
o = options_get_only(w->options, "automatic-rename");
|
||||
if (o != NULL)
|
||||
options_remove_or_default(o, -1, NULL);
|
||||
options_remove_or_default(o, NULL, NULL);
|
||||
if (!options_get_number(w->options, "automatic-rename"))
|
||||
window_set_name(w, "", 1);
|
||||
} else {
|
||||
|
||||
@@ -59,6 +59,8 @@
|
||||
" '#{?mouse_hyperlink,Type #[underscore]#{=/9/...:mouse_hyperlink},}' 'C-h' {copy-mode -q; send-keys -l -- \"#{q:mouse_hyperlink}\"}" \
|
||||
" '#{?mouse_hyperlink,Copy #[underscore]#{=/9/...:mouse_hyperlink},}' 'h' {copy-mode -q; set-buffer -- \"#{q:mouse_hyperlink}\"}" \
|
||||
" ''" \
|
||||
" '#{?#{#{pane_floating_flag}},Move,}' '' {display-menu -xL -yL -T '#[align=centre]Move' " DEFAULT_MOVE_MENU " }" \
|
||||
" '#{?#{#{pane_floating_flag}},Move & Resize,}' '' {display-menu -xL -yL -T '#[align=centre]Move & Resize' " DEFAULT_MOVE_RESIZE_MENU " }" \
|
||||
" '#{?#{#{pane_floating_flag}},Tile,}' 't' { join-pane }" \
|
||||
" '#{?#{!:#{pane_floating_flag}},Float,}' 'f' { break-pane -W }" \
|
||||
" '#{?#{!:#{pane_floating_flag}},Horizontal Split,}' 'h' {split-window -h}" \
|
||||
@@ -72,6 +74,30 @@
|
||||
" 'Respawn' 'R' {respawn-pane -k}" \
|
||||
" '#{?pane_marked,Unmark,Mark}' 'm' {select-pane -m}" \
|
||||
" '#{?#{>:#{window_panes},1},,-}#{?window_zoomed_flag,Unzoom,Zoom}' 'z' {resize-pane -Z}"
|
||||
#define DEFAULT_MOVE_MENU \
|
||||
" 'Centre' 'c' {move-pane -P centre}" \
|
||||
" ''" \
|
||||
" 'Top Left' '1' {move-pane -P top-left}" \
|
||||
" 'Top Right' '2' {move-pane -P top-right}" \
|
||||
" 'Bottom Left' '3' {move-pane -P bottom-left}" \
|
||||
" 'Bottom Right' '4' {move-pane -P bottom-right}" \
|
||||
" ''" \
|
||||
" 'Top' 't' {move-pane -P top-centre}" \
|
||||
" 'Bottom' 'b' {move-pane -P bottom-centre}" \
|
||||
" 'Left' 'l' {move-pane -P centre-left}" \
|
||||
" 'Right' 'r' {move-pane -P centre-right}"
|
||||
#define DEFAULT_MOVE_RESIZE_MENU \
|
||||
" 'Fill' '0' {resize-pane -x100% -y100%; move-pane -P top-left}" \
|
||||
" ''" \
|
||||
" 'Top Left' '1' {resize-pane -x50% -y50%; move-pane -P top-left}" \
|
||||
" 'Top Right' '2' {resize-pane -x50% -y50%; move-pane -P top-right}" \
|
||||
" 'Bottom Left' '3' {resize-pane -x50% -y50%; move-pane -P bottom-left}" \
|
||||
" 'Bottom Right' '4' {resize-pane -x50% -y50%; move-pane -P bottom-right}" \
|
||||
" ''" \
|
||||
" 'Top' 't' {resize-pane -x100% -y50%; move-pane -P top-centre}" \
|
||||
" 'Bottom' 'b' {resize-pane -x100% -y50%; move-pane -P bottom-centre}" \
|
||||
" 'Left' 'l' {resize-pane -x50% -y100%; move-pane -P centre-left}" \
|
||||
" 'Right' 'r' {resize-pane -x50% -y100%; move-pane -P centre-right}"
|
||||
|
||||
static int key_bindings_cmp(struct key_binding *, struct key_binding *);
|
||||
RB_GENERATE_STATIC(key_bindings, key_binding, entry, key_bindings_cmp);
|
||||
@@ -362,14 +388,14 @@ key_bindings_init(void)
|
||||
"bind -N 'Rename current session' '$' { command-prompt -I'#S' { rename-session -- '%%' } }",
|
||||
"bind -N 'Split window horizontally' % { split-window -h }",
|
||||
"bind -N 'Kill current window' & { confirm-before -p\"kill-window #W? (y/n)\" kill-window }",
|
||||
"bind -N 'Prompt for window index to select' \"'\" { command-prompt -T window-target -pindex { select-window -t ':%%' } }",
|
||||
"bind -N 'Prompt for window index to select' \"'\" { command-prompt -pindex { select-window -t ':%%' } }",
|
||||
"bind -N 'New floating pane' * { new-pane }",
|
||||
"bind -N 'Toggle pane between floating and tiled' @ { if -F '#{pane_floating_flag}' { join-pane } { break-pane -W } }",
|
||||
"bind -N 'Switch to previous client' ( { switch-client -p }",
|
||||
"bind -N 'Switch to next client' ) { switch-client -n }",
|
||||
"bind -N 'Rename current window' , { command-prompt -I'#W' { rename-window -- '%%' } }",
|
||||
"bind -N 'Delete the most recent paste buffer' - { delete-buffer }",
|
||||
"bind -N 'Move the current window' . { command-prompt -T target { move-window -t '%%' } }",
|
||||
"bind -N 'Move the current window' . { command-prompt { move-window -t '%%' } }",
|
||||
"bind -N 'Describe key binding' '/' { command-prompt -kpkey { list-keys -1N '%%' } }",
|
||||
"bind -N 'Select window 0' 0 { select-window -t:=0 }",
|
||||
"bind -N 'Select window 1' 1 { select-window -t:=1 }",
|
||||
@@ -410,10 +436,8 @@ key_bindings_init(void)
|
||||
"bind -N 'Choose a window from a list' w { choose-tree -Zw }",
|
||||
"bind -N 'Kill the active pane' x { confirm-before -p\"kill-pane #P? (y/n)\" kill-pane }",
|
||||
"bind -N 'Zoom the active pane' z { resize-pane -Z }",
|
||||
"bind -N 'Move pane to top-left corner' '{' { resize-pane -x50% -y50%; move-pane -P top-left }",
|
||||
"bind -N 'Move pane to top-right corner' '}' { resize-pane -x50% -y50%; move-pane -P top-right }",
|
||||
"bind -N 'Move pane to bottom-left corner' 'M-{' { resize-pane -x50% -y50%; move-pane -P bottom-left }",
|
||||
"bind -N 'Move pane to bottom-right corner' 'M-}' { resize-pane -x50% -y50%; move-pane -P bottom-right }",
|
||||
"bind -N 'Swap the active pane with the pane above' '{' { swap-pane -U }",
|
||||
"bind -N 'Swap the active pane with the pane below' '}' { swap-pane -D }",
|
||||
"bind -N 'Show messages' '~' { show-messages }",
|
||||
"bind -N 'Enter copy mode and scroll up' PPage { copy-mode -u }",
|
||||
"bind -N 'Select the pane above the active pane' -r Up { select-pane -U }",
|
||||
@@ -444,6 +468,28 @@ key_bindings_init(void)
|
||||
"bind -N 'Resize the pane left' -r C-Left if -F '#{?floating_pane_flag}' { resizep -R-1 } { resize-pane -L }",
|
||||
"bind -N 'Resize the pane right' -r C-Right { resize-pane -R }",
|
||||
|
||||
/* Floating pane movement. */
|
||||
"bind -N 'Move a floating pane' g { switch-client -Tmove }",
|
||||
"bind -Tmove -N 'Move pane to top-left corner' 1 { move-pane -P top-left }",
|
||||
"bind -Tmove -N 'Move pane to top-right corner' 2 { move-pane -P top-right }",
|
||||
"bind -Tmove -N 'Move pane to bottom-left corner' 3 { move-pane -P bottom-left }",
|
||||
"bind -Tmove -N 'Move pane to bottom-right corner' 4 { move-pane -P bottom-right }",
|
||||
"bind -Tmove -N 'Move pane to top-left corner and resize' M-1 { resize-pane -x50% -y50%; move-pane -P top-left }",
|
||||
"bind -Tmove -N 'Move pane to top-right corner and resize' M-2 { resize-pane -x50% -y50%; move-pane -P top-right }",
|
||||
"bind -Tmove -N 'Move pane to bottom-left corner and resize' M-3 { resize-pane -x50% -y50%; move-pane -P bottom-left }",
|
||||
"bind -Tmove -N 'Move pane to bottom-right corner and resize' M-4 { resize-pane -x50% -y50%; move-pane -P bottom-right }",
|
||||
"bind -Tmove -N 'Move pane to top' 'Up' { move-pane -P top-centre }",
|
||||
"bind -Tmove -N 'Move pane to bottom' 'Down' { move-pane -P bottom-centre }",
|
||||
"bind -Tmove -N 'Move pane to left' 'Left' { move-pane -P centre-left }",
|
||||
"bind -Tmove -N 'Move pane to right' 'Right' { move-pane -P centre-right }",
|
||||
"bind -Tmove -N 'Move pane to top and resize' 'M-Up' { resizep -x100% -y50%; move-pane -P top-centre }",
|
||||
"bind -Tmove -N 'Move pane to bottom and resize' 'M-Down' { resizep -x100% -y50%; move-pane -P bottom-centre }",
|
||||
"bind -Tmove -N 'Move pane to left and resize' 'M-Left' { resizep -x50% -y100%; move-pane -P centre-left }",
|
||||
"bind -Tmove -N 'Move pane to right and resize' 'M-Right' { resizep -x50% -y100%; move-pane -P centre-right }",
|
||||
"bind -Tmove -N 'Move pane to fill the window' 0 { resize-pane -x100% -y100%; move-pane -P top-left }",
|
||||
"bind -Tmove -N 'Display move menu' , { if -F '#{pane_floating_flag}' { display-menu -xP -yP -T '#[align=centre]Move' " DEFAULT_MOVE_MENU " } }",
|
||||
"bind -Tmove -N 'Display move and resize menu' . { if -F '#{pane_floating_flag}' { display-menu -xP -yP -T '#[align=centre]Move & Resize' " DEFAULT_MOVE_RESIZE_MENU " } }",
|
||||
|
||||
/* Menu keys */
|
||||
"bind -N 'Display window menu' < { display-menu -xW -yW -T '#[align=centre]#{window_index}:#{window_name}' " DEFAULT_WINDOW_MENU " }",
|
||||
"bind -N 'Display pane menu' > { display-menu -xP -yP -T '#[align=centre]#{pane_index} (#{pane_id})' " DEFAULT_PANE_MENU " }",
|
||||
|
||||
106
layout-custom.c
106
layout-custom.c
@@ -231,19 +231,19 @@ layout_append_legacy(struct layout_cell *lc, char *buf, size_t len)
|
||||
if (lc == NULL)
|
||||
return (0);
|
||||
|
||||
sx = lc->sx;
|
||||
sy = lc->sy;
|
||||
xoff = lc->xoff;
|
||||
yoff = lc->yoff;
|
||||
sx = lc->g.sx;
|
||||
sy = lc->g.sy;
|
||||
xoff = lc->g.xoff;
|
||||
yoff = lc->g.yoff;
|
||||
if (lc->flags & LAYOUT_CELL_HIDDEN) {
|
||||
if (lc->saved_sx != UINT_MAX)
|
||||
sx = lc->saved_sx;
|
||||
if (lc->saved_sy != UINT_MAX)
|
||||
sy = lc->saved_sy;
|
||||
if (lc->saved_xoff != INT_MAX)
|
||||
xoff = lc->saved_xoff;
|
||||
if (lc->saved_yoff != INT_MAX)
|
||||
yoff = lc->saved_yoff;
|
||||
if (lc->fg.sx != UINT_MAX)
|
||||
sx = lc->fg.sx;
|
||||
if (lc->fg.sy != UINT_MAX)
|
||||
sy = lc->fg.sy;
|
||||
if (lc->fg.xoff != INT_MAX)
|
||||
xoff = lc->fg.xoff;
|
||||
if (lc->fg.yoff != INT_MAX)
|
||||
yoff = lc->fg.yoff;
|
||||
}
|
||||
|
||||
if (lc->wp != NULL) {
|
||||
@@ -293,19 +293,19 @@ layout_append(struct window *w, struct layout_cell *lc, char *buf, size_t len)
|
||||
if (lc == NULL)
|
||||
return (0);
|
||||
|
||||
sx = lc->sx;
|
||||
sy = lc->sy;
|
||||
xoff = lc->xoff;
|
||||
yoff = lc->yoff;
|
||||
sx = lc->g.sx;
|
||||
sy = lc->g.sy;
|
||||
xoff = lc->g.xoff;
|
||||
yoff = lc->g.yoff;
|
||||
if (lc->flags & LAYOUT_CELL_HIDDEN) {
|
||||
if (lc->saved_sx != UINT_MAX)
|
||||
sx = lc->saved_sx;
|
||||
if (lc->saved_sy != UINT_MAX)
|
||||
sy = lc->saved_sy;
|
||||
if (lc->saved_xoff != INT_MAX)
|
||||
xoff = lc->saved_xoff;
|
||||
if (lc->saved_yoff != INT_MAX)
|
||||
yoff = lc->saved_yoff;
|
||||
if (lc->fg.sx != UINT_MAX)
|
||||
sx = lc->fg.sx;
|
||||
if (lc->fg.sy != UINT_MAX)
|
||||
sy = lc->fg.sy;
|
||||
if (lc->fg.xoff != INT_MAX)
|
||||
xoff = lc->fg.xoff;
|
||||
if (lc->fg.yoff != INT_MAX)
|
||||
yoff = lc->fg.yoff;
|
||||
}
|
||||
|
||||
if (lc->wp != NULL) {
|
||||
@@ -375,24 +375,24 @@ layout_check(struct layout_cell *lc)
|
||||
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
||||
if (!layout_has_tiled(lcchild))
|
||||
continue;
|
||||
if (lcchild->sy != lc->sy || !layout_check(lcchild))
|
||||
if (lcchild->g.sy != lc->g.sy || !layout_check(lcchild))
|
||||
return (0);
|
||||
n += lcchild->sx + 1;
|
||||
n += lcchild->g.sx + 1;
|
||||
children++;
|
||||
}
|
||||
if (children != 0 && n - 1 != lc->sx)
|
||||
if (children != 0 && n - 1 != lc->g.sx)
|
||||
return (0);
|
||||
break;
|
||||
case LAYOUT_TOPBOTTOM:
|
||||
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
||||
if (!layout_has_tiled(lcchild))
|
||||
continue;
|
||||
if (lcchild->sx != lc->sx || !layout_check(lcchild))
|
||||
if (lcchild->g.sx != lc->g.sx || !layout_check(lcchild))
|
||||
return (0);
|
||||
n += lcchild->sy + 1;
|
||||
n += lcchild->g.sy + 1;
|
||||
children++;
|
||||
}
|
||||
if (children != 0 && n - 1 != lc->sy)
|
||||
if (children != 0 && n - 1 != lc->g.sy)
|
||||
return (0);
|
||||
break;
|
||||
}
|
||||
@@ -423,21 +423,21 @@ layout_fix_legacy_root(struct layout_cell *root)
|
||||
return (0);
|
||||
if (root->type == LAYOUT_LEFTRIGHT) {
|
||||
TAILQ_FOREACH(lcchild, &root->cells, entry) {
|
||||
sy = lcchild->sy + 1;
|
||||
sx += lcchild->sx + 1;
|
||||
sy = lcchild->g.sy + 1;
|
||||
sx += lcchild->g.sx + 1;
|
||||
}
|
||||
} else {
|
||||
TAILQ_FOREACH(lcchild, &root->cells, entry) {
|
||||
sx = lcchild->sx + 1;
|
||||
sy += lcchild->sy + 1;
|
||||
sx = lcchild->g.sx + 1;
|
||||
sy += lcchild->g.sy + 1;
|
||||
}
|
||||
}
|
||||
if (sx != 0 && sy != 0 &&
|
||||
(root->sx != sx - 1 || root->sy != sy - 1)) {
|
||||
(root->g.sx != sx - 1 || root->g.sy != sy - 1)) {
|
||||
if (sx - 1 > PANE_MAXIMUM || sy - 1 > PANE_MAXIMUM)
|
||||
return (-1);
|
||||
root->sx = sx - 1;
|
||||
root->sy = sy - 1;
|
||||
root->g.sx = sx - 1;
|
||||
root->g.sy = sy - 1;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
@@ -736,10 +736,10 @@ layout_construct(struct layout_parse_ctx *ctx, struct layout_cell *parent,
|
||||
(lc->flags & LAYOUT_CELL_FLOATING) == 0)
|
||||
goto fail;
|
||||
if (lc->flags & LAYOUT_CELL_HIDDEN) {
|
||||
lc->saved_sx = lc->sx;
|
||||
lc->saved_sy = lc->sy;
|
||||
lc->saved_xoff = lc->xoff;
|
||||
lc->saved_yoff = lc->yoff;
|
||||
lc->fg.sx = lc->g.sx;
|
||||
lc->fg.sy = lc->g.sy;
|
||||
lc->fg.xoff = lc->g.xoff;
|
||||
lc->fg.yoff = lc->g.yoff;
|
||||
}
|
||||
} else if (ctx->ptr != ctx->end &&
|
||||
(*ctx->ptr == '{' || *ctx->ptr == '[')) {
|
||||
@@ -815,26 +815,26 @@ layout_resolve_relative(struct layout_cell *lc, u_int sx, u_int sy)
|
||||
return (0);
|
||||
}
|
||||
if (lc->flags & LAYOUT_CELL_X_RELATIVE) {
|
||||
resolved = (long long)sx - lc->sx - lc->xoff;
|
||||
resolved = (long long)sx - lc->g.sx - lc->g.xoff;
|
||||
if (resolved < INT_MIN || resolved > INT_MAX)
|
||||
return (-1);
|
||||
lc->xoff = resolved;
|
||||
lc->g.xoff = resolved;
|
||||
lc->flags &= ~LAYOUT_CELL_X_RELATIVE;
|
||||
}
|
||||
if (lc->flags & LAYOUT_CELL_Y_RELATIVE) {
|
||||
resolved = (long long)sy - lc->sy - lc->yoff;
|
||||
resolved = (long long)sy - lc->g.sy - lc->g.yoff;
|
||||
if (resolved < INT_MIN || resolved > INT_MAX)
|
||||
return (-1);
|
||||
lc->yoff = resolved;
|
||||
lc->g.yoff = resolved;
|
||||
lc->flags &= ~LAYOUT_CELL_Y_RELATIVE;
|
||||
}
|
||||
if (lc->flags & LAYOUT_CELL_HIDDEN) {
|
||||
lc->saved_sx = lc->sx;
|
||||
lc->saved_sy = lc->sy;
|
||||
lc->saved_xoff = lc->xoff;
|
||||
lc->saved_yoff = lc->yoff;
|
||||
lc->fg.sx = lc->g.sx;
|
||||
lc->fg.sy = lc->g.sy;
|
||||
lc->fg.xoff = lc->g.xoff;
|
||||
lc->fg.yoff = lc->g.yoff;
|
||||
}
|
||||
if (!layout_check_geometry(lc->sx, lc->sy, lc->xoff, lc->yoff))
|
||||
if (!layout_check_geometry(lc->g.sx, lc->g.sy, lc->g.xoff, lc->g.yoff))
|
||||
return (-1);
|
||||
return (0);
|
||||
}
|
||||
@@ -1009,8 +1009,8 @@ layout_prepare(struct window *w, const char *layout, char **cause)
|
||||
return (NULL);
|
||||
}
|
||||
if (layout_resolve_relative(root,
|
||||
root->type == LAYOUT_WINDOWPANE ? w->sx : root->sx,
|
||||
root->type == LAYOUT_WINDOWPANE ? w->sy : root->sy) != 0) {
|
||||
root->type == LAYOUT_WINDOWPANE ? w->sx : root->g.sx,
|
||||
root->type == LAYOUT_WINDOWPANE ? w->sy : root->g.sy) != 0) {
|
||||
*cause = xstrdup("invalid layout");
|
||||
layout_free_cell(root, 0);
|
||||
return (NULL);
|
||||
@@ -1127,7 +1127,7 @@ layout_apply_prepared(struct window *w, struct layout_prepared *prepared)
|
||||
layout_fix_zindexes(w, root);
|
||||
|
||||
if (layout_has_tiled(root))
|
||||
window_resize(w, root->sx, root->sy, -1, -1);
|
||||
window_resize(w, root->g.sx, root->g.sy, -1, -1);
|
||||
layout_fix_offsets(w);
|
||||
layout_fix_panes(w, NULL);
|
||||
layout_print_cell(root, __func__, 0);
|
||||
|
||||
16
layout-set.c
16
layout-set.c
@@ -170,8 +170,8 @@ layout_set_even(struct window *w, enum layout_type type)
|
||||
TAILQ_INSERT_TAIL(&lcroot->cells, lcchild, entry);
|
||||
lcchild->parent = lcroot;
|
||||
if (layout_cell_is_tiled(lcchild)) {
|
||||
lcchild->sx = w->sx;
|
||||
lcchild->sy = w->sy;
|
||||
lcchild->g.sx = w->sx;
|
||||
lcchild->g.sy = w->sy;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,7 +182,7 @@ layout_set_even(struct window *w, enum layout_type type)
|
||||
|
||||
layout_print_cell(w->layout_root, __func__, 1);
|
||||
|
||||
window_resize(w, lcroot->sx, lcroot->sy, -1, -1);
|
||||
window_resize(w, lcroot->g.sx, lcroot->g.sy, -1, -1);
|
||||
notify_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
}
|
||||
@@ -292,7 +292,7 @@ layout_set_main_h(struct window *w)
|
||||
|
||||
layout_print_cell(w->layout_root, __func__, 1);
|
||||
|
||||
window_resize(w, lcroot->sx, lcroot->sy, -1, -1);
|
||||
window_resize(w, lcroot->g.sx, lcroot->g.sy, -1, -1);
|
||||
notify_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
}
|
||||
@@ -390,7 +390,7 @@ layout_set_main_h_mirrored(struct window *w)
|
||||
|
||||
layout_print_cell(w->layout_root, __func__, 1);
|
||||
|
||||
window_resize(w, lcroot->sx, lcroot->sy, -1, -1);
|
||||
window_resize(w, lcroot->g.sx, lcroot->g.sy, -1, -1);
|
||||
notify_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
}
|
||||
@@ -488,7 +488,7 @@ layout_set_main_v(struct window *w)
|
||||
|
||||
layout_print_cell(w->layout_root, __func__, 1);
|
||||
|
||||
window_resize(w, lcroot->sx, lcroot->sy, -1, -1);
|
||||
window_resize(w, lcroot->g.sx, lcroot->g.sy, -1, -1);
|
||||
notify_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
}
|
||||
@@ -587,7 +587,7 @@ layout_set_main_v_mirrored(struct window *w)
|
||||
|
||||
layout_print_cell(w->layout_root, __func__, 1);
|
||||
|
||||
window_resize(w, lcroot->sx, lcroot->sy, -1, -1);
|
||||
window_resize(w, lcroot->g.sx, lcroot->g.sy, -1, -1);
|
||||
notify_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
}
|
||||
@@ -709,7 +709,7 @@ layout_set_tiled(struct window *w)
|
||||
|
||||
layout_print_cell(w->layout_root, __func__, 1);
|
||||
|
||||
window_resize(w, lcroot->sx, lcroot->sy, -1, -1);
|
||||
window_resize(w, lcroot->g.sx, lcroot->g.sy, -1, -1);
|
||||
notify_window("window-layout-changed", w);
|
||||
server_redraw_window(w);
|
||||
}
|
||||
|
||||
290
layout.c
290
layout.c
@@ -56,34 +56,31 @@ static int layout_set_size_check(struct window *, struct layout_cell *,
|
||||
static void layout_resize_child_cells(struct window *,
|
||||
struct layout_cell *);
|
||||
|
||||
/* Initializes cell geometry to sentinel values. */
|
||||
static void
|
||||
layout_geometry_init(struct layout_geometry *lg)
|
||||
{
|
||||
lg->sx = UINT_MAX;
|
||||
lg->sy = UINT_MAX;
|
||||
lg->xoff = INT_MAX;
|
||||
lg->yoff = INT_MAX;
|
||||
}
|
||||
|
||||
/* Create a new layout cell. */
|
||||
struct layout_cell *
|
||||
layout_create_cell(struct layout_cell *lcparent)
|
||||
{
|
||||
struct layout_cell *lc;
|
||||
|
||||
lc = xmalloc(sizeof *lc);
|
||||
lc = xcalloc(1, sizeof *lc);
|
||||
lc->type = LAYOUT_WINDOWPANE;
|
||||
lc->flags = 0;
|
||||
lc->z_index = UINT_MAX;
|
||||
lc->pane_id = UINT_MAX;
|
||||
lc->parent = lcparent;
|
||||
|
||||
TAILQ_INIT(&lc->cells);
|
||||
|
||||
lc->sx = UINT_MAX;
|
||||
lc->sy = UINT_MAX;
|
||||
|
||||
lc->xoff = INT_MAX;
|
||||
lc->yoff = INT_MAX;
|
||||
|
||||
lc->saved_sx = UINT_MAX;
|
||||
lc->saved_sy = UINT_MAX;
|
||||
|
||||
lc->saved_xoff = INT_MAX;
|
||||
lc->saved_yoff = INT_MAX;
|
||||
|
||||
lc->wp = NULL;
|
||||
layout_geometry_init(&lc->g);
|
||||
layout_geometry_init(&lc->fg);
|
||||
|
||||
return (lc);
|
||||
}
|
||||
@@ -146,8 +143,8 @@ layout_print_cell(struct layout_cell *lc, const char *hdr, u_int n)
|
||||
break;
|
||||
}
|
||||
log_debug("%s:%*s%p type %s [parent %p] wp=%p [%d,%d %ux%u]", hdr, n,
|
||||
" ", lc, type, lc->parent, lc->wp, lc->xoff, lc->yoff, lc->sx,
|
||||
lc->sy);
|
||||
" ", lc, type, lc->parent, lc->wp, lc->g.xoff, lc->g.yoff, lc->g.sx,
|
||||
lc->g.sy);
|
||||
switch (lc->type) {
|
||||
case LAYOUT_LEFTRIGHT:
|
||||
case LAYOUT_TOPBOTTOM:
|
||||
@@ -166,10 +163,10 @@ layout_search_by_border(struct layout_cell *lc, u_int x, u_int y)
|
||||
struct layout_cell *lcchild, *last = NULL;
|
||||
|
||||
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
||||
if ((int)x >= lcchild->xoff &&
|
||||
(int)x < lcchild->xoff + (int)lcchild->sx &&
|
||||
(int)y >= lcchild->yoff &&
|
||||
(int)y < lcchild->yoff + (int)lcchild->sy) {
|
||||
if ((int)x >= lcchild->g.xoff &&
|
||||
(int)x < lcchild->g.xoff + (int)lcchild->g.sx &&
|
||||
(int)y >= lcchild->g.yoff &&
|
||||
(int)y < lcchild->g.yoff + (int)lcchild->g.sy) {
|
||||
/* Inside the cell - recurse. */
|
||||
return (layout_search_by_border(lcchild, x, y));
|
||||
}
|
||||
@@ -181,13 +178,13 @@ layout_search_by_border(struct layout_cell *lc, u_int x, u_int y)
|
||||
|
||||
switch (lc->type) {
|
||||
case LAYOUT_LEFTRIGHT:
|
||||
if ((int)x < lcchild->xoff &&
|
||||
(int)x >= last->xoff + (int)last->sx)
|
||||
if ((int)x < lcchild->g.xoff &&
|
||||
(int)x >= last->g.xoff + (int)last->g.sx)
|
||||
return (last);
|
||||
break;
|
||||
case LAYOUT_TOPBOTTOM:
|
||||
if ((int)y < lcchild->yoff &&
|
||||
(int)y >= last->yoff + (int)last->sy)
|
||||
if ((int)y < lcchild->g.yoff &&
|
||||
(int)y >= last->g.yoff + (int)last->g.sy)
|
||||
return (last);
|
||||
break;
|
||||
case LAYOUT_WINDOWPANE:
|
||||
@@ -204,11 +201,11 @@ layout_search_by_border(struct layout_cell *lc, u_int x, u_int y)
|
||||
void
|
||||
layout_set_size(struct layout_cell *lc, u_int sx, u_int sy, int xoff, int yoff)
|
||||
{
|
||||
lc->sx = sx;
|
||||
lc->sy = sy;
|
||||
lc->g.sx = sx;
|
||||
lc->g.sy = sy;
|
||||
|
||||
lc->xoff = xoff;
|
||||
lc->yoff = yoff;
|
||||
lc->g.xoff = xoff;
|
||||
lc->g.yoff = yoff;
|
||||
}
|
||||
|
||||
/* Make a cell a leaf cell. */
|
||||
@@ -332,26 +329,26 @@ layout_fix_offsets1(struct layout_cell *lc)
|
||||
int xoff, yoff;
|
||||
|
||||
if (lc->type == LAYOUT_LEFTRIGHT) {
|
||||
xoff = lc->xoff;
|
||||
xoff = lc->g.xoff;
|
||||
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
||||
if (!layout_has_tiled(lcchild))
|
||||
continue;
|
||||
lcchild->xoff = xoff;
|
||||
lcchild->yoff = lc->yoff;
|
||||
lcchild->g.xoff = xoff;
|
||||
lcchild->g.yoff = lc->g.yoff;
|
||||
if (lcchild->type != LAYOUT_WINDOWPANE)
|
||||
layout_fix_offsets1(lcchild);
|
||||
xoff += lcchild->sx + 1;
|
||||
xoff += lcchild->g.sx + 1;
|
||||
}
|
||||
} else {
|
||||
yoff = lc->yoff;
|
||||
yoff = lc->g.yoff;
|
||||
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
||||
if (!layout_has_tiled(lcchild))
|
||||
continue;
|
||||
lcchild->xoff = lc->xoff;
|
||||
lcchild->yoff = yoff;
|
||||
lcchild->g.xoff = lc->g.xoff;
|
||||
lcchild->g.yoff = yoff;
|
||||
if (lcchild->type != LAYOUT_WINDOWPANE)
|
||||
layout_fix_offsets1(lcchild);
|
||||
yoff += lcchild->sy + 1;
|
||||
yoff += lcchild->g.sy + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -366,8 +363,8 @@ layout_fix_offsets(struct window *w)
|
||||
if (lc->flags & LAYOUT_CELL_FLOATING)
|
||||
return;
|
||||
|
||||
lc->xoff = 0;
|
||||
lc->yoff = 0;
|
||||
lc->g.xoff = 0;
|
||||
lc->g.yoff = 0;
|
||||
|
||||
layout_fix_offsets1(lc);
|
||||
}
|
||||
@@ -451,16 +448,17 @@ layout_fix_panes(struct window *w, struct window_pane *skip)
|
||||
old_sx = wp->sx;
|
||||
old_sy = wp->sy;
|
||||
|
||||
wp->xoff = lc->xoff;
|
||||
wp->yoff = lc->yoff;
|
||||
sx = lc->sx;
|
||||
sy = lc->sy;
|
||||
wp->xoff = lc->g.xoff;
|
||||
wp->yoff = lc->g.yoff;
|
||||
sx = lc->g.sx;
|
||||
sy = lc->g.sy;
|
||||
|
||||
if (!window_pane_is_floating(wp) &&
|
||||
layout_add_horizontal_border(w, lc, status)) {
|
||||
if (status == PANE_STATUS_TOP)
|
||||
wp->yoff++;
|
||||
sy--;
|
||||
if (sy > 1)
|
||||
sy--;
|
||||
}
|
||||
|
||||
if (window_pane_scrollbar_reserve(wp)) {
|
||||
@@ -534,14 +532,14 @@ layout_resize_check(struct window *w, struct layout_cell *lc,
|
||||
if (lc->type == LAYOUT_WINDOWPANE) {
|
||||
/* Space available in this cell only. */
|
||||
if (type == LAYOUT_LEFTRIGHT) {
|
||||
available = lc->sx;
|
||||
available = lc->g.sx;
|
||||
if (w->sb == PANE_SCROLLBARS_ALWAYS)
|
||||
minimum = PANE_MINIMUM + sb_style->width +
|
||||
sb_style->pad;
|
||||
else
|
||||
minimum = PANE_MINIMUM;
|
||||
} else {
|
||||
available = lc->sy;
|
||||
available = lc->g.sy;
|
||||
if (layout_add_horizontal_border(w, lc, status))
|
||||
minimum = PANE_MINIMUM + 1;
|
||||
else
|
||||
@@ -579,12 +577,13 @@ layout_resize_adjust(struct window *w, struct layout_cell *lc,
|
||||
enum layout_type type, int change)
|
||||
{
|
||||
struct layout_cell *lcchild;
|
||||
int changed;
|
||||
|
||||
/* Adjust the cell size. */
|
||||
if (type == LAYOUT_LEFTRIGHT)
|
||||
lc->sx += change;
|
||||
lc->g.sx += change;
|
||||
else
|
||||
lc->sy += change;
|
||||
lc->g.sy += change;
|
||||
|
||||
/* If this is a leaf cell, that is all that is necessary. */
|
||||
if (type == LAYOUT_WINDOWPANE)
|
||||
@@ -611,6 +610,7 @@ layout_resize_adjust(struct window *w, struct layout_cell *lc,
|
||||
* until no further change is possible.
|
||||
*/
|
||||
while (change != 0) {
|
||||
changed = 0;
|
||||
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
||||
if (change == 0)
|
||||
break;
|
||||
@@ -619,13 +619,17 @@ layout_resize_adjust(struct window *w, struct layout_cell *lc,
|
||||
if (change > 0) {
|
||||
layout_resize_adjust(w, lcchild, type, 1);
|
||||
change--;
|
||||
changed = 1;
|
||||
continue;
|
||||
}
|
||||
if (layout_resize_check(w, lcchild, type) > 0) {
|
||||
layout_resize_adjust(w, lcchild, type, -1);
|
||||
change++;
|
||||
changed = 1;
|
||||
}
|
||||
}
|
||||
if (!changed)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -637,9 +641,9 @@ layout_resize_set_size(struct window *w, struct layout_cell *lc,
|
||||
int change;
|
||||
|
||||
if (type == LAYOUT_LEFTRIGHT)
|
||||
change = size - lc->sx;
|
||||
change = size - lc->g.sx;
|
||||
else
|
||||
change = size - lc->sy;
|
||||
change = size - lc->g.sy;
|
||||
layout_resize_adjust(w, lc, type, change);
|
||||
}
|
||||
|
||||
@@ -711,9 +715,9 @@ layout_destroy_cell(struct window *w, struct layout_cell *lc,
|
||||
lcother = layout_cell_get_neighbour(lc);
|
||||
if (lcother != NULL) {
|
||||
if (lcparent->type == LAYOUT_LEFTRIGHT)
|
||||
change = lc->sx + 1;
|
||||
change = lc->g.sx + 1;
|
||||
else
|
||||
change = lc->sy + 1;
|
||||
change = lc->g.sy + 1;
|
||||
layout_resize_adjust(w, lcother, lcparent->type, change);
|
||||
} else
|
||||
layout_remove_tile(w, lcparent);
|
||||
@@ -734,8 +738,8 @@ out:
|
||||
lc->parent = lcparent->parent;
|
||||
if (lc->parent == NULL) {
|
||||
if (layout_cell_is_tiled(lc)) {
|
||||
lc->xoff = 0;
|
||||
lc->yoff = 0;
|
||||
lc->g.xoff = 0;
|
||||
lc->g.yoff = 0;
|
||||
}
|
||||
*lcroot = lc;
|
||||
} else
|
||||
@@ -786,29 +790,29 @@ layout_resize(struct window *w, u_int sx, u_int sy)
|
||||
*/
|
||||
if (lc->type == LAYOUT_WINDOWPANE && (lc->flags & LAYOUT_CELL_FLOATING))
|
||||
return;
|
||||
xchange = sx - lc->sx;
|
||||
xchange = sx - lc->g.sx;
|
||||
xlimit = layout_resize_check(w, lc, LAYOUT_LEFTRIGHT);
|
||||
if (xchange < 0 && xchange < -xlimit)
|
||||
xchange = -xlimit;
|
||||
if (xlimit == 0) {
|
||||
if (sx <= lc->sx) /* lc->sx is minimum possible */
|
||||
if (sx <= lc->g.sx) /* lc->g.sx is minimum possible */
|
||||
xchange = 0;
|
||||
else
|
||||
xchange = sx - lc->sx;
|
||||
xchange = sx - lc->g.sx;
|
||||
}
|
||||
if (xchange != 0)
|
||||
layout_resize_adjust(w, lc, LAYOUT_LEFTRIGHT, xchange);
|
||||
|
||||
/* Adjust vertically in a similar fashion. */
|
||||
ychange = sy - lc->sy;
|
||||
ychange = sy - lc->g.sy;
|
||||
ylimit = layout_resize_check(w, lc, LAYOUT_TOPBOTTOM);
|
||||
if (ychange < 0 && ychange < -ylimit)
|
||||
ychange = -ylimit;
|
||||
if (ylimit == 0) {
|
||||
if (sy <= lc->sy) /* lc->sy is minimum possible */
|
||||
if (sy <= lc->g.sy) /* lc->g.sy is minimum possible */
|
||||
ychange = 0;
|
||||
else
|
||||
ychange = sy - lc->sy;
|
||||
ychange = sy - lc->g.sy;
|
||||
}
|
||||
if (ychange != 0)
|
||||
layout_resize_adjust(w, lc, LAYOUT_TOPBOTTOM, ychange);
|
||||
@@ -839,9 +843,9 @@ layout_resize_pane_to(struct window_pane *wp, enum layout_type type,
|
||||
|
||||
/* Work out the size adjustment. */
|
||||
if (type == LAYOUT_LEFTRIGHT)
|
||||
size = lc->sx;
|
||||
size = lc->g.sx;
|
||||
else
|
||||
size = lc->sy;
|
||||
size = lc->g.sy;
|
||||
if (lc == TAILQ_LAST(&lcparent->cells, layout_cells))
|
||||
change = size - new_size;
|
||||
else
|
||||
@@ -872,13 +876,13 @@ layout_resize_floating_pane_to(struct window_pane *wp, enum layout_type type,
|
||||
}
|
||||
|
||||
if (type == LAYOUT_TOPBOTTOM) {
|
||||
if (lc->sy == size)
|
||||
if (lc->g.sy == size)
|
||||
return (0);
|
||||
lc->sy = size;
|
||||
lc->g.sy = size;
|
||||
} else {
|
||||
if (lc->sx == size)
|
||||
if (lc->g.sx == size)
|
||||
return (0);
|
||||
lc->sx = size;
|
||||
lc->g.sx = size;
|
||||
}
|
||||
redraw_invalidate_scene(wp->window);
|
||||
return (0);
|
||||
@@ -900,23 +904,23 @@ layout_resize_floating_pane(struct window_pane *wp, enum layout_type type,
|
||||
return (0);
|
||||
|
||||
if (type == LAYOUT_TOPBOTTOM) {
|
||||
size = lc->sy + change;
|
||||
size = lc->g.sy + change;
|
||||
if (size < PANE_MINIMUM || size > PANE_MAXIMUM) {
|
||||
*cause = xstrdup("change is too big or too small");
|
||||
return (-1);
|
||||
}
|
||||
lc->sy = size;
|
||||
lc->g.sy = size;
|
||||
if (opposite)
|
||||
lc->yoff -= change;
|
||||
lc->g.yoff -= change;
|
||||
} else {
|
||||
size = lc->sx + change;
|
||||
size = lc->g.sx + change;
|
||||
if (size < PANE_MINIMUM || size > PANE_MAXIMUM) {
|
||||
*cause = xstrdup("change is too big or too small");
|
||||
return (-1);
|
||||
}
|
||||
lc->sx = size;
|
||||
lc->g.sx = size;
|
||||
if (opposite)
|
||||
lc->xoff -= change;
|
||||
lc->g.xoff -= change;
|
||||
}
|
||||
redraw_invalidate_scene(wp->window);
|
||||
return (0);
|
||||
@@ -1082,13 +1086,13 @@ layout_new_pane_size(struct window *w, u_int previous, struct layout_cell *lc,
|
||||
*/
|
||||
min = (PANE_MINIMUM + 1) * (count_left - 1);
|
||||
if (type == LAYOUT_LEFTRIGHT) {
|
||||
if (lc->sx - available > min)
|
||||
min = lc->sx - available;
|
||||
new_size = (lc->sx * size) / previous;
|
||||
if (lc->g.sx - available > min)
|
||||
min = lc->g.sx - available;
|
||||
new_size = (lc->g.sx * size) / previous;
|
||||
} else {
|
||||
if (lc->sy - available > min)
|
||||
min = lc->sy - available;
|
||||
new_size = (lc->sy * size) / previous;
|
||||
if (lc->g.sy - available > min)
|
||||
min = lc->g.sy - available;
|
||||
new_size = (lc->g.sy * size) / previous;
|
||||
}
|
||||
|
||||
/* Check against the maximum and minimum size. */
|
||||
@@ -1124,9 +1128,9 @@ layout_set_size_check(struct window *w, struct layout_cell *lc,
|
||||
return (0);
|
||||
|
||||
if (type == LAYOUT_LEFTRIGHT)
|
||||
previous = lc->sx;
|
||||
previous = lc->g.sx;
|
||||
else
|
||||
previous = lc->sy;
|
||||
previous = lc->g.sy;
|
||||
|
||||
idx = 0;
|
||||
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
||||
@@ -1162,31 +1166,31 @@ static void
|
||||
layout_resize_child_cells(struct window *w, struct layout_cell *lc)
|
||||
{
|
||||
struct layout_cell *lcchild;
|
||||
u_int previous, available, count, idx;
|
||||
u_int prev, available, count, idx;
|
||||
|
||||
if (lc->type == LAYOUT_WINDOWPANE)
|
||||
return;
|
||||
|
||||
/* What is the current size used? */
|
||||
count = 0;
|
||||
previous = 0;
|
||||
prev = 0;
|
||||
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
||||
if (!layout_has_tiled(lcchild))
|
||||
continue;
|
||||
count++;
|
||||
if (lc->type == LAYOUT_LEFTRIGHT)
|
||||
previous += lcchild->sx;
|
||||
prev += lcchild->g.sx;
|
||||
else if (lc->type == LAYOUT_TOPBOTTOM)
|
||||
previous += lcchild->sy;
|
||||
prev += lcchild->g.sy;
|
||||
}
|
||||
previous += (count - 1);
|
||||
prev += (count - 1);
|
||||
|
||||
/* And how much is available? */
|
||||
available = 0;
|
||||
if (lc->type == LAYOUT_LEFTRIGHT)
|
||||
available = lc->sx;
|
||||
available = lc->g.sx;
|
||||
else if (lc->type == LAYOUT_TOPBOTTOM)
|
||||
available = lc->sy;
|
||||
available = lc->g.sy;
|
||||
|
||||
/* Resize children into the new size. */
|
||||
idx = 0;
|
||||
@@ -1194,20 +1198,20 @@ layout_resize_child_cells(struct window *w, struct layout_cell *lc)
|
||||
if (!layout_has_tiled(lcchild))
|
||||
continue;
|
||||
if (lc->type == LAYOUT_TOPBOTTOM) {
|
||||
lcchild->sx = lc->sx;
|
||||
lcchild->xoff = lc->xoff;
|
||||
lcchild->g.sx = lc->g.sx;
|
||||
lcchild->g.xoff = lc->g.xoff;
|
||||
} else {
|
||||
lcchild->sx = layout_new_pane_size(w, previous, lcchild,
|
||||
lc->type, lc->sx, count - idx, available);
|
||||
available -= (lcchild->sx + 1);
|
||||
lcchild->g.sx = layout_new_pane_size(w, prev, lcchild,
|
||||
lc->type, lc->g.sx, count - idx, available);
|
||||
available -= (lcchild->g.sx + 1);
|
||||
}
|
||||
if (lc->type == LAYOUT_LEFTRIGHT) {
|
||||
lcchild->sy = lc->sy;
|
||||
lcchild->yoff = lc->yoff;
|
||||
lcchild->g.sy = lc->g.sy;
|
||||
lcchild->g.yoff = lc->g.yoff;
|
||||
} else {
|
||||
lcchild->sy = layout_new_pane_size(w, previous, lcchild,
|
||||
lc->type, lc->sy, count - idx, available);
|
||||
available -= (lcchild->sy + 1);
|
||||
lcchild->g.sy = layout_new_pane_size(w, prev, lcchild,
|
||||
lc->type, lc->g.sy, count - idx, available);
|
||||
available -= (lcchild->g.sy + 1);
|
||||
}
|
||||
layout_resize_child_cells(w, lcchild);
|
||||
idx++;
|
||||
@@ -1227,7 +1231,7 @@ layout_replace_with_node(struct window *w, struct layout_cell *lc,
|
||||
|
||||
lcparent = layout_create_cell(lc->parent);
|
||||
layout_make_node(lcparent, type);
|
||||
layout_set_size(lcparent, lc->sx, lc->sy, lc->xoff, lc->yoff);
|
||||
layout_set_size(lcparent, lc->g.sx, lc->g.sy, lc->g.xoff, lc->g.yoff);
|
||||
if (lc->parent == NULL)
|
||||
w->layout_root = lcparent;
|
||||
else
|
||||
@@ -1246,7 +1250,7 @@ layout_split_check_space(struct window_pane *wp, struct layout_cell *lc,
|
||||
enum layout_type type)
|
||||
{
|
||||
struct style *sb_style = &wp->scrollbar_style;
|
||||
u_int minimum, sx = lc->sx, sy = lc->sy;
|
||||
u_int minimum, sx = lc->g.sx, sy = lc->g.sy;
|
||||
int status;
|
||||
|
||||
if (lc->flags & LAYOUT_CELL_FLOATING)
|
||||
@@ -1285,7 +1289,7 @@ layout_split_sizes(struct layout_cell *lc, int size, int before,
|
||||
enum layout_type type, u_int *size1, u_int *size2, u_int *saved_size)
|
||||
{
|
||||
u_int s1, s2, ss;
|
||||
u_int sx = lc->sx, sy = lc->sy;
|
||||
u_int sx = lc->g.sx, sy = lc->g.sy;
|
||||
|
||||
if (type == LAYOUT_LEFTRIGHT)
|
||||
ss = sx;
|
||||
@@ -1332,10 +1336,10 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
|
||||
lc = wp->layout_cell;
|
||||
|
||||
/* Copy the old cell size. */
|
||||
sx = lc->sx;
|
||||
sy = lc->sy;
|
||||
xoff = lc->xoff;
|
||||
yoff = lc->yoff;
|
||||
sx = lc->g.sx;
|
||||
sy = lc->g.sy;
|
||||
xoff = lc->g.xoff;
|
||||
yoff = lc->g.yoff;
|
||||
|
||||
/* Check there is enough space for the two new panes. */
|
||||
if (!layout_split_check_space(wp, lc, type))
|
||||
@@ -1376,13 +1380,13 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
|
||||
* must be resized before inserting the new cell.
|
||||
*/
|
||||
if (lc->type == LAYOUT_LEFTRIGHT) {
|
||||
lc->sx = new_size;
|
||||
lc->g.sx = new_size;
|
||||
layout_resize_child_cells(wp->window, lc);
|
||||
lc->sx = saved_size;
|
||||
lc->g.sx = saved_size;
|
||||
} else if (lc->type == LAYOUT_TOPBOTTOM) {
|
||||
lc->sy = new_size;
|
||||
lc->g.sy = new_size;
|
||||
layout_resize_child_cells(wp->window, lc);
|
||||
lc->sy = saved_size;
|
||||
lc->g.sy = saved_size;
|
||||
}
|
||||
resize_first = 1;
|
||||
|
||||
@@ -1426,10 +1430,10 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
|
||||
*/
|
||||
if (!resize_first && type == LAYOUT_LEFTRIGHT) {
|
||||
layout_set_size(lc1, size1, sy, xoff, yoff);
|
||||
layout_set_size(lc2, size2, sy, xoff + lc1->sx + 1, yoff);
|
||||
layout_set_size(lc2, size2, sy, xoff + lc1->g.sx + 1, yoff);
|
||||
} else if (!resize_first && type == LAYOUT_TOPBOTTOM) {
|
||||
layout_set_size(lc1, sx, size1, xoff, yoff);
|
||||
layout_set_size(lc2, sx, size2, xoff, yoff + lc1->sy + 1);
|
||||
layout_set_size(lc2, sx, size2, xoff, yoff + lc1->g.sy + 1);
|
||||
}
|
||||
if (full_size) {
|
||||
if (!resize_first)
|
||||
@@ -1446,8 +1450,8 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
|
||||
* layout_assign_pane before much else happens!
|
||||
*/
|
||||
struct layout_cell *
|
||||
layout_floating_pane(struct window *w, struct window_pane *wp, u_int sx,
|
||||
u_int sy, int ox, int oy)
|
||||
layout_floating_pane(struct window *w, struct window_pane *wp,
|
||||
struct layout_geometry *lg)
|
||||
{
|
||||
struct layout_cell *lc, *lcnew, *lcparent;
|
||||
|
||||
@@ -1459,16 +1463,16 @@ layout_floating_pane(struct window *w, struct window_pane *wp, u_int sx,
|
||||
|
||||
if (lcparent == NULL) {
|
||||
/*
|
||||
* Adding a pane to a root that isn't node. Must create and
|
||||
* insert a new root.
|
||||
*/
|
||||
* Adding a pane to a root that isn't a node. Must create and
|
||||
* insert a new root.
|
||||
*/
|
||||
lcparent = layout_replace_with_node(w, lc, LAYOUT_TOPBOTTOM);
|
||||
}
|
||||
|
||||
lcnew = layout_create_cell(lcparent);
|
||||
TAILQ_INSERT_AFTER(&lcparent->cells, lc, lcnew, entry);
|
||||
lcnew->flags |= LAYOUT_CELL_FLOATING;
|
||||
layout_set_size(lcnew, sx, sy, ox, oy);
|
||||
layout_set_size(lcnew, lg->sx, lg->sy, lg->xoff, lg->yoff);
|
||||
|
||||
return (lcnew);
|
||||
}
|
||||
@@ -1511,12 +1515,12 @@ layout_spread_cell(struct window *w, struct layout_cell *parent)
|
||||
status = window_get_pane_status(w);
|
||||
|
||||
if (parent->type == LAYOUT_LEFTRIGHT)
|
||||
size = parent->sx;
|
||||
size = parent->g.sx;
|
||||
else if (parent->type == LAYOUT_TOPBOTTOM) {
|
||||
if (layout_add_horizontal_border(w, parent, status))
|
||||
size = parent->sy - 1;
|
||||
size = parent->g.sy - 1;
|
||||
else
|
||||
size = parent->sy;
|
||||
size = parent->g.sy;
|
||||
} else
|
||||
return (0);
|
||||
if (size < number - 1)
|
||||
@@ -1537,7 +1541,7 @@ layout_spread_cell(struct window *w, struct layout_cell *parent)
|
||||
continue;
|
||||
change = 0;
|
||||
if (parent->type == LAYOUT_LEFTRIGHT) {
|
||||
change = each - (int)lc->sx;
|
||||
change = each - (int)lc->g.sx;
|
||||
if (remainder > 0) {
|
||||
change++;
|
||||
remainder--;
|
||||
@@ -1552,7 +1556,7 @@ layout_spread_cell(struct window *w, struct layout_cell *parent)
|
||||
this++;
|
||||
remainder--;
|
||||
}
|
||||
change = this - (int)lc->sy;
|
||||
change = this - (int)lc->g.sy;
|
||||
layout_resize_adjust(w, lc, LAYOUT_TOPBOTTOM, change);
|
||||
}
|
||||
if (change != 0)
|
||||
@@ -1649,29 +1653,29 @@ layout_get_floating_cell(struct cmdq_item *item, struct args *args,
|
||||
char **cause)
|
||||
{
|
||||
struct layout_cell *lcnew;
|
||||
u_int sx = UINT_MAX, sy = UINT_MAX;
|
||||
int ox = INT_MAX, oy = INT_MAX;
|
||||
struct layout_geometry fg;
|
||||
|
||||
if (layout_floating_args_parse(item, args, lines, w, &sx, &sy, &ox, &oy,
|
||||
cause) != 0)
|
||||
layout_geometry_init(&fg);
|
||||
if (layout_floating_args_parse(item, args, lines, w, &fg, cause) != 0)
|
||||
return (NULL);
|
||||
|
||||
lcnew = layout_floating_pane(w, wp, sx, sy, ox, oy);
|
||||
window_push_zoom(wp->window, 1, args_has(args, 'Z'));
|
||||
lcnew = layout_floating_pane(w, wp, &fg);
|
||||
return (lcnew);
|
||||
}
|
||||
|
||||
int
|
||||
layout_floating_args_parse(struct cmdq_item *item, struct args *args,
|
||||
enum pane_lines lines, struct window *w, u_int *sxp, u_int *syp, int *oxp,
|
||||
int *oyp, char **cause)
|
||||
enum pane_lines lines, struct window *w, struct layout_geometry *lg,
|
||||
char **cause)
|
||||
{
|
||||
int sx, sy, ox, oy;
|
||||
char *error = NULL;
|
||||
|
||||
sx = *sxp == UINT_MAX ? w->sx / 2 : *sxp;
|
||||
sy = *syp == UINT_MAX ? w->sy / 4 : *syp;
|
||||
ox = *oxp == INT_MAX ? INT_MAX : *oxp;
|
||||
oy = *oyp == INT_MAX ? INT_MAX : *oyp;
|
||||
sx = lg->sx == UINT_MAX ? w->sx / 2 : lg->sx;
|
||||
sy = lg->sy == UINT_MAX ? w->sy / 4 : lg->sy;
|
||||
ox = lg->xoff;
|
||||
oy = lg->yoff;
|
||||
|
||||
if (args_has(args, 'x')) {
|
||||
sx = args_percentage_and_expand(args, 'x', 0, PANE_MAXIMUM,
|
||||
@@ -1748,10 +1752,10 @@ layout_floating_args_parse(struct cmdq_item *item, struct args *args,
|
||||
return (-1);
|
||||
}
|
||||
|
||||
*sxp = sx;
|
||||
*syp = sy;
|
||||
*oxp = ox;
|
||||
*oyp = oy;
|
||||
lg->sx = sx;
|
||||
lg->sy = sy;
|
||||
lg->xoff = ox;
|
||||
lg->yoff = oy;
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -1780,9 +1784,9 @@ layout_remove_tile(struct window *w, struct layout_cell *lc)
|
||||
* neighbour.
|
||||
*/
|
||||
if (type == LAYOUT_TOPBOTTOM)
|
||||
change = lc->sy + 1;
|
||||
change = lc->g.sy + 1;
|
||||
else
|
||||
change = lc->sx + 1;
|
||||
change = lc->g.sx + 1;
|
||||
layout_resize_adjust(w, lcneighbour, type, change);
|
||||
}
|
||||
|
||||
@@ -1828,9 +1832,9 @@ layout_insert_tile(struct window *w, struct layout_cell *lc)
|
||||
*/
|
||||
layout_insert_tile(w, lcparent);
|
||||
if (type == LAYOUT_LEFTRIGHT)
|
||||
size1 = lcparent->sx;
|
||||
size1 = lcparent->g.sx;
|
||||
else
|
||||
size1 = lcparent->sy;
|
||||
size1 = lcparent->g.sy;
|
||||
layout_resize_set_size(w, lc, type, size1);
|
||||
} else {
|
||||
/*
|
||||
@@ -1848,10 +1852,10 @@ layout_insert_tile(struct window *w, struct layout_cell *lc)
|
||||
|
||||
/* Setting opposite of the 'split' size to that of the parent. */
|
||||
if (lcparent->type == LAYOUT_LEFTRIGHT) {
|
||||
size1 = lcparent->sy;
|
||||
size1 = lcparent->g.sy;
|
||||
type = LAYOUT_TOPBOTTOM;
|
||||
} else {
|
||||
size1 = lcparent->sx;
|
||||
size1 = lcparent->g.sx;
|
||||
type = LAYOUT_LEFTRIGHT;
|
||||
}
|
||||
layout_resize_set_size(w, lc, type, size1);
|
||||
|
||||
17
menu.c
17
menu.c
@@ -313,6 +313,7 @@ menu_key_cb(struct client *c, void *data, struct key_event *event)
|
||||
struct mouse_event *m = &event->m;
|
||||
u_int i;
|
||||
int count = menu->count, old = md->choice;
|
||||
int move;
|
||||
const char *name = NULL;
|
||||
const struct menu_item *item;
|
||||
struct cmdq_state *state;
|
||||
@@ -320,6 +321,14 @@ menu_key_cb(struct client *c, void *data, struct key_event *event)
|
||||
char *error;
|
||||
|
||||
if (KEYC_IS_MOUSE(event->key)) {
|
||||
/*
|
||||
* A mouse move with no button held reports as a release, so
|
||||
* treat it as highlight-only: it must never select or close the
|
||||
* menu, otherwise a menu opened without a button already down
|
||||
* (such as a submenu opened from another menu) would vanish as
|
||||
* soon as the mouse moved over it.
|
||||
*/
|
||||
move = MOUSE_DRAG(m->b) && MOUSE_RELEASE(m->b);
|
||||
if (md->flags & MENU_NOMOUSE) {
|
||||
if (MOUSE_BUTTONS(m->b) != MOUSE_BUTTON_1)
|
||||
return (1);
|
||||
@@ -330,7 +339,7 @@ menu_key_cb(struct client *c, void *data, struct key_event *event)
|
||||
m->y < md->py + 1 ||
|
||||
m->y > md->py + 1 + count - 1) {
|
||||
if (~md->flags & MENU_STAYOPEN) {
|
||||
if (MOUSE_RELEASE(m->b))
|
||||
if (!move && MOUSE_RELEASE(m->b))
|
||||
return (1);
|
||||
} else {
|
||||
if (!MOUSE_RELEASE(m->b) &&
|
||||
@@ -345,7 +354,7 @@ menu_key_cb(struct client *c, void *data, struct key_event *event)
|
||||
return (0);
|
||||
}
|
||||
if (~md->flags & MENU_STAYOPEN) {
|
||||
if (MOUSE_RELEASE(m->b))
|
||||
if (!move && MOUSE_RELEASE(m->b))
|
||||
goto chosen;
|
||||
} else {
|
||||
if (!MOUSE_WHEEL(m->b) && !MOUSE_DRAG(m->b))
|
||||
@@ -558,6 +567,10 @@ menu_prepare(struct menu *menu, int flags, int starting_choice,
|
||||
if (py + menu->count + 2 > c->tty.sy)
|
||||
py = c->tty.sy - menu->count - 2;
|
||||
|
||||
/* Remember where this menu is so -x/-y L can reuse the position. */
|
||||
c->menu_last_px = px;
|
||||
c->menu_last_py = py;
|
||||
|
||||
if (lines == BOX_LINES_DEFAULT)
|
||||
lines = options_get_number(o, "menu-border-lines");
|
||||
|
||||
|
||||
@@ -834,6 +834,11 @@ mode_tree_draw(struct mode_tree_data *mtd)
|
||||
if (mtd->line_size == 0)
|
||||
return;
|
||||
|
||||
w = mtd->width;
|
||||
h = mtd->height;
|
||||
if (w == 0 || h == 0)
|
||||
return;
|
||||
|
||||
memcpy(&gc0, &grid_default_cell, sizeof gc0);
|
||||
memcpy(&gc, &grid_default_cell, sizeof gc);
|
||||
style_apply(&gc, oo, "tree-mode-selection-style", NULL);
|
||||
@@ -843,9 +848,6 @@ mode_tree_draw(struct mode_tree_data *mtd)
|
||||
dfg = gc.fg;
|
||||
dfg0 = gc0.fg;
|
||||
|
||||
w = mtd->width;
|
||||
h = mtd->height;
|
||||
|
||||
screen_write_start(&ctx, s);
|
||||
screen_write_clearscreen(&ctx, 8);
|
||||
ft = format_create_defaults(NULL, NULL, NULL, NULL, wp);
|
||||
|
||||
22
monitor.c
22
monitor.c
@@ -93,6 +93,18 @@ monitor_get_session(struct monitor_set *ms)
|
||||
return (s);
|
||||
}
|
||||
|
||||
/* Create a format tree for a subscription. */
|
||||
static struct format_tree *
|
||||
monitor_create_formats(struct client *c, struct session *s, struct winlink *wl,
|
||||
struct window_pane *wp)
|
||||
{
|
||||
struct format_tree *ft;
|
||||
|
||||
ft = format_create(NULL, NULL, 0, FORMAT_NOJOBS);
|
||||
format_defaults(ft, c, s, wl, wp);
|
||||
return (ft);
|
||||
}
|
||||
|
||||
/* Compare subscriptions. */
|
||||
static int
|
||||
monitor_item_cmp(struct monitor_item *m1, struct monitor_item *m2)
|
||||
@@ -236,7 +248,7 @@ monitor_check_pane(struct monitor_set *ms, struct monitor_item *me)
|
||||
if (wl->session != s)
|
||||
continue;
|
||||
|
||||
ft = format_create_defaults(NULL, c, s, wl, wp);
|
||||
ft = monitor_create_formats(c, s, wl, wp);
|
||||
value = format_expand(ft, me->format);
|
||||
format_free(ft);
|
||||
|
||||
@@ -314,7 +326,7 @@ monitor_check_window(struct monitor_set *ms, struct monitor_item *me)
|
||||
if (wl->session != s)
|
||||
continue;
|
||||
|
||||
ft = format_create_defaults(NULL, c, s, wl, NULL);
|
||||
ft = monitor_create_formats(c, s, wl, NULL);
|
||||
value = format_expand(ft, me->format);
|
||||
format_free(ft);
|
||||
|
||||
@@ -382,7 +394,7 @@ monitor_check_sessions(struct monitor_set *ms)
|
||||
struct monitor_item *me, *me1;
|
||||
struct format_tree *ft;
|
||||
|
||||
ft = format_create_defaults(NULL, c, s, NULL, NULL);
|
||||
ft = monitor_create_formats(c, s, NULL, NULL);
|
||||
RB_FOREACH_SAFE(me, monitor_items, &ms->items, me1) {
|
||||
if (me->type == MONITOR_SESSION)
|
||||
monitor_check_session(ms, me, ft);
|
||||
@@ -427,7 +439,7 @@ monitor_check_all_panes(struct monitor_set *ms)
|
||||
ms->generation = 1;
|
||||
RB_FOREACH(wl, winlinks, &s->windows) {
|
||||
TAILQ_FOREACH(wp, &wl->window->panes, entry) {
|
||||
ft = format_create_defaults(NULL, c, s, wl, wp);
|
||||
ft = monitor_create_formats(c, s, wl, wp);
|
||||
RB_FOREACH_SAFE(me, monitor_items, &ms->items, me1) {
|
||||
if (me->type != MONITOR_ALL_PANES)
|
||||
continue;
|
||||
@@ -455,7 +467,7 @@ monitor_check_all_windows(struct monitor_set *ms)
|
||||
if (++ms->generation == 0)
|
||||
ms->generation = 1;
|
||||
RB_FOREACH(wl, winlinks, &s->windows) {
|
||||
ft = format_create_defaults(NULL, c, s, wl, NULL);
|
||||
ft = monitor_create_formats(c, s, wl, NULL);
|
||||
RB_FOREACH_SAFE(me, monitor_items, &ms->items, me1) {
|
||||
if (me->type != MONITOR_ALL_WINDOWS)
|
||||
continue;
|
||||
|
||||
207
options.c
207
options.c
@@ -32,18 +32,69 @@
|
||||
*/
|
||||
|
||||
struct options_array_item {
|
||||
u_int index;
|
||||
char *key;
|
||||
union options_value value;
|
||||
RB_ENTRY(options_array_item) entry;
|
||||
};
|
||||
|
||||
static int
|
||||
options_array_key_to_number(const char *key, u_int *idx)
|
||||
{
|
||||
const char *errstr;
|
||||
long long n;
|
||||
|
||||
if (*key == '\0')
|
||||
return (-1);
|
||||
for (const char *cp = key; *cp != '\0'; cp++) {
|
||||
if (!isdigit((u_char)*cp))
|
||||
return (0);
|
||||
}
|
||||
|
||||
n = strtonum(key, 0, UINT_MAX, &errstr);
|
||||
if (errstr != NULL)
|
||||
return (-1);
|
||||
if (idx != NULL)
|
||||
*idx = n;
|
||||
return (1);
|
||||
}
|
||||
|
||||
static char *
|
||||
options_array_correct_key(const char *key)
|
||||
{
|
||||
u_int idx;
|
||||
int numeric;
|
||||
char *out;
|
||||
|
||||
numeric = options_array_key_to_number(key, &idx);
|
||||
if (numeric == -1)
|
||||
return (NULL);
|
||||
if (numeric == 1) {
|
||||
xasprintf(&out, "%u", idx);
|
||||
return (out);
|
||||
}
|
||||
return (xstrdup(key));
|
||||
}
|
||||
|
||||
static int
|
||||
options_array_cmp(struct options_array_item *a1, struct options_array_item *a2)
|
||||
{
|
||||
if (a1->index < a2->index)
|
||||
u_int i1, i2;
|
||||
int n1, n2;
|
||||
|
||||
n1 = options_array_key_to_number(a1->key, &i1);
|
||||
n2 = options_array_key_to_number(a2->key, &i2);
|
||||
if (n1 && n2) {
|
||||
if (i1 < i2)
|
||||
return (-1);
|
||||
if (i1 > i2)
|
||||
return (1);
|
||||
return (0);
|
||||
}
|
||||
if (n1)
|
||||
return (-1);
|
||||
if (a1->index > a2->index)
|
||||
if (n2)
|
||||
return (1);
|
||||
return (0);
|
||||
return (strcmp(a1->key, a2->key));
|
||||
}
|
||||
RB_GENERATE_STATIC(options_array, options_array_item, entry, options_array_cmp);
|
||||
|
||||
@@ -260,6 +311,7 @@ options_default(struct options *oo, const struct options_table_entry *oe)
|
||||
{
|
||||
struct options_entry *o;
|
||||
union options_value *ov;
|
||||
char key[32];
|
||||
u_int i;
|
||||
struct cmd_parse_result *pr;
|
||||
|
||||
@@ -271,8 +323,10 @@ options_default(struct options *oo, const struct options_table_entry *oe)
|
||||
options_array_assign(o, oe->default_str, NULL);
|
||||
return (o);
|
||||
}
|
||||
for (i = 0; oe->default_arr[i] != NULL; i++)
|
||||
options_array_set(o, i, oe->default_arr[i], 0, NULL);
|
||||
for (i = 0; oe->default_arr[i] != NULL; i++) {
|
||||
xsnprintf(key, sizeof key, "%u", i);
|
||||
options_array_set(o, key, oe->default_arr[i], 0, NULL);
|
||||
}
|
||||
return (o);
|
||||
}
|
||||
|
||||
@@ -393,21 +447,21 @@ options_table_entry(struct options_entry *o)
|
||||
}
|
||||
|
||||
static struct options_array_item *
|
||||
options_array_item(struct options_entry *o, u_int idx)
|
||||
options_array_item(struct options_entry *o, const char *key)
|
||||
{
|
||||
struct options_array_item a;
|
||||
|
||||
a.index = idx;
|
||||
a.key = (char *)key;
|
||||
return (RB_FIND(options_array, &o->value.array, &a));
|
||||
}
|
||||
|
||||
static struct options_array_item *
|
||||
options_array_new(struct options_entry *o, u_int idx)
|
||||
options_array_new(struct options_entry *o, const char *key)
|
||||
{
|
||||
struct options_array_item *a;
|
||||
|
||||
a = xcalloc(1, sizeof *a);
|
||||
a->index = idx;
|
||||
a->key = xstrdup(key);
|
||||
RB_INSERT(options_array, &o->value.array, a);
|
||||
return (a);
|
||||
}
|
||||
@@ -417,6 +471,7 @@ options_array_free(struct options_entry *o, struct options_array_item *a)
|
||||
{
|
||||
options_value_free(o, &a->value);
|
||||
RB_REMOVE(options_array, &o->value.array, a);
|
||||
free(a->key);
|
||||
free(a);
|
||||
}
|
||||
|
||||
@@ -433,24 +488,45 @@ options_array_clear(struct options_entry *o)
|
||||
}
|
||||
|
||||
union options_value *
|
||||
options_array_get(struct options_entry *o, u_int idx)
|
||||
options_array_get(struct options_entry *o, const char *key)
|
||||
{
|
||||
struct options_array_item *a;
|
||||
char *new_key;
|
||||
|
||||
if (!OPTIONS_IS_ARRAY(o))
|
||||
return (NULL);
|
||||
a = options_array_item(o, idx);
|
||||
new_key = options_array_correct_key(key);
|
||||
if (new_key == NULL)
|
||||
return (NULL);
|
||||
a = options_array_item(o, new_key);
|
||||
free(new_key);
|
||||
if (a == NULL)
|
||||
return (NULL);
|
||||
return (&a->value);
|
||||
}
|
||||
|
||||
union options_value *
|
||||
options_array_getv(struct options_entry *o, const char *fmt, ...)
|
||||
{
|
||||
union options_value *ov;
|
||||
va_list ap;
|
||||
char *key;
|
||||
|
||||
va_start(ap, fmt);
|
||||
xvasprintf(&key, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
ov = options_array_get(o, key);
|
||||
free(key);
|
||||
return (ov);
|
||||
}
|
||||
|
||||
int
|
||||
options_array_set(struct options_entry *o, u_int idx, const char *value,
|
||||
options_array_set(struct options_entry *o, const char *key, const char *value,
|
||||
int append, char **cause)
|
||||
{
|
||||
struct options_array_item *a;
|
||||
char *new;
|
||||
char *new, *new_key;
|
||||
struct cmd_parse_result *pr;
|
||||
long long number;
|
||||
|
||||
@@ -460,10 +536,18 @@ options_array_set(struct options_entry *o, u_int idx, const char *value,
|
||||
return (-1);
|
||||
}
|
||||
|
||||
new_key = options_array_correct_key(key);
|
||||
if (new_key == NULL) {
|
||||
if (cause != NULL)
|
||||
xasprintf(cause, "bad array key: %s", key);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (value == NULL) {
|
||||
a = options_array_item(o, idx);
|
||||
a = options_array_item(o, new_key);
|
||||
if (a != NULL)
|
||||
options_array_free(o, a);
|
||||
free(new_key);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -475,50 +559,56 @@ options_array_set(struct options_entry *o, u_int idx, const char *value,
|
||||
*cause = pr->error;
|
||||
else
|
||||
free(pr->error);
|
||||
free(new_key);
|
||||
return (-1);
|
||||
case CMD_PARSE_SUCCESS:
|
||||
break;
|
||||
}
|
||||
|
||||
a = options_array_item(o, idx);
|
||||
a = options_array_item(o, new_key);
|
||||
if (a == NULL)
|
||||
a = options_array_new(o, idx);
|
||||
a = options_array_new(o, new_key);
|
||||
else
|
||||
options_value_free(o, &a->value);
|
||||
a->value.cmdlist = pr->cmdlist;
|
||||
free(new_key);
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (OPTIONS_IS_STRING(o)) {
|
||||
a = options_array_item(o, idx);
|
||||
a = options_array_item(o, new_key);
|
||||
if (a != NULL && append)
|
||||
xasprintf(&new, "%s%s", a->value.string, value);
|
||||
else
|
||||
new = xstrdup(value);
|
||||
if (a == NULL)
|
||||
a = options_array_new(o, idx);
|
||||
a = options_array_new(o, new_key);
|
||||
else
|
||||
options_value_free(o, &a->value);
|
||||
a->value.string = new;
|
||||
free(new_key);
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (o->tableentry->type == OPTIONS_TABLE_COLOUR) {
|
||||
if ((number = colour_fromstring(value)) == -1) {
|
||||
xasprintf(cause, "bad colour: %s", value);
|
||||
free(new_key);
|
||||
return (-1);
|
||||
}
|
||||
a = options_array_item(o, idx);
|
||||
a = options_array_item(o, new_key);
|
||||
if (a == NULL)
|
||||
a = options_array_new(o, idx);
|
||||
a = options_array_new(o, new_key);
|
||||
else
|
||||
options_value_free(o, &a->value);
|
||||
a->value.number = number;
|
||||
free(new_key);
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (cause != NULL)
|
||||
*cause = xstrdup("wrong array type");
|
||||
free(new_key);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
@@ -527,6 +617,7 @@ options_array_assign(struct options_entry *o, const char *s, char **cause)
|
||||
{
|
||||
const char *separator;
|
||||
char *copy, *next, *string;
|
||||
char key[32];
|
||||
u_int i;
|
||||
|
||||
separator = o->tableentry->separator;
|
||||
@@ -536,10 +627,11 @@ options_array_assign(struct options_entry *o, const char *s, char **cause)
|
||||
if (*s == '\0')
|
||||
return (0);
|
||||
for (i = 0; i < UINT_MAX; i++) {
|
||||
if (options_array_item(o, i) == NULL)
|
||||
if (options_array_getv(o, "%u", i) == NULL)
|
||||
break;
|
||||
}
|
||||
return (options_array_set(o, i, s, 0, cause));
|
||||
xsnprintf(key, sizeof key, "%u", i);
|
||||
return (options_array_set(o, key, s, 0, cause));
|
||||
}
|
||||
|
||||
if (*s == '\0')
|
||||
@@ -549,12 +641,13 @@ options_array_assign(struct options_entry *o, const char *s, char **cause)
|
||||
if (*next == '\0')
|
||||
continue;
|
||||
for (i = 0; i < UINT_MAX; i++) {
|
||||
if (options_array_item(o, i) == NULL)
|
||||
if (options_array_getv(o, "%u", i) == NULL)
|
||||
break;
|
||||
}
|
||||
if (i == UINT_MAX)
|
||||
break;
|
||||
if (options_array_set(o, i, next, 0, cause) != 0) {
|
||||
xsnprintf(key, sizeof key, "%u", i);
|
||||
if (options_array_set(o, key, next, 0, cause) != 0) {
|
||||
free(copy);
|
||||
return (-1);
|
||||
}
|
||||
@@ -574,13 +667,13 @@ options_array_first(struct options_entry *o)
|
||||
struct options_array_item *
|
||||
options_array_next(struct options_array_item *a)
|
||||
{
|
||||
return (RB_NEXT(options_array, &o->value.array, a));
|
||||
return (RB_NEXT(options_array, , a));
|
||||
}
|
||||
|
||||
u_int
|
||||
options_array_item_index(struct options_array_item *a)
|
||||
const char *
|
||||
options_array_item_key(struct options_array_item *a)
|
||||
{
|
||||
return (a->index);
|
||||
return (a->key);
|
||||
}
|
||||
|
||||
union options_value *
|
||||
@@ -602,15 +695,16 @@ options_is_string(struct options_entry *o)
|
||||
}
|
||||
|
||||
char *
|
||||
options_to_string(struct options_entry *o, int idx, int numeric)
|
||||
options_to_string(struct options_entry *o, const char *key, int numeric)
|
||||
{
|
||||
struct options_array_item *a;
|
||||
char *result = NULL;
|
||||
char *last = NULL;
|
||||
char *next;
|
||||
char *new_key;
|
||||
|
||||
if (OPTIONS_IS_ARRAY(o)) {
|
||||
if (idx == -1) {
|
||||
if (key == NULL) {
|
||||
RB_FOREACH(a, options_array, &o->value.array) {
|
||||
next = options_value_to_string(o, &a->value,
|
||||
numeric);
|
||||
@@ -627,7 +721,11 @@ options_to_string(struct options_entry *o, int idx, int numeric)
|
||||
return (xstrdup(""));
|
||||
return (result);
|
||||
}
|
||||
a = options_array_item(o, idx);
|
||||
new_key = options_array_correct_key(key);
|
||||
if (new_key == NULL)
|
||||
return (xstrdup(""));
|
||||
a = options_array_item(o, new_key);
|
||||
free(new_key);
|
||||
if (a == NULL)
|
||||
return (xstrdup(""));
|
||||
return (options_value_to_string(o, &a->value, numeric));
|
||||
@@ -636,37 +734,41 @@ options_to_string(struct options_entry *o, int idx, int numeric)
|
||||
}
|
||||
|
||||
char *
|
||||
options_parse(const char *name, int *idx)
|
||||
options_parse(const char *name, char **key)
|
||||
{
|
||||
char *copy, *cp, *end;
|
||||
char *copy, *cp, *end, *raw, *new_key;
|
||||
|
||||
if (*name == '\0')
|
||||
return (NULL);
|
||||
*key = NULL;
|
||||
copy = xstrdup(name);
|
||||
if ((cp = strchr(copy, '[')) == NULL) {
|
||||
*idx = -1;
|
||||
return (copy);
|
||||
}
|
||||
end = strchr(cp + 1, ']');
|
||||
if (end == NULL || end[1] != '\0' || !isdigit((u_char)end[-1])) {
|
||||
if (end == NULL || end[1] != '\0' || end == cp + 1) {
|
||||
free(copy);
|
||||
return (NULL);
|
||||
}
|
||||
if (sscanf(cp, "[%d]", idx) != 1 || *idx < 0) {
|
||||
raw = xstrndup(cp + 1, end - (cp + 1));
|
||||
new_key = options_array_correct_key(raw);
|
||||
free(raw);
|
||||
if (new_key == NULL) {
|
||||
free(copy);
|
||||
return (NULL);
|
||||
}
|
||||
*key = new_key;
|
||||
*cp = '\0';
|
||||
return (copy);
|
||||
}
|
||||
|
||||
struct options_entry *
|
||||
options_parse_get(struct options *oo, const char *s, int *idx, int only)
|
||||
options_parse_get(struct options *oo, const char *s, char **key, int only)
|
||||
{
|
||||
struct options_entry *o;
|
||||
char *name;
|
||||
|
||||
name = options_parse(s, idx);
|
||||
name = options_parse(s, key);
|
||||
if (name == NULL)
|
||||
return (NULL);
|
||||
if (only)
|
||||
@@ -674,6 +776,10 @@ options_parse_get(struct options *oo, const char *s, int *idx, int only)
|
||||
else
|
||||
o = options_get(oo, name);
|
||||
free(name);
|
||||
if (o == NULL) {
|
||||
free(*key);
|
||||
*key = NULL;
|
||||
}
|
||||
return (o);
|
||||
}
|
||||
|
||||
@@ -690,14 +796,14 @@ options_search(const char *name)
|
||||
}
|
||||
|
||||
char *
|
||||
options_match(const char *s, int *idx, int *ambiguous)
|
||||
options_match(const char *s, char **key, int *ambiguous)
|
||||
{
|
||||
const struct options_table_entry *oe, *found;
|
||||
char *parsed;
|
||||
const char *name;
|
||||
size_t namelen;
|
||||
|
||||
parsed = options_parse(s, idx);
|
||||
parsed = options_parse(s, key);
|
||||
if (parsed == NULL)
|
||||
return (NULL);
|
||||
if (*parsed == '@') {
|
||||
@@ -718,6 +824,8 @@ options_match(const char *s, int *idx, int *ambiguous)
|
||||
if (found != NULL) {
|
||||
*ambiguous = 1;
|
||||
free(parsed);
|
||||
free(*key);
|
||||
*key = NULL;
|
||||
return (NULL);
|
||||
}
|
||||
found = oe;
|
||||
@@ -726,19 +834,21 @@ options_match(const char *s, int *idx, int *ambiguous)
|
||||
free(parsed);
|
||||
if (found == NULL) {
|
||||
*ambiguous = 0;
|
||||
free(*key);
|
||||
*key = NULL;
|
||||
return (NULL);
|
||||
}
|
||||
return (xstrdup(found->name));
|
||||
}
|
||||
|
||||
struct options_entry *
|
||||
options_match_get(struct options *oo, const char *s, int *idx, int only,
|
||||
options_match_get(struct options *oo, const char *s, char **key, int only,
|
||||
int *ambiguous)
|
||||
{
|
||||
char *name;
|
||||
struct options_entry *o;
|
||||
|
||||
name = options_match(s, idx, ambiguous);
|
||||
name = options_match(s, key, ambiguous);
|
||||
if (name == NULL)
|
||||
return (NULL);
|
||||
*ambiguous = 0;
|
||||
@@ -747,6 +857,10 @@ options_match_get(struct options *oo, const char *s, int *idx, int only,
|
||||
else
|
||||
o = options_get(oo, name);
|
||||
free(name);
|
||||
if (o == NULL) {
|
||||
free(*key);
|
||||
*key = NULL;
|
||||
}
|
||||
return (o);
|
||||
}
|
||||
|
||||
@@ -1340,11 +1454,12 @@ options_push_changes(const char *name)
|
||||
}
|
||||
|
||||
int
|
||||
options_remove_or_default(struct options_entry *o, int idx, char **cause)
|
||||
options_remove_or_default(struct options_entry *o, const char *key,
|
||||
char **cause)
|
||||
{
|
||||
struct options *oo = o->owner;
|
||||
|
||||
if (idx == -1) {
|
||||
if (key == NULL) {
|
||||
if (o->tableentry != NULL &&
|
||||
(oo == global_options ||
|
||||
oo == global_s_options ||
|
||||
@@ -1352,7 +1467,7 @@ options_remove_or_default(struct options_entry *o, int idx, char **cause)
|
||||
options_default(oo, o->tableentry);
|
||||
else
|
||||
options_remove(o);
|
||||
} else if (options_array_set(o, idx, NULL, 0, cause) != 0)
|
||||
} else if (options_array_set(o, key, NULL, 0, cause) != 0)
|
||||
return (-1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -1,22 +1,30 @@
|
||||
TESTS!= echo *.sh
|
||||
LOGDIR=logs
|
||||
|
||||
.PHONY: all $(TESTS)
|
||||
.NOTPARALLEL: all $(TESTS)
|
||||
.PHONY: all
|
||||
.NOTPARALLEL: all
|
||||
|
||||
all:
|
||||
@failed=0; failures=; \
|
||||
@mkdir -p "$(LOGDIR)"; \
|
||||
rm -f "$(LOGDIR)"/*.log; \
|
||||
failed=0; failures=; \
|
||||
for test in $(TESTS); do \
|
||||
base=$${test##*/}; \
|
||||
log="$(LOGDIR)/$${base%.sh}.log"; \
|
||||
rm -f "$$log"; \
|
||||
printf '%-40s ' "$$test"; \
|
||||
start=$$(date +%s); \
|
||||
ASAN_OPTIONS="abort_on_error=1:detect_leaks=0:$$ASAN_OPTIONS"; \
|
||||
env -i LC_CTYPE=C.UTF-8 ASAN_OPTIONS="$$ASAN_OPTIONS" \
|
||||
sh "$$test" >/dev/null 2>&1; \
|
||||
sh -x "$$test" >"$$log" 2>&1; \
|
||||
if [ $$? -eq 0 ]; then \
|
||||
end=$$(date +%s); \
|
||||
rm -f "$$log"; \
|
||||
echo "PASS ($$((end - start))s)"; \
|
||||
else \
|
||||
end=$$(date +%s); \
|
||||
echo "FAIL ($$((end - start))s)"; \
|
||||
echo " log: $$log"; \
|
||||
failed=1; \
|
||||
failures="$$failures $$test"; \
|
||||
fi; \
|
||||
@@ -28,9 +36,7 @@ all:
|
||||
for test in $$failures; do \
|
||||
echo " $$test"; \
|
||||
done; \
|
||||
else \
|
||||
rmdir "$(LOGDIR)" 2>/dev/null || true; \
|
||||
fi; \
|
||||
exit $$failed
|
||||
|
||||
$(TESTS):
|
||||
sh $@
|
||||
sleep 1
|
||||
|
||||
291
regress/alerts.sh
Normal file
291
regress/alerts.sh
Normal file
@@ -0,0 +1,291 @@
|
||||
#!/bin/sh
|
||||
|
||||
# monitor-activity, monitor-bell and monitor-silence: both the
|
||||
# alert-activity, alert-bell and alert-silence hooks and the winlink alert
|
||||
# flags (window_activity_flag, window_bell_flag, window_silence_flag and
|
||||
# the #, !, ~ characters in window_flags). The sessions are detached so
|
||||
# alert flags are set even on the current window; the *-action options
|
||||
# still decide whether the hooks fire. Panes run cat: activity is
|
||||
# generated by the tty echo of send-keys and a bell by sending a BEL and
|
||||
# newline for cat to write back.
|
||||
|
||||
PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
LC_ALL=C.UTF-8
|
||||
LANG=C.UTF-8
|
||||
export TERM LC_ALL LANG
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
OUT=$(mktemp -d)
|
||||
TMUX_TMPDIR="$OUT"
|
||||
export TMUX_TMPDIR
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
|
||||
fail()
|
||||
{
|
||||
echo "$*" >&2
|
||||
$TMUX kill-server 2>/dev/null || true
|
||||
rm -rf "$OUT"
|
||||
exit 1
|
||||
}
|
||||
|
||||
cleanup()
|
||||
{
|
||||
$TMUX kill-server 2>/dev/null || true
|
||||
rm -rf "$OUT"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
wait_for()
|
||||
{
|
||||
option=$1
|
||||
expected=$2
|
||||
i=0
|
||||
|
||||
while [ $i -lt 30 ]; do
|
||||
value=$($TMUX show -gqv "$option" 2>/dev/null || true)
|
||||
[ "$value" = "$expected" ] && return 0
|
||||
i=$((i + 1))
|
||||
sleep 0.2
|
||||
done
|
||||
fail "expected $option to be '$expected' but got '$value'"
|
||||
}
|
||||
|
||||
assert_unchanged()
|
||||
{
|
||||
option=$1
|
||||
expected=$2
|
||||
i=0
|
||||
|
||||
while [ $i -lt 10 ]; do
|
||||
value=$($TMUX show -gqv "$option" 2>/dev/null || true)
|
||||
[ "$value" = "$expected" ] || \
|
||||
fail "expected $option to remain '$expected' but got '$value'"
|
||||
i=$((i + 1))
|
||||
sleep 0.2
|
||||
done
|
||||
}
|
||||
|
||||
wait_for_fmt()
|
||||
{
|
||||
target=$1
|
||||
fmt=$2
|
||||
expected=$3
|
||||
i=0
|
||||
|
||||
while [ $i -lt 30 ]; do
|
||||
value=$($TMUX display -pt "$target" "$fmt" 2>/dev/null || true)
|
||||
[ "$value" = "$expected" ] && return 0
|
||||
i=$((i + 1))
|
||||
sleep 0.2
|
||||
done
|
||||
fail "expected $fmt for $target to be '$expected' but got '$value'"
|
||||
}
|
||||
|
||||
assert_fmt_unchanged()
|
||||
{
|
||||
target=$1
|
||||
fmt=$2
|
||||
expected=$3
|
||||
i=0
|
||||
|
||||
while [ $i -lt 10 ]; do
|
||||
value=$($TMUX display -pt "$target" "$fmt" 2>/dev/null || true)
|
||||
[ "$value" = "$expected" ] || \
|
||||
fail "expected $fmt for $target to remain '$expected' but got '$value'"
|
||||
i=$((i + 1))
|
||||
sleep 0.2
|
||||
done
|
||||
}
|
||||
|
||||
flags_have()
|
||||
{
|
||||
target=$1
|
||||
char=$2
|
||||
|
||||
flags=$($TMUX display -pt "$target" '#{window_flags}') ||
|
||||
fail "display window_flags failed"
|
||||
case "$flags" in
|
||||
*"$char"*) ;;
|
||||
*) fail "expected '$char' in window_flags for $target: '$flags'" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
flags_lack()
|
||||
{
|
||||
target=$1
|
||||
char=$2
|
||||
|
||||
flags=$($TMUX display -pt "$target" '#{window_flags}') ||
|
||||
fail "display window_flags failed"
|
||||
case "$flags" in
|
||||
*"$char"*) fail "unexpected '$char' in window_flags for $target: '$flags'" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
bell()
|
||||
{
|
||||
$TMUX send-keys -t "$1" -H 07 0a || fail "send-keys bell failed"
|
||||
}
|
||||
|
||||
activity()
|
||||
{
|
||||
$TMUX send-keys -t "$1" -l x || fail "send-keys activity failed"
|
||||
}
|
||||
|
||||
$TMUX new -d -s mon -n w0 cat || fail "new-session mon failed"
|
||||
|
||||
$TMUX set -g @log '' || fail "set @log failed"
|
||||
$TMUX set-hook -g alert-bell \
|
||||
'set -gF @log "#{@log}|alert-bell:#{hook_session_name}:#{hook_window_name}"' ||
|
||||
fail "set-hook alert-bell failed"
|
||||
$TMUX set-hook -g alert-activity \
|
||||
'set -gF @log "#{@log}|alert-activity:#{hook_session_name}:#{hook_window_name}"' ||
|
||||
fail "set-hook alert-activity failed"
|
||||
$TMUX set-hook -g alert-silence \
|
||||
'set -gF @log "#{@log}|alert-silence:#{hook_session_name}:#{hook_window_name}"' ||
|
||||
fail "set-hook alert-silence failed"
|
||||
|
||||
# A bell in a non-current window (monitor-bell defaults to on) fires
|
||||
# alert-bell and sets the bell flag, shown as ! in window_flags.
|
||||
$TMUX neww -d -t mon: -n bellw cat || fail "new-window bellw failed"
|
||||
assert_fmt_unchanged mon:bellw '#{window_bell_flag}' 0
|
||||
flags_lack mon:bellw '!'
|
||||
bell mon:bellw
|
||||
wait_for @log '|alert-bell:mon:bellw'
|
||||
wait_for_fmt mon:bellw '#{window_bell_flag}' 1
|
||||
flags_have mon:bellw '!'
|
||||
|
||||
# Bells are not deduplicated: a second bell fires the hook again even
|
||||
# though the flag is still set.
|
||||
bell mon:bellw
|
||||
wait_for @log '|alert-bell:mon:bellw|alert-bell:mon:bellw'
|
||||
|
||||
# Selecting the window clears the alert flags.
|
||||
$TMUX selectw -t mon:bellw || fail "select-window bellw failed"
|
||||
wait_for_fmt mon:bellw '#{window_bell_flag}' 0
|
||||
flags_lack mon:bellw '!'
|
||||
$TMUX selectw -t mon:w0 || fail "select-window w0 failed"
|
||||
|
||||
# A bell in the current window of a detached session still sets the flag
|
||||
# and bell-action any (the default) fires the hook for the current window.
|
||||
$TMUX set -g @log '' || fail "reset @log failed"
|
||||
bell mon:w0
|
||||
wait_for @log '|alert-bell:mon:w0'
|
||||
wait_for_fmt mon:w0 '#{window_bell_flag}' 1
|
||||
$TMUX selectw -t mon:bellw || fail "select-window bellw failed"
|
||||
$TMUX selectw -t mon:w0 || fail "select-window w0 failed"
|
||||
wait_for_fmt mon:w0 '#{window_bell_flag}' 0
|
||||
|
||||
# bell-action none: the flag is still set but the hook does not fire.
|
||||
$TMUX set -t mon bell-action none || fail "set bell-action none failed"
|
||||
$TMUX set -g @log '' || fail "reset @log failed"
|
||||
bell mon:bellw
|
||||
wait_for_fmt mon:bellw '#{window_bell_flag}' 1
|
||||
assert_unchanged @log ''
|
||||
$TMUX set -ut mon bell-action || fail "unset bell-action failed"
|
||||
$TMUX selectw -t mon:bellw || fail "select-window bellw failed"
|
||||
$TMUX selectw -t mon:w0 || fail "select-window w0 failed"
|
||||
|
||||
# monitor-bell off: neither the flag nor the hook.
|
||||
$TMUX set -wt mon:bellw monitor-bell off || fail "set monitor-bell failed"
|
||||
$TMUX set -g @log '' || fail "reset @log failed"
|
||||
bell mon:bellw
|
||||
assert_fmt_unchanged mon:bellw '#{window_bell_flag}' 0
|
||||
assert_unchanged @log ''
|
||||
|
||||
# monitor-activity defaults to off: output sets neither flag nor hook.
|
||||
$TMUX neww -d -t mon: -n actw cat || fail "new-window actw failed"
|
||||
$TMUX set -g @log '' || fail "reset @log failed"
|
||||
activity mon:actw
|
||||
assert_fmt_unchanged mon:actw '#{window_activity_flag}' 0
|
||||
assert_unchanged @log ''
|
||||
|
||||
# With monitor-activity on, output fires alert-activity and sets the
|
||||
# activity flag, shown as # in window_flags.
|
||||
$TMUX set -wt mon:actw monitor-activity on ||
|
||||
fail "set monitor-activity failed"
|
||||
activity mon:actw
|
||||
wait_for @log '|alert-activity:mon:actw'
|
||||
wait_for_fmt mon:actw '#{window_activity_flag}' 1
|
||||
flags_have mon:actw '#'
|
||||
|
||||
# While the flag is set further activity does not fire the hook again.
|
||||
$TMUX set -g @log '' || fail "reset @log failed"
|
||||
activity mon:actw
|
||||
assert_unchanged @log ''
|
||||
|
||||
# On a detached session selecting the window does not clear the activity
|
||||
# flag: session_set_current treats the selection itself as activity and
|
||||
# the flag is raised again at once because the session is not attached.
|
||||
# No hook fires as activity-action other does not apply to the current
|
||||
# window.
|
||||
$TMUX selectw -t mon:actw || fail "select-window actw failed"
|
||||
assert_fmt_unchanged mon:actw '#{window_activity_flag}' 1
|
||||
$TMUX selectw -t mon:w0 || fail "select-window w0 failed"
|
||||
assert_fmt_unchanged mon:actw '#{window_activity_flag}' 1
|
||||
assert_unchanged @log ''
|
||||
|
||||
# With a client attached, selecting the window does clear the activity
|
||||
# flag and it stays clear for the current window.
|
||||
mkfifo "$OUT/fifo" || fail "mkfifo failed"
|
||||
$TMUX -C attach -t mon <"$OUT/fifo" >"$OUT/control.out" 2>&1 &
|
||||
exec 3>"$OUT/fifo"
|
||||
wait_for_fmt mon: '#{session_attached}' 1
|
||||
$TMUX selectw -t mon:actw || fail "select-window actw failed"
|
||||
wait_for_fmt mon:actw '#{window_activity_flag}' 0
|
||||
flags_lack mon:actw '#'
|
||||
$TMUX selectw -t mon:w0 || fail "select-window w0 failed"
|
||||
exec 3>&-
|
||||
wait_for_fmt mon: '#{session_attached}' 0
|
||||
|
||||
# Once the flag is clear the alert is re-armed.
|
||||
activity mon:actw
|
||||
wait_for @log '|alert-activity:mon:actw'
|
||||
|
||||
# Activity in the current window of a detached session sets the flag but
|
||||
# activity-action other (the default) does not fire the hook.
|
||||
$TMUX set -wt mon:w0 monitor-activity on ||
|
||||
fail "set monitor-activity w0 failed"
|
||||
$TMUX set -g @log '' || fail "reset @log failed"
|
||||
activity mon:w0
|
||||
wait_for_fmt mon:w0 '#{window_activity_flag}' 1
|
||||
assert_unchanged @log ''
|
||||
$TMUX set -wut mon:w0 monitor-activity ||
|
||||
fail "unset monitor-activity w0 failed"
|
||||
|
||||
# monitor-silence: a quiet window fires alert-silence after the interval
|
||||
# and sets the silence flag, shown as ~ in window_flags. The hook fires
|
||||
# only once while the flag remains set even though the timer keeps
|
||||
# running.
|
||||
$TMUX neww -d -t mon: -n silw cat || fail "new-window silw failed"
|
||||
assert_fmt_unchanged mon:silw '#{window_silence_flag}' 0
|
||||
$TMUX set -g @log '' || fail "reset @log failed"
|
||||
$TMUX set -wt mon:silw monitor-silence 1 || fail "set monitor-silence failed"
|
||||
wait_for @log '|alert-silence:mon:silw'
|
||||
wait_for_fmt mon:silw '#{window_silence_flag}' 1
|
||||
flags_have mon:silw '~'
|
||||
assert_unchanged @log '|alert-silence:mon:silw'
|
||||
$TMUX set -wt mon:silw monitor-silence 0 ||
|
||||
fail "reset monitor-silence failed"
|
||||
$TMUX selectw -t mon:silw || fail "select-window silw failed"
|
||||
wait_for_fmt mon:silw '#{window_silence_flag}' 0
|
||||
flags_lack mon:silw '~'
|
||||
$TMUX selectw -t mon:w0 || fail "select-window w0 failed"
|
||||
|
||||
# A window linked into two sessions: the hook fires once per winlink and
|
||||
# the flag is set in both sessions. Selecting the window in one session
|
||||
# clears the flags on every winlink.
|
||||
$TMUX new -d -s mon2 || fail "new-session mon2 failed"
|
||||
$TMUX neww -d -t mon: -n shw cat || fail "new-window shw failed"
|
||||
$TMUX link-window -d -s mon:shw -t mon2:5 || fail "link-window failed"
|
||||
$TMUX set -g @log '' || fail "reset @log failed"
|
||||
bell mon:shw
|
||||
wait_for @log '|alert-bell:mon:shw|alert-bell:mon2:shw'
|
||||
wait_for_fmt mon:shw '#{window_bell_flag}' 1
|
||||
wait_for_fmt mon2:5 '#{window_bell_flag}' 1
|
||||
$TMUX selectw -t mon2:5 || fail "select-window mon2:5 failed"
|
||||
wait_for_fmt mon2:5 '#{window_bell_flag}' 0
|
||||
wait_for_fmt mon:shw '#{window_bell_flag}' 0
|
||||
|
||||
exit 0
|
||||
@@ -4,9 +4,9 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
TMUX2="$TEST_TMUX -Ltest2 -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -LtestB$$ -f/dev/null"
|
||||
$TMUX2 kill-server 2>/dev/null
|
||||
|
||||
TMP=$(mktemp)
|
||||
|
||||
@@ -11,9 +11,9 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
TMUX_OUTER="$TEST_TMUX -Ltest2 -f/dev/null"
|
||||
TMUX_OUTER="$TEST_TMUX -LtestB$$ -f/dev/null"
|
||||
$TMUX_OUTER kill-server 2>/dev/null
|
||||
|
||||
trap "$TMUX kill-server 2>/dev/null; $TMUX_OUTER kill-server 2>/dev/null" 0 1 15
|
||||
|
||||
@@ -23,7 +23,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
TMP=$(mktemp)
|
||||
|
||||
@@ -6,7 +6,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
TMP=$(mktemp)
|
||||
TMP2=$(mktemp)
|
||||
trap "rm -f $TMP $TMP2" 0 1 15
|
||||
|
||||
@@ -7,7 +7,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
TMP=$(mktemp)
|
||||
|
||||
@@ -6,7 +6,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
fail()
|
||||
|
||||
@@ -17,18 +17,23 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -Ltest2 -f/dev/null"
|
||||
TMP=$(mktemp -d) || exit 1
|
||||
TMUX_TMPDIR="$TMP"
|
||||
export TMUX_TMPDIR
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -LtestB$$ -f/dev/null"
|
||||
|
||||
cleanup()
|
||||
{
|
||||
$TMUX kill-server 2>/dev/null
|
||||
$TMUX2 kill-server 2>/dev/null
|
||||
rm -rf "$TMP"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
fail()
|
||||
{
|
||||
echo "$1"
|
||||
cleanup
|
||||
echo "$1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
@@ -46,16 +51,50 @@ wait_for()
|
||||
{
|
||||
i=0
|
||||
while [ "$i" -lt 50 ]; do
|
||||
if capture | grep -q "$1"; then
|
||||
sleep 0.5
|
||||
CAPTURED=$(capture)
|
||||
if printf '%s\n' "$CAPTURED" | grep -F -q "$1"; then
|
||||
return 0
|
||||
fi
|
||||
sleep 0.5
|
||||
sleep 0.2
|
||||
i=$((i + 1))
|
||||
done
|
||||
fail "timed out waiting for '$1'"
|
||||
}
|
||||
|
||||
# wait_gone $marker
|
||||
#
|
||||
# Wait (up to ~10s) until the rendered screen no longer contains $marker.
|
||||
wait_gone()
|
||||
{
|
||||
i=0
|
||||
while [ "$i" -lt 50 ]; do
|
||||
CAPTURED=$(capture)
|
||||
if ! printf '%s\n' "$CAPTURED" | grep -F -q "$1"; then
|
||||
return 0
|
||||
fi
|
||||
sleep 0.2
|
||||
i=$((i + 1))
|
||||
done
|
||||
fail "timed out waiting for '$1' to disappear"
|
||||
}
|
||||
|
||||
# wait_count $marker $n
|
||||
#
|
||||
# Wait (up to ~10s) until exactly $n rendered lines contain $marker. The
|
||||
# matching capture is left in CAPTURED.
|
||||
wait_count()
|
||||
{
|
||||
i=0
|
||||
while [ "$i" -lt 50 ]; do
|
||||
CAPTURED=$(capture)
|
||||
c=$(printf '%s\n' "$CAPTURED" | grep -F -c "$1")
|
||||
[ "$c" -eq "$2" ] && return 0
|
||||
sleep 0.2
|
||||
i=$((i + 1))
|
||||
done
|
||||
fail "timed out waiting for $2 lines of '$1' (have $c)"
|
||||
}
|
||||
|
||||
# wait_buffers $n
|
||||
#
|
||||
# Wait (up to ~10s) until the test server has exactly $n paste buffers.
|
||||
@@ -86,10 +125,36 @@ wait_clients()
|
||||
return 1
|
||||
}
|
||||
|
||||
$TMUX kill-server 2>/dev/null
|
||||
$TMUX2 kill-server 2>/dev/null
|
||||
# wait_mode $target $state
|
||||
#
|
||||
# Wait (up to ~10s) until a pane enters or leaves mode.
|
||||
wait_mode()
|
||||
{
|
||||
t=$1
|
||||
want=$2
|
||||
|
||||
$TMUX new-session -d -s aaa -x 80 -y 24 || exit 1
|
||||
i=0
|
||||
while [ "$i" -lt 50 ]; do
|
||||
got=$($TMUX display-message -p -t "$t" '#{pane_in_mode}' \
|
||||
2>/dev/null)
|
||||
[ "$got" = "$want" ] && return 0
|
||||
sleep 0.2
|
||||
i=$((i + 1))
|
||||
done
|
||||
fail "pane $t mode state is $got, expected $want"
|
||||
}
|
||||
|
||||
exit_mode()
|
||||
{
|
||||
marker=$1
|
||||
shift
|
||||
|
||||
$TMUX send-keys -t aaa:0 "$@" || fail "send-keys $* failed"
|
||||
wait_mode aaa:0 0
|
||||
wait_gone "$marker"
|
||||
}
|
||||
|
||||
$TMUX new-session -d -s aaa -x 80 -y 24 'cat' || exit 1
|
||||
|
||||
$TMUX2 new-session -d -s out -x 80 -y 24 "$TMUX attach -t aaa" || exit 1
|
||||
wait_clients 1 || fail "no client attached to test server"
|
||||
@@ -100,57 +165,70 @@ $TMUX set-buffer -b bufz "other buffer" || exit 1
|
||||
|
||||
# --- filter by buffer name ---------------------------------------------------
|
||||
$TMUX choose-buffer -t aaa:0 -F 'B1' -f '#{==:#{buffer_name},bufa}' || exit 1
|
||||
wait_for 'B1'
|
||||
out=$(capture)
|
||||
echo "$out" | grep -q 'bufa: B1' || fail "bufa missing when it matches"
|
||||
echo "$out" | grep -q 'bufz: B1' && fail "bufz shown but does not match"
|
||||
[ "$(echo "$out" | grep -c ': B1')" -eq 1 ] || fail "expected 1 buffer"
|
||||
$TMUX send-keys -t aaa:0 q
|
||||
wait_count ': B1' 1
|
||||
out=$CAPTURED
|
||||
printf '%s\n' "$out" | grep -F -q 'bufa: B1' || \
|
||||
fail "bufa missing when it matches"
|
||||
printf '%s\n' "$out" | grep -F -q 'bufz: B1' && \
|
||||
fail "bufz shown but does not match"
|
||||
[ "$(printf '%s\n' "$out" | grep -F -c ': B1')" -eq 1 ] || \
|
||||
fail "expected 1 buffer"
|
||||
exit_mode ': B1' q
|
||||
|
||||
# --- filter by buffer content ------------------------------------------------
|
||||
$TMUX choose-buffer -t aaa:0 -F 'B2' -f '#{m:*hello*,#{buffer_sample}}' || \
|
||||
exit 1
|
||||
wait_for 'B2'
|
||||
out=$(capture)
|
||||
echo "$out" | grep -q 'bufa: B2' || fail "bufa missing when content matches"
|
||||
echo "$out" | grep -q 'bufz: B2' && fail "bufz shown but content not matched"
|
||||
$TMUX send-keys -t aaa:0 q
|
||||
wait_count ': B2' 1
|
||||
out=$CAPTURED
|
||||
printf '%s\n' "$out" | grep -F -q 'bufa: B2' || \
|
||||
fail "bufa missing when content matches"
|
||||
printf '%s\n' "$out" | grep -F -q 'bufz: B2' && \
|
||||
fail "bufz shown but content not matched"
|
||||
exit_mode ': B2' q
|
||||
|
||||
# --- no filter shows both buffers ---------------------------------------------
|
||||
$TMUX choose-buffer -t aaa:0 -F 'B3' || exit 1
|
||||
wait_for 'B3'
|
||||
out=$(capture)
|
||||
echo "$out" | grep -q 'bufa: B3' || fail "bufa missing with no filter"
|
||||
echo "$out" | grep -q 'bufz: B3' || fail "bufz missing with no filter"
|
||||
[ "$(echo "$out" | grep -c ': B3')" -eq 2 ] || fail "expected 2 buffers"
|
||||
$TMUX send-keys -t aaa:0 q
|
||||
wait_count ': B3' 2
|
||||
out=$CAPTURED
|
||||
printf '%s\n' "$out" | grep -F -q 'bufa: B3' || \
|
||||
fail "bufa missing with no filter"
|
||||
printf '%s\n' "$out" | grep -F -q 'bufz: B3' || \
|
||||
fail "bufz missing with no filter"
|
||||
[ "$(printf '%s\n' "$out" | grep -F -c ': B3')" -eq 2 ] || \
|
||||
fail "expected 2 buffers"
|
||||
exit_mode ': B3' q
|
||||
|
||||
# --- filter matching nothing ---------------------------------------------------
|
||||
#
|
||||
# Everything is shown and the filter indicator reports no matches.
|
||||
$TMUX choose-buffer -t aaa:0 -F 'B4' -f '#{==:#{buffer_name},nosuch}' || \
|
||||
exit 1
|
||||
wait_for 'B4'
|
||||
out=$(capture)
|
||||
echo "$out" | grep -q 'bufa: B4' || fail "bufa missing with no-match filter"
|
||||
echo "$out" | grep -q 'bufz: B4' || fail "bufz missing with no-match filter"
|
||||
echo "$out" | grep -q 'no matches' || fail "no matches indicator missing"
|
||||
$TMUX send-keys -t aaa:0 q
|
||||
wait_count ': B4' 2
|
||||
out=$CAPTURED
|
||||
printf '%s\n' "$out" | grep -F -q 'bufa: B4' || \
|
||||
fail "bufa missing with no-match filter"
|
||||
printf '%s\n' "$out" | grep -F -q 'bufz: B4' || \
|
||||
fail "bufz missing with no-match filter"
|
||||
printf '%s\n' "$out" | grep -F -q 'no matches' || \
|
||||
fail "no matches indicator missing"
|
||||
exit_mode ': B4' q
|
||||
|
||||
# --- sort orders ---------------------------------------------------------------
|
||||
#
|
||||
# By name bufa sorts first and -r reverses.
|
||||
$TMUX choose-buffer -t aaa:0 -F 'B5' -O name || exit 1
|
||||
wait_for 'B5'
|
||||
capture | grep ': B5' | head -1 | grep -q 'bufa: B5' || \
|
||||
wait_count ': B5' 2
|
||||
printf '%s\n' "$CAPTURED" | grep -F ': B5' | head -1 | \
|
||||
grep -F -q 'bufa: B5' || \
|
||||
fail "bufa not first with -O name"
|
||||
$TMUX send-keys -t aaa:0 q
|
||||
exit_mode ': B5' q
|
||||
|
||||
$TMUX choose-buffer -t aaa:0 -F 'B6' -O name -r || exit 1
|
||||
wait_for 'B6'
|
||||
capture | grep ': B6' | head -1 | grep -q 'bufz: B6' || \
|
||||
wait_count ': B6' 2
|
||||
printf '%s\n' "$CAPTURED" | grep -F ': B6' | head -1 | \
|
||||
grep -F -q 'bufz: B6' || \
|
||||
fail "bufz not first with -O name -r"
|
||||
$TMUX send-keys -t aaa:0 q
|
||||
exit_mode ': B6' q
|
||||
|
||||
# --- d deletes the selected buffer --------------------------------------------
|
||||
#
|
||||
@@ -159,18 +237,19 @@ $TMUX choose-buffer -t aaa:0 -F 'G1' -f '#{==:#{buffer_name},bufz}' || exit 1
|
||||
wait_for 'bufz: G1'
|
||||
$TMUX send-keys -t aaa:0 d
|
||||
wait_buffers 1
|
||||
$TMUX list-buffers -F '#{buffer_name}' | grep -q 'bufa' || \
|
||||
$TMUX list-buffers -F '#{buffer_name}' | grep -F -q 'bufa' || \
|
||||
fail "wrong buffer deleted"
|
||||
$TMUX send-keys -t aaa:0 q
|
||||
exit_mode ': G1' q
|
||||
|
||||
# --- C-t tags all buffers and D deletes the tagged ------------------------------
|
||||
$TMUX set-buffer -b bufz "other buffer" || exit 1
|
||||
$TMUX set-buffer -b bufb "third buffer" || exit 1
|
||||
$TMUX choose-buffer -t aaa:0 -F 'G2' || exit 1
|
||||
wait_for ': G2'
|
||||
wait_count ': G2' 3
|
||||
$TMUX send-keys -t aaa:0 C-t D
|
||||
wait_buffers 0
|
||||
$TMUX send-keys -t aaa:0 q
|
||||
wait_mode aaa:0 0
|
||||
wait_gone ': G2'
|
||||
|
||||
# --- Enter runs the default command (paste-buffer) ------------------------------
|
||||
#
|
||||
@@ -178,22 +257,15 @@ $TMUX send-keys -t aaa:0 q
|
||||
# into the shell in the pane, where it appears on the screen.
|
||||
$TMUX set-buffer -b bufa "hello buffer" || exit 1
|
||||
$TMUX choose-buffer -t aaa:0 -F 'G3' || exit 1
|
||||
wait_for 'bufa: G3'
|
||||
$TMUX send-keys -t aaa:0 Enter
|
||||
wait_count ': G3' 1
|
||||
exit_mode ': G3' Enter
|
||||
i=0
|
||||
while [ "$i" -lt 50 ]; do
|
||||
[ "$($TMUX display -p -t aaa:0 '#{pane_in_mode}')" = "0" ] && break
|
||||
sleep 0.5
|
||||
i=$((i + 1))
|
||||
done
|
||||
[ "$i" -lt 50 ] || fail "mode did not exit after Enter"
|
||||
i=0
|
||||
while [ "$i" -lt 50 ]; do
|
||||
$TMUX capture-pane -p -t aaa:0 | grep -q 'hello buffer' && break
|
||||
sleep 0.5
|
||||
$TMUX capture-pane -p -t aaa:0 | grep -F -q 'hello buffer' && \
|
||||
break
|
||||
sleep 0.2
|
||||
i=$((i + 1))
|
||||
done
|
||||
[ "$i" -lt 50 ] || fail "buffer not pasted into pane"
|
||||
|
||||
cleanup
|
||||
exit 0
|
||||
|
||||
@@ -16,18 +16,23 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -Ltest2 -f/dev/null"
|
||||
TMP=$(mktemp -d) || exit 1
|
||||
TMUX_TMPDIR="$TMP"
|
||||
export TMUX_TMPDIR
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -LtestB$$ -f/dev/null"
|
||||
|
||||
cleanup()
|
||||
{
|
||||
$TMUX kill-server 2>/dev/null
|
||||
$TMUX2 kill-server 2>/dev/null
|
||||
rm -rf "$TMP"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
fail()
|
||||
{
|
||||
echo "$1"
|
||||
cleanup
|
||||
echo "$1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
@@ -45,16 +50,50 @@ wait_for()
|
||||
{
|
||||
i=0
|
||||
while [ "$i" -lt 50 ]; do
|
||||
if capture | grep -q "$1"; then
|
||||
sleep 0.5
|
||||
CAPTURED=$(capture)
|
||||
if printf '%s\n' "$CAPTURED" | grep -F -q "$1"; then
|
||||
return 0
|
||||
fi
|
||||
sleep 0.5
|
||||
sleep 0.2
|
||||
i=$((i + 1))
|
||||
done
|
||||
fail "timed out waiting for '$1'"
|
||||
}
|
||||
|
||||
# wait_gone $marker
|
||||
#
|
||||
# Wait (up to ~10s) until the rendered screen no longer contains $marker.
|
||||
wait_gone()
|
||||
{
|
||||
i=0
|
||||
while [ "$i" -lt 50 ]; do
|
||||
CAPTURED=$(capture)
|
||||
if ! printf '%s\n' "$CAPTURED" | grep -F -q "$1"; then
|
||||
return 0
|
||||
fi
|
||||
sleep 0.2
|
||||
i=$((i + 1))
|
||||
done
|
||||
fail "timed out waiting for '$1' to disappear"
|
||||
}
|
||||
|
||||
# wait_count $marker $n
|
||||
#
|
||||
# Wait (up to ~10s) until exactly $n rendered lines contain $marker. The
|
||||
# matching capture is left in CAPTURED.
|
||||
wait_count()
|
||||
{
|
||||
i=0
|
||||
while [ "$i" -lt 50 ]; do
|
||||
CAPTURED=$(capture)
|
||||
c=$(printf '%s\n' "$CAPTURED" | grep -F -c "$1")
|
||||
[ "$c" -eq "$2" ] && return 0
|
||||
sleep 0.2
|
||||
i=$((i + 1))
|
||||
done
|
||||
fail "timed out waiting for $2 lines of '$1' (have $c)"
|
||||
}
|
||||
|
||||
# wait_clients $n
|
||||
#
|
||||
# Wait (up to ~10s) until the test server has exactly $n clients attached.
|
||||
@@ -70,14 +109,40 @@ wait_clients()
|
||||
return 1
|
||||
}
|
||||
|
||||
$TMUX kill-server 2>/dev/null
|
||||
$TMUX2 kill-server 2>/dev/null
|
||||
# wait_mode $target $state
|
||||
#
|
||||
# Wait (up to ~10s) until a pane enters or leaves mode.
|
||||
wait_mode()
|
||||
{
|
||||
t=$1
|
||||
want=$2
|
||||
|
||||
i=0
|
||||
while [ "$i" -lt 50 ]; do
|
||||
got=$($TMUX display-message -p -t "$t" '#{pane_in_mode}' \
|
||||
2>/dev/null)
|
||||
[ "$got" = "$want" ] && return 0
|
||||
sleep 0.2
|
||||
i=$((i + 1))
|
||||
done
|
||||
fail "pane $t mode state is $got, expected $want"
|
||||
}
|
||||
|
||||
exit_mode()
|
||||
{
|
||||
marker=$1
|
||||
shift
|
||||
|
||||
$TMUX send-keys -t aaa:0 "$@" || fail "send-keys $* failed"
|
||||
wait_mode aaa:0 0
|
||||
wait_gone "$marker"
|
||||
}
|
||||
|
||||
# One client attached to each of two sessions; the mode is displayed on the
|
||||
# client attached to aaa (in window 0 of the outer server) and the filters
|
||||
# tell the clients apart by their attached session.
|
||||
$TMUX new-session -d -s aaa -x 80 -y 24 || exit 1
|
||||
$TMUX new-session -d -s bbb -x 80 -y 24 || exit 1
|
||||
$TMUX new-session -d -s aaa -x 80 -y 24 'cat' || exit 1
|
||||
$TMUX new-session -d -s bbb -x 80 -y 24 'cat' || exit 1
|
||||
|
||||
$TMUX2 new-session -d -s out -x 80 -y 24 "$TMUX attach -t aaa" || exit 1
|
||||
$TMUX2 new-window -d -t out: "$TMUX attach -t bbb" || exit 1
|
||||
@@ -86,43 +151,55 @@ wait_clients 2 || fail "expected two clients attached to test server"
|
||||
# --- filter keeping only the aaa client -------------------------------------
|
||||
$TMUX choose-client -t aaa:0 -F 'C1=#{client_session}' \
|
||||
-f '#{==:#{client_session},aaa}' || exit 1
|
||||
wait_for 'C1='
|
||||
out=$(capture)
|
||||
echo "$out" | grep -q 'C1=aaa' || fail "aaa client missing when it matches"
|
||||
echo "$out" | grep -q 'C1=bbb' && fail "bbb client shown but does not match"
|
||||
[ "$(echo "$out" | grep -c 'C1=')" -eq 1 ] || fail "expected 1 client"
|
||||
$TMUX send-keys -t aaa:0 q
|
||||
wait_count 'C1=' 1
|
||||
out=$CAPTURED
|
||||
printf '%s\n' "$out" | grep -F -q 'C1=aaa' || \
|
||||
fail "aaa client missing when it matches"
|
||||
printf '%s\n' "$out" | grep -F -q 'C1=bbb' && \
|
||||
fail "bbb client shown but does not match"
|
||||
[ "$(printf '%s\n' "$out" | grep -F -c 'C1=')" -eq 1 ] || \
|
||||
fail "expected 1 client"
|
||||
exit_mode 'C1=' q
|
||||
|
||||
# --- filter keeping only the bbb client -------------------------------------
|
||||
$TMUX choose-client -t aaa:0 -F 'C2=#{client_session}' \
|
||||
-f '#{==:#{client_session},bbb}' || exit 1
|
||||
wait_for 'C2='
|
||||
out=$(capture)
|
||||
echo "$out" | grep -q 'C2=bbb' || fail "bbb client missing when it matches"
|
||||
echo "$out" | grep -q 'C2=aaa' && fail "aaa client shown but does not match"
|
||||
[ "$(echo "$out" | grep -c 'C2=')" -eq 1 ] || fail "expected 1 client"
|
||||
$TMUX send-keys -t aaa:0 q
|
||||
wait_count 'C2=' 1
|
||||
out=$CAPTURED
|
||||
printf '%s\n' "$out" | grep -F -q 'C2=bbb' || \
|
||||
fail "bbb client missing when it matches"
|
||||
printf '%s\n' "$out" | grep -F -q 'C2=aaa' && \
|
||||
fail "aaa client shown but does not match"
|
||||
[ "$(printf '%s\n' "$out" | grep -F -c 'C2=')" -eq 1 ] || \
|
||||
fail "expected 1 client"
|
||||
exit_mode 'C2=' q
|
||||
|
||||
# --- no filter shows both clients -------------------------------------------
|
||||
$TMUX choose-client -t aaa:0 -F 'C3=#{client_session}' || exit 1
|
||||
wait_for 'C3='
|
||||
out=$(capture)
|
||||
echo "$out" | grep -q 'C3=aaa' || fail "aaa client missing with no filter"
|
||||
echo "$out" | grep -q 'C3=bbb' || fail "bbb client missing with no filter"
|
||||
[ "$(echo "$out" | grep -c 'C3=')" -eq 2 ] || fail "expected 2 clients"
|
||||
$TMUX send-keys -t aaa:0 q
|
||||
wait_count 'C3=' 2
|
||||
out=$CAPTURED
|
||||
printf '%s\n' "$out" | grep -F -q 'C3=aaa' || \
|
||||
fail "aaa client missing with no filter"
|
||||
printf '%s\n' "$out" | grep -F -q 'C3=bbb' || \
|
||||
fail "bbb client missing with no filter"
|
||||
[ "$(printf '%s\n' "$out" | grep -F -c 'C3=')" -eq 2 ] || \
|
||||
fail "expected 2 clients"
|
||||
exit_mode 'C3=' q
|
||||
|
||||
# --- filter matching nothing ------------------------------------------------
|
||||
#
|
||||
# Everything is shown and the filter indicator reports no matches.
|
||||
$TMUX choose-client -t aaa:0 -F 'C4=#{client_session}' \
|
||||
-f '#{==:#{client_session},nosuch}' || exit 1
|
||||
wait_for 'C4='
|
||||
out=$(capture)
|
||||
echo "$out" | grep -q 'C4=aaa' || fail "aaa client missing with no-match filter"
|
||||
echo "$out" | grep -q 'C4=bbb' || fail "bbb client missing with no-match filter"
|
||||
echo "$out" | grep -q 'no matches' || fail "no matches indicator missing"
|
||||
$TMUX send-keys -t aaa:0 q
|
||||
wait_count 'C4=' 2
|
||||
out=$CAPTURED
|
||||
printf '%s\n' "$out" | grep -F -q 'C4=aaa' || \
|
||||
fail "aaa client missing with no-match filter"
|
||||
printf '%s\n' "$out" | grep -F -q 'C4=bbb' || \
|
||||
fail "bbb client missing with no-match filter"
|
||||
printf '%s\n' "$out" | grep -F -q 'no matches' || \
|
||||
fail "no matches indicator missing"
|
||||
exit_mode 'C4=' q
|
||||
|
||||
# --- Enter runs the default command (detach-client) --------------------------
|
||||
#
|
||||
@@ -131,10 +208,11 @@ $TMUX send-keys -t aaa:0 q
|
||||
$TMUX choose-client -t aaa:0 -F 'G1=#{client_session}' \
|
||||
-f '#{==:#{client_session},bbb}' || exit 1
|
||||
wait_for 'G1=bbb'
|
||||
$TMUX send-keys -t aaa:0 Enter
|
||||
$TMUX send-keys -t aaa:0 Enter || fail "send-keys Enter failed"
|
||||
wait_clients 1 || fail "bbb client did not detach"
|
||||
wait_mode aaa:0 0
|
||||
wait_gone 'G1='
|
||||
[ "$($TMUX list-clients -F '#{client_session}')" = "aaa" ] || \
|
||||
fail "wrong client detached"
|
||||
|
||||
cleanup
|
||||
exit 0
|
||||
|
||||
@@ -24,18 +24,23 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -Ltest2 -f/dev/null"
|
||||
TMP=$(mktemp -d) || exit 1
|
||||
TMUX_TMPDIR="$TMP"
|
||||
export TMUX_TMPDIR
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -LtestB$$ -f/dev/null"
|
||||
|
||||
cleanup()
|
||||
{
|
||||
$TMUX kill-server 2>/dev/null
|
||||
$TMUX2 kill-server 2>/dev/null
|
||||
rm -rf "$TMP"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
fail()
|
||||
{
|
||||
echo "$1"
|
||||
cleanup
|
||||
echo "$1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
@@ -53,28 +58,30 @@ wait_for()
|
||||
{
|
||||
i=0
|
||||
while [ "$i" -lt 50 ]; do
|
||||
if capture | grep -q "$1"; then
|
||||
sleep 0.5
|
||||
CAPTURED=$(capture)
|
||||
if printf '%s\n' "$CAPTURED" | grep -F -q "$1"; then
|
||||
return 0
|
||||
fi
|
||||
sleep 0.5
|
||||
sleep 0.2
|
||||
i=$((i + 1))
|
||||
done
|
||||
fail "timed out waiting for '$1'"
|
||||
}
|
||||
|
||||
# wait_count $marker $n
|
||||
# wait_count $row-marker $n
|
||||
#
|
||||
# Wait (up to ~10s) until exactly $n rendered lines contain $marker.
|
||||
# Wait (up to ~10s) until exactly $n rendered list rows contain $row-marker.
|
||||
wait_count()
|
||||
{
|
||||
i=0
|
||||
while [ "$i" -lt 50 ]; do
|
||||
[ "$(capture | grep -c "$1")" -eq "$2" ] && return 0
|
||||
sleep 0.5
|
||||
CAPTURED=$(capture)
|
||||
c=$(printf '%s\n' "$CAPTURED" | grep -F -c "$1")
|
||||
[ "$c" -eq "$2" ] && return 0
|
||||
sleep 0.2
|
||||
i=$((i + 1))
|
||||
done
|
||||
fail "timed out waiting for $2 lines of '$1' (have $(capture | grep -c "$1"))"
|
||||
fail "timed out waiting for $2 lines of '$1' (have $c)"
|
||||
}
|
||||
|
||||
# wait_clients $n
|
||||
@@ -92,8 +99,30 @@ wait_clients()
|
||||
return 1
|
||||
}
|
||||
|
||||
$TMUX kill-server 2>/dev/null
|
||||
$TMUX2 kill-server 2>/dev/null
|
||||
# wait_mode $target $state
|
||||
#
|
||||
# Wait (up to ~10s) until a pane enters or leaves mode.
|
||||
wait_mode()
|
||||
{
|
||||
t=$1
|
||||
want=$2
|
||||
|
||||
i=0
|
||||
while [ "$i" -lt 50 ]; do
|
||||
got=$($TMUX display-message -p -t "$t" '#{pane_in_mode}' \
|
||||
2>/dev/null)
|
||||
[ "$got" = "$want" ] && return 0
|
||||
sleep 0.2
|
||||
i=$((i + 1))
|
||||
done
|
||||
fail "pane $t mode state is $got, expected $want"
|
||||
}
|
||||
|
||||
exit_mode()
|
||||
{
|
||||
$TMUX send-keys -t aaa:0 "$@" || fail "send-keys $* failed"
|
||||
wait_mode aaa:0 0
|
||||
}
|
||||
|
||||
# Session zzz is created first, so it sorts first by index, and has a
|
||||
# two-pane window 0 and a single-pane window 1. Session aaa has one window
|
||||
@@ -102,10 +131,10 @@ $TMUX2 kill-server 2>/dev/null
|
||||
#
|
||||
# 0 zzz 1 window 0 2 pane 0 3 pane 1 4 window 1 5 pane 0
|
||||
# 6 aaa 7 window 0 8 pane 0
|
||||
$TMUX new-session -d -s zzz -x 80 -y 24 || exit 1
|
||||
$TMUX split-window -t zzz:0 || exit 1
|
||||
$TMUX new-window -t zzz || exit 1
|
||||
$TMUX new-session -d -s aaa -x 80 -y 24 || exit 1
|
||||
$TMUX new-session -d -s zzz -x 80 -y 24 'cat' || exit 1
|
||||
$TMUX split-window -t zzz:0 'cat' || exit 1
|
||||
$TMUX new-window -t zzz 'cat' || exit 1
|
||||
$TMUX new-session -d -s aaa -x 80 -y 24 'cat' || exit 1
|
||||
|
||||
$TMUX2 new-session -d -s out -x 80 -y 24 "$TMUX attach -t aaa" || exit 1
|
||||
wait_clients 1 || fail "no client attached to test server"
|
||||
@@ -116,45 +145,55 @@ wait_clients 1 || fail "no client attached to test server"
|
||||
# regression - its two-pane window 0. aaa contributes exactly three lines
|
||||
# (session, window, pane).
|
||||
$TMUX choose-tree -t aaa:0 -F 'F1' -f '#{==:#{session_name},aaa}' || exit 1
|
||||
wait_count 'F1' 3
|
||||
out=$(capture)
|
||||
echo "$out" | grep -q 'aaa: F1' || fail "aaa missing when filter matches it"
|
||||
echo "$out" | grep -q 'zzz: F1' && fail "zzz shown but no pane matches"
|
||||
$TMUX send-keys -t aaa:0 q
|
||||
wait_count ': F1' 3
|
||||
out=$CAPTURED
|
||||
printf '%s\n' "$out" | grep -F -q 'aaa: F1' || \
|
||||
fail "aaa missing when filter matches it"
|
||||
printf '%s\n' "$out" | grep -F -q 'zzz: F1' && \
|
||||
fail "zzz shown but no pane matches"
|
||||
exit_mode q
|
||||
|
||||
# --- filter keeping only zzz ------------------------------------------------
|
||||
#
|
||||
# zzz contributes six lines (session, two windows, three panes); aaa must
|
||||
# disappear.
|
||||
$TMUX choose-tree -t aaa:0 -F 'F2' -f '#{==:#{session_name},zzz}' || exit 1
|
||||
wait_count 'F2' 6
|
||||
out=$(capture)
|
||||
echo "$out" | grep -q 'zzz: F2' || fail "zzz missing when filter matches it"
|
||||
echo "$out" | grep -q 'aaa: F2' && fail "aaa shown but no pane matches"
|
||||
$TMUX send-keys -t aaa:0 q
|
||||
wait_count ': F2' 6
|
||||
out=$CAPTURED
|
||||
printf '%s\n' "$out" | grep -F -q 'zzz: F2' || \
|
||||
fail "zzz missing when filter matches it"
|
||||
printf '%s\n' "$out" | grep -F -q 'aaa: F2' && \
|
||||
fail "aaa shown but no pane matches"
|
||||
exit_mode q
|
||||
|
||||
# --- filter matching a single pane ------------------------------------------
|
||||
#
|
||||
# Only pane 1 of zzz:0 matches, so the tree is exactly session zzz, window 0
|
||||
# and that pane; zzz:1 and all of aaa must disappear.
|
||||
$TMUX choose-tree -t aaa:0 -F 'F3' -f '#{==:#{pane_index},1}' || exit 1
|
||||
wait_count 'F3' 3
|
||||
out=$(capture)
|
||||
echo "$out" | grep -q 'zzz: F3' || fail "zzz missing when its pane matches"
|
||||
echo "$out" | grep -q 'aaa: F3' && fail "aaa shown but no pane matches"
|
||||
echo "$out" | grep -q '1: F3' || fail "matching pane missing"
|
||||
$TMUX send-keys -t aaa:0 q
|
||||
wait_count ': F3' 3
|
||||
out=$CAPTURED
|
||||
printf '%s\n' "$out" | grep -F -q 'zzz: F3' || \
|
||||
fail "zzz missing when its pane matches"
|
||||
printf '%s\n' "$out" | grep -F -q 'aaa: F3' && \
|
||||
fail "aaa shown but no pane matches"
|
||||
printf '%s\n' "$out" | grep -F -q '1: F3' || \
|
||||
fail "matching pane missing"
|
||||
exit_mode q
|
||||
|
||||
# --- filter matching nothing ------------------------------------------------
|
||||
#
|
||||
# Everything is shown and the filter indicator reports no matches.
|
||||
$TMUX choose-tree -t aaa:0 -F 'F4' -f '#{==:#{session_name},nosuch}' || exit 1
|
||||
wait_for 'F4'
|
||||
out=$(capture)
|
||||
echo "$out" | grep -q 'aaa: F4' || fail "aaa missing with no-match filter"
|
||||
echo "$out" | grep -q 'zzz: F4' || fail "zzz missing with no-match filter"
|
||||
echo "$out" | grep -q 'no matches' || fail "no matches indicator missing"
|
||||
$TMUX send-keys -t aaa:0 q
|
||||
wait_count ': F4' 9
|
||||
out=$CAPTURED
|
||||
printf '%s\n' "$out" | grep -F -q 'aaa: F4' || \
|
||||
fail "aaa missing with no-match filter"
|
||||
printf '%s\n' "$out" | grep -F -q 'zzz: F4' || \
|
||||
fail "zzz missing with no-match filter"
|
||||
printf '%s\n' "$out" | grep -F -q 'no matches' || \
|
||||
fail "no matches indicator missing"
|
||||
exit_mode q
|
||||
|
||||
# --- -h with the tree pane as the only match --------------------------------
|
||||
#
|
||||
@@ -162,86 +201,93 @@ $TMUX send-keys -t aaa:0 q
|
||||
# match, so session and window aaa stay listed: two lines, no pane line.
|
||||
$TMUX choose-tree -h -t aaa:0 -F 'F5' -f '#{==:#{session_name},aaa}' || \
|
||||
exit 1
|
||||
wait_count 'F5' 2
|
||||
capture | grep -q 'aaa: F5' || fail "aaa missing with -h"
|
||||
$TMUX send-keys -t aaa:0 q
|
||||
wait_count ': F5' 2
|
||||
printf '%s\n' "$CAPTURED" | grep -F -q 'aaa: F5' || \
|
||||
fail "aaa missing with -h"
|
||||
exit_mode q
|
||||
|
||||
# --- sort orders ------------------------------------------------------------
|
||||
#
|
||||
# By index zzz (created first) sorts first, by name aaa does, and -r reverses.
|
||||
$TMUX choose-tree -t aaa:0 -F 'F6' -O index || exit 1
|
||||
wait_for 'F6'
|
||||
capture | grep 'F6' | head -1 | grep -q 'zzz: F6' || \
|
||||
wait_count ': F6' 9
|
||||
printf '%s\n' "$CAPTURED" | grep -F ': F6' | head -1 | \
|
||||
grep -F -q 'zzz: F6' || \
|
||||
fail "zzz not first with -O index"
|
||||
$TMUX send-keys -t aaa:0 q
|
||||
exit_mode q
|
||||
|
||||
$TMUX choose-tree -t aaa:0 -F 'F7' -O name || exit 1
|
||||
wait_for 'F7'
|
||||
capture | grep 'F7' | head -1 | grep -q 'aaa: F7' || \
|
||||
wait_count ': F7' 9
|
||||
printf '%s\n' "$CAPTURED" | grep -F ': F7' | head -1 | \
|
||||
grep -F -q 'aaa: F7' || \
|
||||
fail "aaa not first with -O name"
|
||||
$TMUX send-keys -t aaa:0 q
|
||||
exit_mode q
|
||||
|
||||
$TMUX choose-tree -t aaa:0 -F 'F8' -O name -r || exit 1
|
||||
wait_for 'F8'
|
||||
capture | grep 'F8' | head -1 | grep -q 'zzz: F8' || \
|
||||
wait_count ': F8' 9
|
||||
printf '%s\n' "$CAPTURED" | grep -F ': F8' | head -1 | \
|
||||
grep -F -q 'zzz: F8' || \
|
||||
fail "zzz not first with -O name -r"
|
||||
$TMUX send-keys -t aaa:0 q
|
||||
exit_mode q
|
||||
|
||||
# --- collapse and expand with h and l -----------------------------------------
|
||||
#
|
||||
# g moves to the top (session zzz); h collapses it, hiding its five children;
|
||||
# l expands it again.
|
||||
$TMUX choose-tree -t aaa:0 -F 'G1' -O index || exit 1
|
||||
wait_count 'G1' 9
|
||||
$TMUX send-keys -t aaa:0 g h
|
||||
wait_count 'G1' 4
|
||||
$TMUX send-keys -t aaa:0 l
|
||||
wait_count 'G1' 9
|
||||
$TMUX send-keys -t aaa:0 q
|
||||
wait_count ': G1' 9
|
||||
$TMUX send-keys -t aaa:0 g h || fail "send-keys collapse failed"
|
||||
wait_count ': G1' 4
|
||||
$TMUX send-keys -t aaa:0 l || fail "send-keys expand failed"
|
||||
wait_count ': G1' 9
|
||||
exit_mode q
|
||||
|
||||
# --- filter entered at the prompt with f, cleared with c ----------------------
|
||||
$TMUX choose-tree -t aaa:0 -F 'G2' -O index || exit 1
|
||||
wait_count 'G2' 9
|
||||
$TMUX send-keys -t aaa:0 f
|
||||
$TMUX send-keys -t aaa:0 -l '#{==:#{session_name},aaa}'
|
||||
$TMUX send-keys -t aaa:0 Enter
|
||||
wait_count 'G2' 3
|
||||
out=$(capture)
|
||||
echo "$out" | grep -q 'aaa: G2' || fail "aaa missing with prompt filter"
|
||||
echo "$out" | grep -q 'zzz: G2' && fail "zzz shown with prompt filter"
|
||||
$TMUX send-keys -t aaa:0 c
|
||||
wait_count 'G2' 9
|
||||
$TMUX send-keys -t aaa:0 q
|
||||
wait_count ': G2' 9
|
||||
$TMUX send-keys -t aaa:0 f || fail "send-keys f failed"
|
||||
$TMUX send-keys -t aaa:0 -l '#{==:#{session_name},aaa}' || \
|
||||
fail "send-keys filter failed"
|
||||
$TMUX send-keys -t aaa:0 Enter || fail "send-keys Enter failed"
|
||||
wait_count ': G2' 3
|
||||
out=$CAPTURED
|
||||
printf '%s\n' "$out" | grep -F -q 'aaa: G2' || \
|
||||
fail "aaa missing with prompt filter"
|
||||
printf '%s\n' "$out" | grep -F -q 'zzz: G2' && \
|
||||
fail "zzz shown with prompt filter"
|
||||
$TMUX send-keys -t aaa:0 c || fail "send-keys c failed"
|
||||
wait_count ': G2' 9
|
||||
exit_mode q
|
||||
|
||||
# --- Enter runs the default command (switch-client) ----------------------------
|
||||
#
|
||||
# g selects session zzz and Enter switches the client to it.
|
||||
$TMUX choose-tree -t aaa:0 -F 'G3' -O index || exit 1
|
||||
wait_count 'G3' 9
|
||||
$TMUX send-keys -t aaa:0 g Enter
|
||||
wait_count ': G3' 9
|
||||
$TMUX send-keys -t aaa:0 g Enter || fail "send-keys Enter failed"
|
||||
i=0
|
||||
while [ "$i" -lt 50 ]; do
|
||||
[ "$($TMUX list-clients -F '#{client_session}')" = "zzz" ] && break
|
||||
sleep 0.5
|
||||
sleep 0.2
|
||||
i=$((i + 1))
|
||||
done
|
||||
[ "$i" -lt 50 ] || fail "client did not switch to zzz"
|
||||
$TMUX switch-client -c "$($TMUX list-clients -F '#{client_name}')" -t aaa || \
|
||||
exit 1
|
||||
wait_mode aaa:0 0
|
||||
|
||||
# --- x kills the current item after confirmation -------------------------------
|
||||
#
|
||||
# g and four times j select window 1 of zzz; x asks for confirmation and y
|
||||
# kills it, leaving zzz with one window and the tree with seven lines.
|
||||
$TMUX choose-tree -t aaa:0 -F 'G4' -O index || exit 1
|
||||
wait_count 'G4' 9
|
||||
$TMUX send-keys -t aaa:0 g j j j j x
|
||||
wait_count ': G4' 9
|
||||
$TMUX send-keys -t aaa:0 g j j j j x || fail "send-keys x failed"
|
||||
wait_for 'Kill window 1'
|
||||
$TMUX send-keys -t aaa:0 y
|
||||
wait_count 'G4' 7
|
||||
$TMUX send-keys -t aaa:0 y || fail "send-keys y failed"
|
||||
wait_count ': G4' 7
|
||||
[ "$($TMUX list-windows -t zzz -F x | grep -c x)" -eq 1 ] || \
|
||||
fail "window 1 of zzz not killed"
|
||||
$TMUX send-keys -t aaa:0 q
|
||||
exit_mode q
|
||||
|
||||
cleanup
|
||||
exit 0
|
||||
|
||||
@@ -4,7 +4,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
TMP=$(mktemp)
|
||||
|
||||
@@ -6,7 +6,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
$TMUX new-session -d -sfoo || exit 1
|
||||
|
||||
@@ -4,7 +4,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
TMP=$(mktemp)
|
||||
|
||||
@@ -4,7 +4,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
for i in conf/*.conf; do
|
||||
|
||||
@@ -4,7 +4,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
TMP=$(mktemp)
|
||||
|
||||
@@ -8,7 +8,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
TMP=$(mktemp)
|
||||
|
||||
@@ -7,7 +7,7 @@ LANG=C.UTF-8
|
||||
export TERM LC_ALL LANG
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest$$ -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
|
||||
TMPDIR=$(mktemp -d)
|
||||
IN="$TMPDIR/in"
|
||||
|
||||
@@ -4,7 +4,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
$TMUX new -d -x40 -y10 \
|
||||
|
||||
@@ -4,7 +4,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -f/dev/null -Ltest"
|
||||
TMUX="$TEST_TMUX -f/dev/null -LtestA$$"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
$TMUX new -d -x40 -y10 \
|
||||
|
||||
@@ -4,7 +4,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
TMP=$(mktemp)
|
||||
|
||||
@@ -4,7 +4,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
TMP=$(mktemp)
|
||||
|
||||
@@ -4,7 +4,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
TMP=$(mktemp)
|
||||
|
||||
@@ -4,7 +4,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
TMP=$(mktemp)
|
||||
|
||||
@@ -9,7 +9,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
sleep 1
|
||||
|
||||
|
||||
@@ -17,9 +17,9 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
# A second server on its own socket hosts the pane that runs the inner client.
|
||||
TMUX2="$TEST_TMUX -Ltest2 -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -LtestB$$ -f/dev/null"
|
||||
|
||||
cleanup()
|
||||
{
|
||||
|
||||
@@ -19,7 +19,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
# check_value $args $expected
|
||||
@@ -151,7 +151,7 @@ cat > "$CONF" <<EOF
|
||||
CFGVAR=fromconfig
|
||||
%hidden CFGHID=hiddencfg
|
||||
EOF
|
||||
CTMUX="$TEST_TMUX -Ltest2 -f$CONF"
|
||||
CTMUX="$TEST_TMUX -LtestB$$ -f$CONF"
|
||||
$CTMUX kill-server 2>/dev/null
|
||||
$CTMUX new-session -d -s c -x 80 -y 24 || { rm -f "$CONF"; exit 1; }
|
||||
out=$($CTMUX show-environment -g CFGVAR 2>&1)
|
||||
|
||||
@@ -15,7 +15,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
fail()
|
||||
|
||||
@@ -6,7 +6,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
|
||||
# test_format $format $expected_result
|
||||
test_format()
|
||||
|
||||
@@ -17,7 +17,7 @@ LC_ALL=C.UTF-8
|
||||
export TZ LANG LC_ALL
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
|
||||
ESC=$(printf '\033')
|
||||
|
||||
|
||||
@@ -18,8 +18,8 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -Ltest2 -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -LtestB$$ -f/dev/null"
|
||||
|
||||
cleanup()
|
||||
{
|
||||
|
||||
@@ -9,8 +9,8 @@ export PATH TERM LANG LC_ALL
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
|
||||
TMUX="$TEST_TMUX -Lformat-render-contexts-$$ -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -Lformat-render-contexts-outer-$$ -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -LtestB$$ -f/dev/null"
|
||||
LIMIT=20000
|
||||
|
||||
cleanup()
|
||||
@@ -49,7 +49,13 @@ tmux_run()
|
||||
name=$1
|
||||
shift
|
||||
|
||||
out=$(run_cmd $TMUX "$@" 2>&1)
|
||||
out=$(
|
||||
if command -v timeout >/dev/null 2>&1; then
|
||||
timeout 10 $TMUX "$@" 2>&1
|
||||
else
|
||||
$TMUX "$@" 2>&1
|
||||
fi
|
||||
)
|
||||
rc=$?
|
||||
bounded "$name" "$out"
|
||||
[ "$rc" -eq 0 ] || fail "$name failed: $out"
|
||||
@@ -58,7 +64,13 @@ tmux_run()
|
||||
|
||||
capture()
|
||||
{
|
||||
out=$(run_cmd $TMUX2 capture-pane -p -t out:0 2>/dev/null)
|
||||
out=$(
|
||||
if command -v timeout >/dev/null 2>&1; then
|
||||
timeout 10 $TMUX2 capture-pane -p -t out:0 2>/dev/null
|
||||
else
|
||||
$TMUX2 capture-pane -p -t out:0 2>/dev/null
|
||||
fi
|
||||
)
|
||||
rc=$?
|
||||
bounded "capture-pane" "$out"
|
||||
[ "$rc" -eq 0 ] || fail "capture-pane failed"
|
||||
@@ -67,7 +79,14 @@ capture()
|
||||
|
||||
capture_esc()
|
||||
{
|
||||
out=$(run_cmd $TMUX2 capture-pane -pe -t out:0 2>/dev/null)
|
||||
out=$(
|
||||
if command -v timeout >/dev/null 2>&1; then
|
||||
timeout 10 $TMUX2 capture-pane -pe -t out:0 \
|
||||
2>/dev/null
|
||||
else
|
||||
$TMUX2 capture-pane -pe -t out:0 2>/dev/null
|
||||
fi
|
||||
)
|
||||
rc=$?
|
||||
bounded "capture-pane -e" "$out"
|
||||
[ "$rc" -eq 0 ] || fail "capture-pane -e failed"
|
||||
|
||||
@@ -6,7 +6,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
|
||||
# test_format $format $expected_result
|
||||
test_format()
|
||||
|
||||
@@ -15,10 +15,10 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
# A second server on its own socket provides a real terminal (an inner client
|
||||
# attached inside one of its panes) so client terminal variables are populated.
|
||||
TMUX2="$TEST_TMUX -Ltest2 -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -LtestB$$ -f/dev/null"
|
||||
|
||||
# Every variable name in format_table[]. Kept as a plain word list so it can be
|
||||
# iterated with normal shell word splitting.
|
||||
|
||||
@@ -7,7 +7,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
$TMUX -f/dev/null has -tfoo </dev/null 2>/dev/null && exit 1
|
||||
|
||||
124
regress/hooks-after.sh
Normal file
124
regress/hooks-after.sh
Normal file
@@ -0,0 +1,124 @@
|
||||
#!/bin/sh
|
||||
|
||||
PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
LC_ALL=C.UTF-8
|
||||
LANG=C.UTF-8
|
||||
export TERM LC_ALL LANG
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
OUT=$(mktemp -d)
|
||||
TMUX_TMPDIR="$OUT"
|
||||
export TMUX_TMPDIR
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
|
||||
fail()
|
||||
{
|
||||
echo "$*" >&2
|
||||
$TMUX kill-server 2>/dev/null || true
|
||||
rm -rf "$OUT"
|
||||
exit 1
|
||||
}
|
||||
|
||||
cleanup()
|
||||
{
|
||||
$TMUX kill-server 2>/dev/null || true
|
||||
rm -rf "$OUT"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
wait_for()
|
||||
{
|
||||
option=$1
|
||||
expected=$2
|
||||
i=0
|
||||
|
||||
while [ $i -lt 30 ]; do
|
||||
value=$($TMUX show -gqv "$option" 2>/dev/null || true)
|
||||
[ "$value" = "$expected" ] && return 0
|
||||
i=$((i + 1))
|
||||
sleep 0.2
|
||||
done
|
||||
fail "expected $option to be '$expected' but got '$value'"
|
||||
}
|
||||
|
||||
assert_unchanged()
|
||||
{
|
||||
option=$1
|
||||
expected=$2
|
||||
i=0
|
||||
|
||||
while [ $i -lt 10 ]; do
|
||||
value=$($TMUX show -gqv "$option" 2>/dev/null || true)
|
||||
[ "$value" = "$expected" ] || \
|
||||
fail "expected $option to remain '$expected' but got '$value'"
|
||||
i=$((i + 1))
|
||||
sleep 0.2
|
||||
done
|
||||
}
|
||||
|
||||
$TMUX new -d -s one || fail "new-session one failed"
|
||||
$TMUX new -d -s two || fail "new-session two failed"
|
||||
|
||||
# An after hook fires with the command arguments as formats.
|
||||
$TMUX set -g @after 0 || fail "set @after failed"
|
||||
$TMUX set-hook -g after-rename-window \
|
||||
'set -gF @after "#{hook}|#{hook_argument_0}|#{hook_flag_t}"' ||
|
||||
fail "set-hook -g after-rename-window failed"
|
||||
$TMUX rename-window -t one:0 first || fail "rename-window first failed"
|
||||
wait_for @after 'after-rename-window|first|one:0'
|
||||
|
||||
# An appended hook command runs after the first.
|
||||
$TMUX set -g @after2 0 || fail "set @after2 failed"
|
||||
$TMUX set-hook -ga after-rename-window \
|
||||
'set -gF @after2 "#{@after}+2"' ||
|
||||
fail "set-hook -ga after-rename-window failed"
|
||||
$TMUX rename-window -t one:0 second || fail "rename-window second failed"
|
||||
wait_for @after 'after-rename-window|second|one:0'
|
||||
wait_for @after2 'after-rename-window|second|one:0+2'
|
||||
$TMUX set-hook -gu after-rename-window || fail "set-hook -gu failed"
|
||||
|
||||
# A session after hook only fires for commands targeting that session and
|
||||
# the hook commands run with the command target as current state.
|
||||
$TMUX set -g @safter 0 || fail "set @safter failed"
|
||||
$TMUX set-hook -t two after-rename-window \
|
||||
'set -gF @safter "#{hook}:#{session_name}"' ||
|
||||
fail "set-hook -t two after-rename-window failed"
|
||||
$TMUX rename-window -t one:0 third || fail "rename-window third failed"
|
||||
assert_unchanged @safter 0
|
||||
$TMUX rename-window -t two:0 fourth || fail "rename-window fourth failed"
|
||||
wait_for @safter 'after-rename-window:two'
|
||||
$TMUX set-hook -u -t two after-rename-window ||
|
||||
fail "set-hook -u -t two failed"
|
||||
|
||||
# The command-error hook fires when a command fails.
|
||||
$TMUX set -g @error 0 || fail "set @error failed"
|
||||
$TMUX set-hook -g command-error 'set -gF @error "#{hook}"' ||
|
||||
fail "set-hook -g command-error failed"
|
||||
if $TMUX rename-window -t nosuchsession:0 x 2>/dev/null; then
|
||||
fail "rename-window to missing session succeeded"
|
||||
fi
|
||||
wait_for @error 'command-error'
|
||||
$TMUX set-hook -gu command-error || fail "set-hook -gu command-error failed"
|
||||
|
||||
# Commands run from a hook do not fire their own after hooks.
|
||||
$TMUX set -g @copy 0 || fail "set @copy failed"
|
||||
$TMUX set-hook -g after-copy-mode 'set -gF @copy "#{hook}"' ||
|
||||
fail "set-hook -g after-copy-mode failed"
|
||||
$TMUX copy-mode -t one:0 || fail "copy-mode failed"
|
||||
wait_for @copy 'after-copy-mode'
|
||||
$TMUX send-keys -t one:0 -X cancel || fail "cancel failed"
|
||||
$TMUX set -g @copy 0 || fail "reset @copy failed"
|
||||
$TMUX set -g @ran 0 || fail "set @ran failed"
|
||||
$TMUX set-hook -g after-rename-window 'copy-mode -t one:0' ||
|
||||
fail "set-hook -g after-rename-window nested failed"
|
||||
$TMUX set-hook -ga after-rename-window 'set -g @ran 1' ||
|
||||
fail "set-hook -ga after-rename-window nested failed"
|
||||
$TMUX rename-window -t one:0 fifth || fail "rename-window fifth failed"
|
||||
wait_for @ran 1
|
||||
mode=$($TMUX display -pt one:0 '#{pane_in_mode}') ||
|
||||
fail "display pane_in_mode failed"
|
||||
[ "$mode" = 1 ] || fail "hook did not enter copy mode"
|
||||
assert_unchanged @copy 0
|
||||
|
||||
exit 0
|
||||
162
regress/hooks-lifecycle.sh
Normal file
162
regress/hooks-lifecycle.sh
Normal file
@@ -0,0 +1,162 @@
|
||||
#!/bin/sh
|
||||
|
||||
# End-of-life hooks: pane-exited, pane-died, window-unlinked and
|
||||
# session-closed when the pane, window or session they refer to is being
|
||||
# or has been destroyed. Each hook appends to @log so the order hooks fire
|
||||
# in is checked as well as the hook formats for the dead objects.
|
||||
|
||||
PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
LC_ALL=C.UTF-8
|
||||
LANG=C.UTF-8
|
||||
export TERM LC_ALL LANG
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
OUT=$(mktemp -d)
|
||||
TMUX_TMPDIR="$OUT"
|
||||
export TMUX_TMPDIR
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
|
||||
fail()
|
||||
{
|
||||
echo "$*" >&2
|
||||
$TMUX kill-server 2>/dev/null || true
|
||||
rm -rf "$OUT"
|
||||
exit 1
|
||||
}
|
||||
|
||||
cleanup()
|
||||
{
|
||||
$TMUX kill-server 2>/dev/null || true
|
||||
rm -rf "$OUT"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
wait_for()
|
||||
{
|
||||
option=$1
|
||||
expected=$2
|
||||
i=0
|
||||
|
||||
while [ $i -lt 30 ]; do
|
||||
value=$($TMUX show -gqv "$option" 2>/dev/null || true)
|
||||
[ "$value" = "$expected" ] && return 0
|
||||
i=$((i + 1))
|
||||
sleep 0.2
|
||||
done
|
||||
fail "expected $option to be '$expected' but got '$value'"
|
||||
}
|
||||
|
||||
assert_unchanged()
|
||||
{
|
||||
option=$1
|
||||
expected=$2
|
||||
i=0
|
||||
|
||||
while [ $i -lt 10 ]; do
|
||||
value=$($TMUX show -gqv "$option" 2>/dev/null || true)
|
||||
[ "$value" = "$expected" ] || \
|
||||
fail "expected $option to remain '$expected' but got '$value'"
|
||||
i=$((i + 1))
|
||||
sleep 0.2
|
||||
done
|
||||
}
|
||||
|
||||
$TMUX new -d -s main || fail "new-session main failed"
|
||||
|
||||
$TMUX set -g @log '' || fail "set @log failed"
|
||||
$TMUX set-hook -g pane-exited \
|
||||
'set -gF @log "#{@log}|pane-exited:#{hook_pane}"' ||
|
||||
fail "set-hook pane-exited failed"
|
||||
$TMUX set-hook -g window-unlinked \
|
||||
'set -gF @log "#{@log}|window-unlinked:#{hook_session_name}:#{hook_window_name}"' ||
|
||||
fail "set-hook window-unlinked failed"
|
||||
$TMUX set-hook -g session-closed \
|
||||
'set -gF @log "#{@log}|session-closed:#{hook_session_name}"' ||
|
||||
fail "set-hook session-closed failed"
|
||||
|
||||
# The only pane of the only window of a session exits: pane-exited, then
|
||||
# window-unlinked, then session-closed, each seeing the dead object in the
|
||||
# hook formats.
|
||||
pane=$($TMUX new -d -s doomed -n dwin -P -F '#{pane_id}' 'true') ||
|
||||
fail "new-session doomed failed"
|
||||
wait_for @log \
|
||||
"|pane-exited:$pane|window-unlinked:doomed:dwin|session-closed:doomed"
|
||||
assert_unchanged @log \
|
||||
"|pane-exited:$pane|window-unlinked:doomed:dwin|session-closed:doomed"
|
||||
|
||||
# The dead pane, window and session cannot be used as targets but the
|
||||
# server survives.
|
||||
if $TMUX select-pane -t "$pane" 2>/dev/null; then
|
||||
fail "dead pane still a valid target"
|
||||
fi
|
||||
if $TMUX list-windows -t doomed >/dev/null 2>&1; then
|
||||
fail "dead session still a valid target"
|
||||
fi
|
||||
$TMUX list-panes -sat main >/dev/null || fail "list-panes failed"
|
||||
$TMUX has -t main || fail "server died after pane exit chain"
|
||||
|
||||
# kill-window on the last window: window-unlinked then session-closed but
|
||||
# no pane-exited for the panes in the killed window.
|
||||
$TMUX set -g @log '' || fail "reset @log failed"
|
||||
$TMUX new -d -s doomed2 -n dwin2 || fail "new-session doomed2 failed"
|
||||
$TMUX splitw -d -t doomed2:0 || fail "split-window doomed2 failed"
|
||||
$TMUX kill-window -t doomed2:0 || fail "kill-window failed"
|
||||
wait_for @log '|window-unlinked:doomed2:dwin2|session-closed:doomed2'
|
||||
assert_unchanged @log '|window-unlinked:doomed2:dwin2|session-closed:doomed2'
|
||||
$TMUX has -t main || fail "server died after kill-window chain"
|
||||
|
||||
# kill-session: session-closed fires first, then window-unlinked for its
|
||||
# windows. A window linked into another session survives.
|
||||
$TMUX new -d -s shareA -n shared || fail "new-session shareA failed"
|
||||
$TMUX new -d -s shareB -n bwin || fail "new-session shareB failed"
|
||||
$TMUX link-window -s shareA:shared -t shareB:7 || fail "link-window failed"
|
||||
$TMUX set -g @log '' || fail "reset @log failed"
|
||||
$TMUX kill-session -t shareA || fail "kill-session shareA failed"
|
||||
wait_for @log '|session-closed:shareA|window-unlinked:shareA:shared'
|
||||
name=$($TMUX display -pt shareB:7 '#{window_name}') ||
|
||||
fail "shared window did not survive"
|
||||
[ "$name" = shared ] || fail "expected window shared but got $name"
|
||||
|
||||
# Killing the surviving session destroys the shared window for real while
|
||||
# the session is being destroyed.
|
||||
$TMUX set -g @log '' || fail "reset @log failed"
|
||||
$TMUX kill-window -t shareB:0 || fail "kill-window bwin failed"
|
||||
wait_for @log '|window-unlinked:shareB:bwin'
|
||||
$TMUX set -g @log '' || fail "reset @log failed"
|
||||
$TMUX kill-session -t shareB || fail "kill-session shareB failed"
|
||||
wait_for @log '|session-closed:shareB|window-unlinked:shareB:shared'
|
||||
$TMUX has -t main || fail "server died after kill-session chain"
|
||||
|
||||
# A pane-died hook can kill its own dead pane (the hook runs with the dead
|
||||
# pane as current target). The kill-pane runs without hooks so pane-exited
|
||||
# does not fire.
|
||||
$TMUX set -g @log '' || fail "reset @log failed"
|
||||
$TMUX new -d -s roe -n rwin || fail "new-session roe failed"
|
||||
$TMUX set -wt roe:0 remain-on-exit on || fail "set remain-on-exit failed"
|
||||
$TMUX set-hook -g pane-died \
|
||||
'set -gF @log "#{@log}|pane-died:#{hook_pane}" ; kill-pane' ||
|
||||
fail "set-hook pane-died failed"
|
||||
pane=$($TMUX splitw -d -t roe:0 -P -F '#{pane_id}' 'true') ||
|
||||
fail "split-window roe failed"
|
||||
wait_for @log "|pane-died:$pane"
|
||||
assert_unchanged @log "|pane-died:$pane"
|
||||
if $TMUX select-pane -t "$pane" 2>/dev/null; then
|
||||
fail "pane-died hook did not kill its pane"
|
||||
fi
|
||||
$TMUX list-panes -t roe:0 >/dev/null || fail "surviving pane broken"
|
||||
$TMUX has -t roe || fail "session roe died"
|
||||
$TMUX set-hook -gu pane-died || fail "unset pane-died failed"
|
||||
$TMUX kill-session -t roe || fail "kill-session roe failed"
|
||||
|
||||
# Killing the last session with end-of-life hooks still set: the server
|
||||
# runs the hooks and exits cleanly.
|
||||
$TMUX kill-session -t main || fail "kill-session main failed"
|
||||
i=0
|
||||
while $TMUX has 2>/dev/null; do
|
||||
i=$((i + 1))
|
||||
[ $i -lt 30 ] || fail "server still running after last session killed"
|
||||
sleep 0.2
|
||||
done
|
||||
|
||||
exit 0
|
||||
199
regress/hooks-notify.sh
Normal file
199
regress/hooks-notify.sh
Normal file
@@ -0,0 +1,199 @@
|
||||
#!/bin/sh
|
||||
|
||||
PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
LC_ALL=C.UTF-8
|
||||
LANG=C.UTF-8
|
||||
export TERM LC_ALL LANG
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
OUT=$(mktemp -d)
|
||||
TMUX_TMPDIR="$OUT"
|
||||
export TMUX_TMPDIR
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
|
||||
fail()
|
||||
{
|
||||
echo "$*" >&2
|
||||
$TMUX kill-server 2>/dev/null || true
|
||||
rm -rf "$OUT"
|
||||
exit 1
|
||||
}
|
||||
|
||||
cleanup()
|
||||
{
|
||||
$TMUX kill-server 2>/dev/null || true
|
||||
rm -rf "$OUT"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
wait_for()
|
||||
{
|
||||
option=$1
|
||||
expected=$2
|
||||
i=0
|
||||
|
||||
while [ $i -lt 30 ]; do
|
||||
value=$($TMUX show -gqv "$option" 2>/dev/null || true)
|
||||
[ "$value" = "$expected" ] && return 0
|
||||
i=$((i + 1))
|
||||
sleep 0.2
|
||||
done
|
||||
fail "expected $option to be '$expected' but got '$value'"
|
||||
}
|
||||
|
||||
$TMUX new -d -s main || fail "new-session main failed"
|
||||
|
||||
# session-created, session-renamed, session-closed.
|
||||
$TMUX set -g @s 0 || fail "set @s failed"
|
||||
$TMUX set-hook -g session-created \
|
||||
'set -gF @s "#{hook}:#{hook_session_name}"' ||
|
||||
fail "set-hook session-created failed"
|
||||
$TMUX new -d -s tmp || fail "new-session tmp failed"
|
||||
wait_for @s 'session-created:tmp'
|
||||
$TMUX set-hook -gu session-created || fail "unset session-created failed"
|
||||
|
||||
$TMUX set-hook -g session-renamed \
|
||||
'set -gF @s "#{hook}:#{hook_session_name}"' ||
|
||||
fail "set-hook session-renamed failed"
|
||||
$TMUX rename-session -t tmp tmp2 || fail "rename-session failed"
|
||||
wait_for @s 'session-renamed:tmp2'
|
||||
$TMUX set-hook -gu session-renamed || fail "unset session-renamed failed"
|
||||
|
||||
$TMUX set-hook -g session-closed \
|
||||
'set -gF @s "#{hook}:#{hook_session_name}"' ||
|
||||
fail "set-hook session-closed failed"
|
||||
$TMUX kill-session -t tmp2 || fail "kill-session failed"
|
||||
wait_for @s 'session-closed:tmp2'
|
||||
$TMUX set-hook -gu session-closed || fail "unset session-closed failed"
|
||||
|
||||
# window-linked and window-unlinked from new-window and kill-window.
|
||||
$TMUX set -g @w 0 || fail "set @w failed"
|
||||
$TMUX set-hook -g window-linked \
|
||||
'set -gF @w "#{hook}:#{hook_session_name}:#{hook_window_name}"' ||
|
||||
fail "set-hook window-linked failed"
|
||||
$TMUX set-hook -g window-unlinked \
|
||||
'set -gF @w "#{hook}:#{hook_session_name}:#{hook_window_name}"' ||
|
||||
fail "set-hook window-unlinked failed"
|
||||
$TMUX neww -d -t main: -n mywin || fail "new-window failed"
|
||||
wait_for @w 'window-linked:main:mywin'
|
||||
|
||||
# window-linked and window-unlinked from link-window and unlink-window.
|
||||
$TMUX new -d -s other || fail "new-session other failed"
|
||||
$TMUX set -g @w 0 || fail "reset @w failed"
|
||||
$TMUX link-window -s main:mywin -t other:5 || fail "link-window failed"
|
||||
wait_for @w 'window-linked:other:mywin'
|
||||
$TMUX set -g @w 0 || fail "reset @w failed"
|
||||
$TMUX unlink-window -t other:5 || fail "unlink-window failed"
|
||||
wait_for @w 'window-unlinked:other:mywin'
|
||||
$TMUX set -g @w 0 || fail "reset @w failed"
|
||||
$TMUX kill-window -t main:mywin || fail "kill-window failed"
|
||||
wait_for @w 'window-unlinked:main:mywin'
|
||||
$TMUX set-hook -gu window-linked || fail "unset window-linked failed"
|
||||
$TMUX set-hook -gu window-unlinked || fail "unset window-unlinked failed"
|
||||
|
||||
# window-renamed sees the window id.
|
||||
window=$($TMUX display -pt main:0 '#{window_id}') ||
|
||||
fail "display window_id failed"
|
||||
$TMUX set -g @r 0 || fail "set @r failed"
|
||||
$TMUX set-hook -g window-renamed \
|
||||
'set -gF @r "#{hook}:#{hook_window}:#{hook_window_name}"' ||
|
||||
fail "set-hook window-renamed failed"
|
||||
$TMUX rename-window -t main:0 renamed || fail "rename-window failed"
|
||||
wait_for @r "window-renamed:$window:renamed"
|
||||
$TMUX set-hook -gu window-renamed || fail "unset window-renamed failed"
|
||||
|
||||
# window-layout-changed from split-window.
|
||||
$TMUX set -g @l 0 || fail "set @l failed"
|
||||
$TMUX set-hook -g window-layout-changed \
|
||||
'set -gF @l "#{hook}:#{hook_window}"' ||
|
||||
fail "set-hook window-layout-changed failed"
|
||||
$TMUX splitw -d -t main:0 || fail "split-window failed"
|
||||
wait_for @l "window-layout-changed:$window"
|
||||
$TMUX set-hook -gu window-layout-changed ||
|
||||
fail "unset window-layout-changed failed"
|
||||
|
||||
# window-pane-changed from select-pane.
|
||||
$TMUX set -g @p 0 || fail "set @p failed"
|
||||
$TMUX set-hook -g window-pane-changed \
|
||||
'set -gF @p "#{hook}:#{hook_window}"' ||
|
||||
fail "set-hook window-pane-changed failed"
|
||||
$TMUX selectp -t main:0.1 || fail "select-pane failed"
|
||||
wait_for @p "window-pane-changed:$window"
|
||||
$TMUX set-hook -gu window-pane-changed ||
|
||||
fail "unset window-pane-changed failed"
|
||||
|
||||
# session-window-changed from select-window.
|
||||
$TMUX neww -d -t main: -n w2 || fail "new-window w2 failed"
|
||||
$TMUX set -g @c 0 || fail "set @c failed"
|
||||
$TMUX set-hook -g session-window-changed \
|
||||
'set -gF @c "#{hook}:#{hook_session_name}"' ||
|
||||
fail "set-hook session-window-changed failed"
|
||||
$TMUX selectw -t main:w2 || fail "select-window failed"
|
||||
wait_for @c 'session-window-changed:main'
|
||||
$TMUX set-hook -gu session-window-changed ||
|
||||
fail "unset session-window-changed failed"
|
||||
|
||||
# pane-mode-changed from entering and leaving copy mode.
|
||||
$TMUX set -g @m 0 || fail "set @m failed"
|
||||
pane=$($TMUX display -pt main:0.0 '#{pane_id}') ||
|
||||
fail "display pane_id failed"
|
||||
$TMUX set-hook -g pane-mode-changed \
|
||||
'set -gF @m "#{hook}:#{hook_pane}:#{pane_in_mode}"' ||
|
||||
fail "set-hook pane-mode-changed failed"
|
||||
$TMUX copy-mode -t main:0.0 || fail "copy-mode failed"
|
||||
wait_for @m "pane-mode-changed:$pane:1"
|
||||
$TMUX send-keys -t main:0.0 -X cancel || fail "cancel failed"
|
||||
wait_for @m "pane-mode-changed:$pane:0"
|
||||
$TMUX set-hook -gu pane-mode-changed || fail "unset pane-mode-changed failed"
|
||||
|
||||
# pane-exited when a pane's command exits with remain-on-exit off.
|
||||
$TMUX set -g @x 0 || fail "set @x failed"
|
||||
$TMUX set-hook -g pane-exited 'set -gF @x "#{hook}:#{hook_pane}"' ||
|
||||
fail "set-hook pane-exited failed"
|
||||
pane=$($TMUX splitw -d -t main:0 -P -F '#{pane_id}' 'true') ||
|
||||
fail "split-window true failed"
|
||||
wait_for @x "pane-exited:$pane"
|
||||
$TMUX set-hook -gu pane-exited || fail "unset pane-exited failed"
|
||||
|
||||
# pane-died when a pane's command exits with remain-on-exit on.
|
||||
$TMUX set -g remain-on-exit on || fail "set remain-on-exit failed"
|
||||
$TMUX set -g @d 0 || fail "set @d failed"
|
||||
$TMUX set-hook -g pane-died 'set -gF @d "#{hook}:#{hook_pane}"' ||
|
||||
fail "set-hook pane-died failed"
|
||||
pane=$($TMUX splitw -d -t main:0 -P -F '#{pane_id}' 'true') ||
|
||||
fail "split-window remain-on-exit failed"
|
||||
wait_for @d "pane-died:$pane"
|
||||
$TMUX set-hook -gu pane-died || fail "unset pane-died failed"
|
||||
$TMUX killp -t "$pane" || fail "kill-pane failed"
|
||||
$TMUX set -g remain-on-exit off || fail "reset remain-on-exit failed"
|
||||
|
||||
# pane-title-changed when a pane sets its title.
|
||||
$TMUX set -g @t 0 || fail "set @t failed"
|
||||
$TMUX set-hook -g pane-title-changed \
|
||||
'set -gF @t "#{hook}:#{hook_pane}:#{pane_title}"' ||
|
||||
fail "set-hook pane-title-changed failed"
|
||||
pane=$($TMUX splitw -d -t main:0 -P -F '#{pane_id}' \
|
||||
'printf "\033]2;mytitle\007"; sleep 30') ||
|
||||
fail "split-window title failed"
|
||||
wait_for @t "pane-title-changed:$pane:mytitle"
|
||||
$TMUX set-hook -gu pane-title-changed ||
|
||||
fail "unset pane-title-changed failed"
|
||||
$TMUX killp -t "$pane" || fail "kill-pane title failed"
|
||||
|
||||
# client-attached and client-detached using a control client.
|
||||
$TMUX set -g @a 0 || fail "set @a failed"
|
||||
$TMUX set-hook -g client-attached 'set -gF @a "#{hook}"' ||
|
||||
fail "set-hook client-attached failed"
|
||||
$TMUX set-hook -g client-detached 'set -gF @a "#{hook}"' ||
|
||||
fail "set-hook client-detached failed"
|
||||
mkfifo "$OUT/fifo" || fail "mkfifo failed"
|
||||
$TMUX -C attach -t main <"$OUT/fifo" >"$OUT/control.out" 2>&1 &
|
||||
exec 3>"$OUT/fifo"
|
||||
wait_for @a 'client-attached'
|
||||
exec 3>&-
|
||||
wait_for @a 'client-detached'
|
||||
$TMUX set-hook -gu client-attached || fail "unset client-attached failed"
|
||||
$TMUX set-hook -gu client-detached || fail "unset client-detached failed"
|
||||
|
||||
exit 0
|
||||
155
regress/hooks.sh
Normal file
155
regress/hooks.sh
Normal file
@@ -0,0 +1,155 @@
|
||||
#!/bin/sh
|
||||
|
||||
PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
LC_ALL=C.UTF-8
|
||||
LANG=C.UTF-8
|
||||
export TERM LC_ALL LANG
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
OUT=$(mktemp -d)
|
||||
TMUX_TMPDIR="$OUT"
|
||||
export TMUX_TMPDIR
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
|
||||
fail()
|
||||
{
|
||||
echo "$*" >&2
|
||||
$TMUX kill-server 2>/dev/null || true
|
||||
rm -rf "$OUT"
|
||||
exit 1
|
||||
}
|
||||
|
||||
cleanup()
|
||||
{
|
||||
$TMUX kill-server 2>/dev/null || true
|
||||
rm -rf "$OUT"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
wait_for()
|
||||
{
|
||||
option=$1
|
||||
expected=$2
|
||||
i=0
|
||||
|
||||
while [ $i -lt 30 ]; do
|
||||
value=$($TMUX show -gqv "$option" 2>/dev/null || true)
|
||||
[ "$value" = "$expected" ] && return 0
|
||||
i=$((i + 1))
|
||||
sleep 0.2
|
||||
done
|
||||
fail "expected $option to be '$expected' but got '$value'"
|
||||
}
|
||||
|
||||
assert_unchanged()
|
||||
{
|
||||
option=$1
|
||||
expected=$2
|
||||
i=0
|
||||
|
||||
while [ $i -lt 10 ]; do
|
||||
value=$($TMUX show -gqv "$option" 2>/dev/null || true)
|
||||
[ "$value" = "$expected" ] || \
|
||||
fail "expected $option to remain '$expected' but got '$value'"
|
||||
i=$((i + 1))
|
||||
sleep 0.2
|
||||
done
|
||||
}
|
||||
|
||||
$TMUX new -d -s one || fail "new-session one failed"
|
||||
|
||||
# A global hook fires and sees the hook formats.
|
||||
$TMUX set -g @created 0 || fail "set @created failed"
|
||||
$TMUX set-hook -g session-created \
|
||||
'set -gF @created "#{hook}:#{hook_session_name}"' ||
|
||||
fail "set-hook -g session-created failed"
|
||||
$TMUX new -d -s two || fail "new-session two failed"
|
||||
wait_for @created 'session-created:two'
|
||||
|
||||
# Hooks are arrays: an appended command runs after the first.
|
||||
$TMUX set -g @second 0 || fail "set @second failed"
|
||||
$TMUX set-hook -ga session-created \
|
||||
'set -gF @second "#{@created}+second"' ||
|
||||
fail "set-hook -ga session-created failed"
|
||||
$TMUX new -d -s three || fail "new-session three failed"
|
||||
wait_for @created 'session-created:three'
|
||||
wait_for @second 'session-created:three+second'
|
||||
|
||||
# show-hooks lists both commands.
|
||||
shown=$($TMUX show-hooks -g session-created) ||
|
||||
fail "show-hooks -g failed"
|
||||
[ "$(echo "$shown" | wc -l)" -eq 2 ] ||
|
||||
fail "unexpected show-hooks output: $shown"
|
||||
echo "$shown" | grep -q '^session-created\[0\]' ||
|
||||
fail "missing first array item: $shown"
|
||||
echo "$shown" | grep -q '^session-created\[1\]' ||
|
||||
fail "missing second array item: $shown"
|
||||
|
||||
# Unsetting removes the whole hook.
|
||||
$TMUX set-hook -gu session-created || fail "set-hook -gu failed"
|
||||
shown=$($TMUX show-hooks -g session-created) ||
|
||||
fail "show-hooks -g after unset failed"
|
||||
if echo "$shown" | grep -q '\['; then
|
||||
fail "show-hooks showed removed hook: $shown"
|
||||
fi
|
||||
$TMUX set -g @created 0 || fail "reset @created failed"
|
||||
$TMUX new -d -s four || fail "new-session four failed"
|
||||
assert_unchanged @created 0
|
||||
|
||||
# An unknown hook name is rejected.
|
||||
if $TMUX set-hook -g no-such-hook 'display x' 2>/dev/null; then
|
||||
fail "unknown hook name was accepted"
|
||||
fi
|
||||
|
||||
# A session hook only fires for events in that session.
|
||||
$TMUX set -g @renamed 0 || fail "set @renamed failed"
|
||||
$TMUX set-hook -t one window-renamed \
|
||||
'set -gF @renamed "#{hook}:#{hook_window_name}"' ||
|
||||
fail "set-hook -t one window-renamed failed"
|
||||
$TMUX rename-window -t two:0 twoname || fail "rename-window two failed"
|
||||
assert_unchanged @renamed 0
|
||||
$TMUX rename-window -t one:0 onename || fail "rename-window one failed"
|
||||
wait_for @renamed 'window-renamed:onename'
|
||||
$TMUX set-hook -u -t one window-renamed || fail "set-hook -u failed"
|
||||
|
||||
# A pane hook only fires for events in that pane.
|
||||
pane2=$($TMUX splitw -d -t one:0 -P -F '#{pane_id}') ||
|
||||
fail "split-window failed"
|
||||
$TMUX set -g @mode 0 || fail "set @mode failed"
|
||||
$TMUX set-hook -p -t "$pane2" pane-mode-changed \
|
||||
'set -gF @mode "#{hook}:#{hook_pane}"' ||
|
||||
fail "set-hook -p pane-mode-changed failed"
|
||||
$TMUX copy-mode -t one:0.0 || fail "copy-mode pane 0 failed"
|
||||
assert_unchanged @mode 0
|
||||
$TMUX copy-mode -t "$pane2" || fail "copy-mode pane 1 failed"
|
||||
wait_for @mode "pane-mode-changed:$pane2"
|
||||
$TMUX send-keys -t "$pane2" -X cancel || fail "cancel failed"
|
||||
$TMUX set-hook -pu -t "$pane2" pane-mode-changed ||
|
||||
fail "set-hook -pu failed"
|
||||
|
||||
# A window hook only fires for events in that window.
|
||||
$TMUX set -g @wmode 0 || fail "set @wmode failed"
|
||||
$TMUX set-hook -w -t two:0 pane-mode-changed \
|
||||
'set -gF @wmode "#{hook}:#{hook_window_name}"' ||
|
||||
fail "set-hook -w pane-mode-changed failed"
|
||||
$TMUX copy-mode -t three:0.0 || fail "copy-mode three failed"
|
||||
assert_unchanged @wmode 0
|
||||
$TMUX copy-mode -t two:0.0 || fail "copy-mode two failed"
|
||||
wait_for @wmode 'pane-mode-changed:twoname'
|
||||
$TMUX set-hook -wu -t two:0 pane-mode-changed ||
|
||||
fail "set-hook -wu failed"
|
||||
|
||||
# Commands run from a hook do not fire hooks again.
|
||||
$TMUX set -g @renames '' || fail "set @renames failed"
|
||||
$TMUX set-hook -g window-renamed \
|
||||
'set -gF @renames "#{@renames}x" ; rename-window -t three:0 inner' ||
|
||||
fail "set-hook -g window-renamed failed"
|
||||
$TMUX rename-window -t three:0 outer || fail "rename-window outer failed"
|
||||
wait_for @renames 'x'
|
||||
assert_unchanged @renames 'x'
|
||||
name=$($TMUX display -pt three:0 '#{window_name}') ||
|
||||
fail "display window_name failed"
|
||||
[ "$name" = inner ] || fail "expected window name inner but got $name"
|
||||
|
||||
exit 0
|
||||
@@ -7,7 +7,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
TMP=$(mktemp)
|
||||
|
||||
@@ -7,7 +7,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
TMP=$(mktemp)
|
||||
|
||||
@@ -7,7 +7,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
TMP=$(mktemp)
|
||||
|
||||
@@ -2,7 +2,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
|
||||
TMP=$(mktemp)
|
||||
EXP=$(mktemp)
|
||||
|
||||
@@ -4,7 +4,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
sleep 1
|
||||
$TMUX -f/dev/null new -x20 -y2 -d \; set -g escape-time 0 || exit 1
|
||||
|
||||
@@ -8,8 +8,8 @@ export PATH TERM LANG LC_ALL
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
|
||||
TMUX="$TEST_TMUX -Linput-reflow-stress-$$ -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -Linput-reflow-stress-outer-$$ -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -LtestB$$ -f/dev/null"
|
||||
|
||||
TMP=$(mktemp "${TMPDIR:-/tmp}/input-reflow-stress.XXXXXX") || exit 1
|
||||
EXP=$(mktemp "${TMPDIR:-/tmp}/input-reflow-stress.XXXXXX") || exit 1
|
||||
|
||||
@@ -4,7 +4,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
|
||||
$TMUX kill-server 2>/dev/null
|
||||
sleep 0.5
|
||||
|
||||
@@ -15,7 +15,8 @@ import tempfile
|
||||
import time
|
||||
|
||||
tmux = sys.argv[1]
|
||||
server = [tmux, "-Ltest", "-f/dev/null"]
|
||||
label = "testA%d" % os.getpid()
|
||||
server = [tmux, "-L" + label, "-f/dev/null"]
|
||||
|
||||
def run(*args, check=True):
|
||||
return subprocess.run(server + list(args), check=check,
|
||||
@@ -25,7 +26,7 @@ def attach():
|
||||
pid, fd = os.forkpty()
|
||||
if pid == 0:
|
||||
os.environ["TERM"] = "xterm-256color"
|
||||
os.execl(tmux, tmux, "-Ltest", "-f/dev/null", "attach-session",
|
||||
os.execl(tmux, tmux, "-L" + label, "-f/dev/null", "attach-session",
|
||||
"-t", "requests")
|
||||
os.set_blocking(fd, False)
|
||||
return pid, fd
|
||||
|
||||
@@ -6,7 +6,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
sleep 1
|
||||
|
||||
|
||||
@@ -8,8 +8,8 @@ export TERM LC_ALL LANG
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
|
||||
TMUX="$TEST_TMUX -Llifecycle-deferred -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -Llifecycle-deferred-outer -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -LtestB$$ -f/dev/null"
|
||||
|
||||
TMPDIR=$(mktemp -d)
|
||||
IN="$TMPDIR/in"
|
||||
|
||||
@@ -8,20 +8,30 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMP=$(mktemp -d) || exit 1
|
||||
TMUX_TMPDIR="$TMP"
|
||||
export TMUX_TMPDIR
|
||||
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -Ltest2 -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -LtestB$$ -f/dev/null"
|
||||
|
||||
cleanup()
|
||||
cleanup_servers()
|
||||
{
|
||||
$TMUX kill-server 2>/dev/null
|
||||
$TMUX2 kill-server 2>/dev/null
|
||||
sleep 0.5
|
||||
}
|
||||
|
||||
cleanup()
|
||||
{
|
||||
cleanup_servers
|
||||
rm -rf "$TMP"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
fail()
|
||||
{
|
||||
echo "$1"
|
||||
echo "$1" >&2
|
||||
cleanup
|
||||
exit 1
|
||||
}
|
||||
@@ -53,7 +63,7 @@ wait_for()
|
||||
{
|
||||
i=0
|
||||
while [ "$i" -lt 50 ]; do
|
||||
capture | grep -q "$1" && return 0
|
||||
capture | grep -F -q "$1" && return 0
|
||||
sleep 0.2
|
||||
i=$((i + 1))
|
||||
done
|
||||
@@ -95,7 +105,7 @@ start_client()
|
||||
s=$1
|
||||
cmd=${2:-cat}
|
||||
|
||||
cleanup
|
||||
cleanup_servers
|
||||
$TMUX new-session -d -s "$s" -n main -x 80 -y 24 "$cmd" || \
|
||||
fail "$s: new-session failed"
|
||||
$TMUX2 new-session -d -s out -x 80 -y 24 "$TMUX attach -t $s" || \
|
||||
@@ -287,7 +297,7 @@ test_copy_mode()
|
||||
assert_alive "copy-mode exit"
|
||||
}
|
||||
|
||||
cleanup
|
||||
cleanup_servers
|
||||
test_choose_tree
|
||||
test_choose_buffer
|
||||
test_choose_client
|
||||
|
||||
@@ -6,7 +6,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
TMP=$(mktemp)
|
||||
|
||||
@@ -6,7 +6,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
TMP=$(mktemp)
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
PATH=/bin:/usr/bin
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
TERM=$($TMUX start \; show -gv default-terminal)
|
||||
|
||||
@@ -8,7 +8,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
TMP=$(mktemp)
|
||||
|
||||
@@ -6,7 +6,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
TMP=$(mktemp)
|
||||
|
||||
@@ -6,7 +6,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
TMP=$(mktemp)
|
||||
|
||||
@@ -3,12 +3,14 @@
|
||||
# Tests of array options in the options engine (options_array_* in options.c
|
||||
# and the array handling in cmd-set-option.c / cmd-show-options.c).
|
||||
#
|
||||
# Array options are indexed by integer. This exercises: setting a whole array
|
||||
# from a separator-delimited string; per-index set with option[N]; -a append
|
||||
# (which lands at the next free index); show ordering by ascending index and
|
||||
# preservation of gaps; per-index unset with -u; show -v of a single index and
|
||||
# of a missing index; and per-option separators (user-keys splits only on
|
||||
# comma, update-environment on space or comma).
|
||||
# Array options are keyed by string, with numeric-looking keys kept compatible
|
||||
# with the old numeric forms. This exercises: setting a whole array from a
|
||||
# separator-delimited string; per-key set with option[key]; -a append (which
|
||||
# lands at the next free numeric key); show ordering by numeric keys first in
|
||||
# ascending order followed by string keys in strcmp order; preservation of gaps;
|
||||
# per-key unset with -u; show -v of a single key and of a missing key; and
|
||||
# per-option separators (user-keys splits only on comma, update-environment on
|
||||
# space or comma).
|
||||
#
|
||||
# update-environment (session), status-format (session), user-keys (server)
|
||||
# and command-alias (server) are used as representative array options.
|
||||
@@ -20,7 +22,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
check_value()
|
||||
@@ -87,41 +89,59 @@ $TMUX new-session -d -s main -x 80 -y 24 || exit 1
|
||||
# --- whole-array assignment splits on the separator -----------------------
|
||||
#
|
||||
# update-environment has the default " ," separator, so a single string value
|
||||
# is split into consecutive indices starting at 0.
|
||||
# is split into consecutive numeric keys starting at 0.
|
||||
check_ok set -g update-environment "AAA BBB,CCC"
|
||||
check_array "-g update-environment" "update-environment[0] AAA
|
||||
update-environment[1] BBB
|
||||
update-environment[2] CCC"
|
||||
|
||||
# --- -a append goes to the next free index --------------------------------
|
||||
# --- -a append goes to the next free numeric key --------------------------
|
||||
check_ok set -ga update-environment "DDD"
|
||||
check_array "-g update-environment" "update-environment[0] AAA
|
||||
update-environment[1] BBB
|
||||
update-environment[2] CCC
|
||||
update-environment[3] DDD"
|
||||
|
||||
# --- per-index unset leaves a gap; show preserves order and gaps ----------
|
||||
# --- per-key unset leaves a gap; show preserves order and gaps ------------
|
||||
check_ok set -gu update-environment[1]
|
||||
check_array "-g update-environment" "update-environment[0] AAA
|
||||
update-environment[2] CCC
|
||||
update-environment[3] DDD"
|
||||
# show -v of an existing index returns its value; a missing index is empty.
|
||||
# show -v of an existing key returns its value; a missing key is empty.
|
||||
check_value "-gv update-environment[0]" "AAA"
|
||||
check_value "-gv update-environment[1]" ""
|
||||
check_ok set -g update-environment[notify] "EEE"
|
||||
check_ok set -ga update-environment "FFF"
|
||||
check_array "-g update-environment" "update-environment[0] AAA
|
||||
update-environment[1] FFF
|
||||
update-environment[2] CCC
|
||||
update-environment[3] DDD
|
||||
update-environment[notify] EEE"
|
||||
|
||||
# --- explicit indexed set, including out-of-order and gaps ----------------
|
||||
# --- explicit keyed set, including out-of-order and gaps ------------------
|
||||
#
|
||||
# status-format is a session array; assigning an empty string first clears its
|
||||
# multi-index default, then set specific indices out of order and confirm show
|
||||
# sorts by ascending index and keeps the gap at [1].
|
||||
# multi-index default, then set specific keys out of order and confirm show
|
||||
# sorts by ascending numeric key and keeps the gap at [1].
|
||||
check_ok set -g status-format ""
|
||||
check_array "-g status-format" "status-format"
|
||||
check_ok set -g status-format[5] "five"
|
||||
check_ok set -g status-format[0] "zero"
|
||||
check_ok set -g status-format[2] "two"
|
||||
check_ok set -g status-format[01] "one"
|
||||
check_ok set -g status-format[zoom] "zoom"
|
||||
check_ok set -g status-format[foo-bar] "foo-bar"
|
||||
check_ok set -g status-format[xterm-256color] "xterm"
|
||||
check_array "-g status-format" "status-format[0] zero
|
||||
status-format[1] one
|
||||
status-format[2] two
|
||||
status-format[5] five"
|
||||
status-format[5] five
|
||||
status-format[foo-bar] foo-bar
|
||||
status-format[xterm-256color] xterm
|
||||
status-format[zoom] zoom"
|
||||
check_value "-gv status-format[01]" "one"
|
||||
check_ok set -gu status-format[zoom]
|
||||
check_value "-gv status-format[zoom]" ""
|
||||
|
||||
# --- comma-only separator (user-keys) -------------------------------------
|
||||
#
|
||||
@@ -133,11 +153,15 @@ user-keys[1] "Two Three"'
|
||||
|
||||
# --- command-type array (a hook) ------------------------------------------
|
||||
#
|
||||
# Hooks are command arrays: an indexed value is parsed as a command when set
|
||||
# Hooks are command arrays: a keyed value is parsed as a command when set
|
||||
# and re-printed from the parsed command list; a syntax error is reported.
|
||||
check_ok set -g alert-bell[0] "display-message hi"
|
||||
check_value "-gv alert-bell[0]" "display-message hi"
|
||||
check_fail "syntax error" set -g alert-bell[0] "if -x {"
|
||||
check_ok set-hook -g window-renamed[notify] "display-message renamed"
|
||||
check_value "-gv window-renamed[notify]" "display-message renamed"
|
||||
check_ok set-hook -gu window-renamed[notify]
|
||||
check_value "-gv window-renamed[notify]" ""
|
||||
|
||||
# --- colour-type array ----------------------------------------------------
|
||||
#
|
||||
@@ -146,11 +170,11 @@ check_ok set -w pane-colours[0] red
|
||||
check_value "-wv pane-colours[0]" "red"
|
||||
check_fail "bad colour: xxxyyy" set -w pane-colours[1] xxxyyy
|
||||
|
||||
# --- -o refuses to overwrite an already-set index -------------------------
|
||||
# --- -o refuses to overwrite an already-set key ---------------------------
|
||||
check_ok set -g command-alias[9] "x=list-keys"
|
||||
check_fail "already set: command-alias[9]" set -go command-alias[9] "y=list-keys"
|
||||
|
||||
# --- non-array option rejects index syntax --------------------------------
|
||||
# --- non-array option rejects key syntax ----------------------------------
|
||||
#
|
||||
# status-left is a plain string; indexing it is an error.
|
||||
check_fail "not an array: status-left[0]" set -g status-left[0] "x"
|
||||
|
||||
@@ -17,7 +17,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
# check_value $args $expected
|
||||
|
||||
@@ -17,7 +17,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
check_value()
|
||||
|
||||
@@ -4,7 +4,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
$TMUX new -d
|
||||
|
||||
@@ -30,7 +30,7 @@ LC_ALL=C.UTF-8
|
||||
export TERM LANG LC_ALL
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
# check_ok $cmd...
|
||||
|
||||
@@ -7,8 +7,8 @@ LANG=C.UTF-8
|
||||
export TERM LC_ALL LANG
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
OUT="$TEST_TMUX -Ltest -f/dev/null" # outer (host for the client)
|
||||
IN="$TEST_TMUX -Ltest2 -f/dev/null" # inner (under test)
|
||||
OUT="$TEST_TMUX -LtestA$$ -f/dev/null" # outer (host for the client)
|
||||
IN="$TEST_TMUX -LtestB$$ -f/dev/null" # inner (under test)
|
||||
|
||||
$OUT kill-server 2>/dev/null
|
||||
$IN kill-server 2>/dev/null
|
||||
|
||||
@@ -20,8 +20,8 @@ LANG=C.UTF-8
|
||||
export TERM LC_ALL LANG
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
OUT="$TEST_TMUX -Ltest -f/dev/null" # outer (host for the client)
|
||||
IN="$TEST_TMUX -Ltest2 -f/dev/null" # inner (under test)
|
||||
OUT="$TEST_TMUX -LtestA$$ -f/dev/null" # outer (host for the client)
|
||||
IN="$TEST_TMUX -LtestB$$ -f/dev/null" # inner (under test)
|
||||
|
||||
$OUT kill-server 2>/dev/null
|
||||
$IN kill-server 2>/dev/null
|
||||
|
||||
@@ -7,7 +7,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
TMP=$(mktemp)
|
||||
|
||||
@@ -17,8 +17,8 @@ LC_ALL=C.UTF-8
|
||||
export TERM LC_ALL
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -Ltest2 -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -LtestB$$ -f/dev/null"
|
||||
RESULTS=screen-redraw-results
|
||||
|
||||
TMP=$(mktemp)
|
||||
|
||||
@@ -18,8 +18,8 @@ LC_ALL=C.UTF-8
|
||||
export TERM LC_ALL
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -Ltest2 -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -LtestB$$ -f/dev/null"
|
||||
RESULTS=screen-redraw-results
|
||||
|
||||
TMP=$(mktemp)
|
||||
|
||||
@@ -16,8 +16,8 @@ LC_ALL=C.UTF-8
|
||||
export TERM LC_ALL
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -Ltest2 -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -LtestB$$ -f/dev/null"
|
||||
RESULTS=screen-redraw-results
|
||||
|
||||
TMP=$(mktemp)
|
||||
|
||||
@@ -18,8 +18,8 @@ LC_ALL=C.UTF-8
|
||||
export TERM LC_ALL
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -Ltest2 -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -LtestB$$ -f/dev/null"
|
||||
RESULTS=screen-redraw-results
|
||||
|
||||
TMP=$(mktemp)
|
||||
|
||||
@@ -18,8 +18,8 @@ LC_ALL=C.UTF-8
|
||||
export TERM LC_ALL
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -Ltest2 -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -LtestB$$ -f/dev/null"
|
||||
RESULTS=screen-redraw-results
|
||||
|
||||
TMP=$(mktemp)
|
||||
|
||||
@@ -17,8 +17,8 @@ LC_ALL=C.UTF-8
|
||||
export TERM LC_ALL
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -Ltest2 -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -LtestB$$ -f/dev/null"
|
||||
RESULTS=screen-redraw-results
|
||||
|
||||
TMP=$(mktemp)
|
||||
|
||||
@@ -16,8 +16,8 @@ LC_ALL=C.UTF-8
|
||||
export TERM LC_ALL
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -Ltest2 -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -LtestB$$ -f/dev/null"
|
||||
RESULTS=screen-redraw-results
|
||||
|
||||
TMP=$(mktemp)
|
||||
|
||||
@@ -20,8 +20,8 @@ LC_ALL=C.UTF-8
|
||||
export TERM LC_ALL
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -Ltest2 -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -LtestB$$ -f/dev/null"
|
||||
RESULTS=screen-redraw-results
|
||||
|
||||
TMP=$(mktemp)
|
||||
|
||||
@@ -24,8 +24,8 @@ LC_ALL=C.UTF-8
|
||||
export TERM LC_ALL
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -Ltest2 -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -LtestB$$ -f/dev/null"
|
||||
RESULTS=screen-redraw-results
|
||||
|
||||
TMP=$(mktemp)
|
||||
|
||||
@@ -13,8 +13,8 @@ LC_ALL=C.UTF-8
|
||||
export TERM LC_ALL
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -Ltest2 -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -LtestB$$ -f/dev/null"
|
||||
RESULTS=screen-redraw-results
|
||||
|
||||
TMP=$(mktemp)
|
||||
|
||||
@@ -10,7 +10,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
TMP1=$(mktemp)
|
||||
|
||||
@@ -27,7 +27,7 @@ LC_ALL=C.UTF-8
|
||||
export TERM LANG LC_ALL
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
# check_ok $cmd...
|
||||
|
||||
@@ -10,7 +10,7 @@ export TERM LC_ALL LANG
|
||||
OUT=$(mktemp -d)
|
||||
TMUX_TMPDIR="$OUT"
|
||||
export TMUX_TMPDIR
|
||||
TMUX="$TEST_TMUX -Ltest-hook-B-$$ -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
|
||||
fail()
|
||||
{
|
||||
|
||||
63
regress/set-hook-R.sh
Normal file
63
regress/set-hook-R.sh
Normal file
@@ -0,0 +1,63 @@
|
||||
#!/bin/sh
|
||||
|
||||
PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
LC_ALL=C.UTF-8
|
||||
LANG=C.UTF-8
|
||||
export TERM LC_ALL LANG
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
OUT=$(mktemp -d)
|
||||
TMUX_TMPDIR="$OUT"
|
||||
export TMUX_TMPDIR
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
|
||||
fail()
|
||||
{
|
||||
echo "$*" >&2
|
||||
$TMUX kill-server 2>/dev/null || true
|
||||
rm -rf "$OUT"
|
||||
exit 1
|
||||
}
|
||||
|
||||
cleanup()
|
||||
{
|
||||
$TMUX kill-server 2>/dev/null || true
|
||||
rm -rf "$OUT"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
wait_for()
|
||||
{
|
||||
option=$1
|
||||
expected=$2
|
||||
i=0
|
||||
|
||||
while [ $i -lt 30 ]; do
|
||||
value=$($TMUX show -gqv "$option" 2>/dev/null || true)
|
||||
[ "$value" = "$expected" ] && return 0
|
||||
i=$((i + 1))
|
||||
sleep 0.2
|
||||
done
|
||||
fail "expected $option to be '$expected' but got '$value'"
|
||||
}
|
||||
|
||||
$TMUX new -d -s one || fail "new-session one failed"
|
||||
$TMUX new -d -s two || fail "new-session two failed"
|
||||
|
||||
pane=$($TMUX display -pt two:0.0 '#{pane_id}') ||
|
||||
fail "display-message pane failed"
|
||||
|
||||
$TMUX set -g @seen 0 || fail "set @seen failed"
|
||||
$TMUX set-hook -g @manual \
|
||||
'set -gF @seen "#{hook}:#{session_name}:#{window_index}:#{pane_id}"' ||
|
||||
fail "set-hook @manual failed"
|
||||
|
||||
[ "$($TMUX show -gqv @seen)" = 0 ] ||
|
||||
fail "hook ran before set-hook -R"
|
||||
|
||||
$TMUX set-hook -g -R -t two:0.0 @manual ||
|
||||
fail "set-hook -R @manual failed"
|
||||
wait_for @seen "@manual:two:0:$pane"
|
||||
|
||||
exit 0
|
||||
@@ -17,9 +17,9 @@ if command -v bash >/dev/null 2>&1; then
|
||||
fi
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
TMUX2="$TEST_TMUX -Ltest2 -f/dev/null"
|
||||
TMUX2="$TEST_TMUX -LtestB$$ -f/dev/null"
|
||||
$TMUX2 kill-server 2>/dev/null
|
||||
|
||||
$TMUX2 -f/dev/null new -d "$TMUX -f/dev/null new -- $shell"
|
||||
|
||||
@@ -27,7 +27,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
# check $target $expected [format]
|
||||
|
||||
@@ -29,7 +29,7 @@ PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
TMUX="$TEST_TMUX -LtestA$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
|
||||
# check $target $expected [format]
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user