mirror of
https://github.com/tmux/tmux.git
synced 2026-09-18 11:04:46 +00:00
Compare commits
235 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d176f1f89c | ||
|
|
2d0845860a | ||
|
|
5ae701aab5 | ||
|
|
0d016195ac | ||
|
|
fc2de240d2 | ||
|
|
7c1ef6a387 | ||
|
|
0b538b6f2a | ||
|
|
3d26aa0dfb | ||
|
|
51d037e881 | ||
|
|
e5fb88fb85 | ||
|
|
787234eff4 | ||
|
|
6b1219b370 | ||
|
|
ed48555bdd | ||
|
|
ba9faae8b6 | ||
|
|
6935dee976 | ||
|
|
12473bb6d3 | ||
|
|
280a962328 | ||
|
|
37633ff957 | ||
|
|
1c2fc8c3c4 | ||
|
|
d3adecd819 | ||
|
|
0a71af41be | ||
|
|
8fb484da37 | ||
|
|
6e6a434a2d | ||
|
|
f23ea9e977 | ||
|
|
55cfdbaa3f | ||
|
|
1b5a07a740 | ||
|
|
00b0af7021 | ||
|
|
89027bd22c | ||
|
|
ff8de1a106 | ||
|
|
0c5e6770df | ||
|
|
c2ad33a04c | ||
|
|
c0a5e10313 | ||
|
|
1c394b8606 | ||
|
|
505d557fbb | ||
|
|
a63e429d22 | ||
|
|
de086f9848 | ||
|
|
6643acb375 | ||
|
|
c25cb107bb | ||
|
|
9dba08ac8b | ||
|
|
3ec115115d | ||
|
|
09c91b8931 | ||
|
|
de1940065a | ||
|
|
748ef8b2ae | ||
|
|
2ecf0a9053 | ||
|
|
b82048eb18 | ||
|
|
9d58ff97fe | ||
|
|
51b787e449 | ||
|
|
7654b518f1 | ||
|
|
52877c9af1 | ||
|
|
265f22be49 | ||
|
|
2a26c738bd | ||
|
|
02b37b3c69 | ||
|
|
d8370864f3 | ||
|
|
ffe48f00e3 | ||
|
|
49dff83a00 | ||
|
|
95afd7549c | ||
|
|
06ee890db3 | ||
|
|
e680420c89 | ||
|
|
357ee692bd | ||
|
|
347baa6f3e | ||
|
|
cc922de758 | ||
|
|
dbca906ef5 | ||
|
|
1fc4dcb76f | ||
|
|
dcd7d1c8e6 | ||
|
|
72e768ef14 | ||
|
|
047f61aad6 | ||
|
|
d04b1ffca5 | ||
|
|
c93e2f2332 | ||
|
|
e7c29d0ceb | ||
|
|
6c46358be8 | ||
|
|
b0ff8af9ac | ||
|
|
624db256c6 | ||
|
|
cfb15d158e | ||
|
|
34c7881ddd | ||
|
|
f06d930445 | ||
|
|
b29f5688bd | ||
|
|
333e2f266a | ||
|
|
af94399473 | ||
|
|
3d35f26031 | ||
|
|
b1c72ec48c | ||
|
|
8dee34459b | ||
|
|
e7f649e40a | ||
|
|
5843fbc6ee | ||
|
|
c8eca3a69d | ||
|
|
12fdcea8b8 | ||
|
|
035447b08f | ||
|
|
55b2e748e7 | ||
|
|
3246331876 | ||
|
|
6d9fbb0e97 | ||
|
|
14fc4a06a6 | ||
|
|
cba4ba9cdc | ||
|
|
937d99150c | ||
|
|
0a6c846091 | ||
|
|
c6b8ad6e7e | ||
|
|
d92a479d2f | ||
|
|
f242182840 | ||
|
|
f5871369cc | ||
|
|
b1b184cdb8 | ||
|
|
1a6de01210 | ||
|
|
1dd2589a42 | ||
|
|
3485e1c089 | ||
|
|
6f7965e4f1 | ||
|
|
1ba8fa6f04 | ||
|
|
6eb67fcc5f | ||
|
|
a8abea8247 | ||
|
|
d4defd943a | ||
|
|
eafd2bed5d | ||
|
|
6549765930 | ||
|
|
6cb2233cd2 | ||
|
|
9ad75e1dc3 | ||
|
|
bec0f7d975 | ||
|
|
4b772fd783 | ||
|
|
1d026b921c | ||
|
|
fcbb6a7384 | ||
|
|
bdc01f44de | ||
|
|
d2c23773ff | ||
|
|
38dc3ec0da | ||
|
|
c03acc9572 | ||
|
|
30e133d36a | ||
|
|
0890df5891 | ||
|
|
d223a49d18 | ||
|
|
26285e183e | ||
|
|
408e9f1481 | ||
|
|
7c8344930b | ||
|
|
482e254a49 | ||
|
|
eb65331403 | ||
|
|
9031f59f7b | ||
|
|
b86bd1fcd0 | ||
|
|
c156e597dc | ||
|
|
bb750b07bc | ||
|
|
0e6fe5a097 | ||
|
|
13de7cafb2 | ||
|
|
057b688fc7 | ||
|
|
45bb3e7ffc | ||
|
|
8ced9c332c | ||
|
|
9fcd5ce03d | ||
|
|
a41e6e2ed2 | ||
|
|
e54855ef88 | ||
|
|
7a18fa281d | ||
|
|
aed9018807 | ||
|
|
97b5f22a70 | ||
|
|
748dab2f38 | ||
|
|
3c11129b04 | ||
|
|
6e0e343f23 | ||
|
|
cc27470cb6 | ||
|
|
fb527fa7db | ||
|
|
87976aa48e | ||
|
|
863923472a | ||
|
|
778a15b64a | ||
|
|
5eaf5570c4 | ||
|
|
cbe0f1f1e9 | ||
|
|
97472e374f | ||
|
|
7a28aa0dd7 | ||
|
|
b1054ac227 | ||
|
|
1618b98533 | ||
|
|
5b6ed54817 | ||
|
|
d23a2b7e97 | ||
|
|
ab92b27226 | ||
|
|
eb6efdf17a | ||
|
|
b182791052 | ||
|
|
97a7f174ce | ||
|
|
654758e622 | ||
|
|
c8887a5846 | ||
|
|
56779f9542 | ||
|
|
f474838e22 | ||
|
|
19393e13db | ||
|
|
301b10de8d | ||
|
|
aa2fd3a151 | ||
|
|
2dd604949f | ||
|
|
ec481ac82a | ||
|
|
7afee45635 | ||
|
|
385d18590a | ||
|
|
bc9252f6e3 | ||
|
|
6c76f2a7c7 | ||
|
|
bf187170b1 | ||
|
|
14837e8e0f | ||
|
|
b44cdf1006 | ||
|
|
5d73f90133 | ||
|
|
34a6a9d3a1 | ||
|
|
f92a4e611b | ||
|
|
b3deb9ec86 | ||
|
|
a92653f2b2 | ||
|
|
29cdab650b | ||
|
|
574a4eccb5 | ||
|
|
42c0641daf | ||
|
|
11b6e7844a | ||
|
|
f1b67152af | ||
|
|
b6be437bab | ||
|
|
3d7f421809 | ||
|
|
fa6d33f742 | ||
|
|
dc22196394 | ||
|
|
3ea458b9dc | ||
|
|
86128a7f06 | ||
|
|
de60750506 | ||
|
|
f07ac3068b | ||
|
|
7ec94fda08 | ||
|
|
9231c80cd8 | ||
|
|
4702e58ee5 | ||
|
|
2719549cf2 | ||
|
|
cd26f29fb8 | ||
|
|
9c350af582 | ||
|
|
c019b3dad9 | ||
|
|
8cb4aabb8b | ||
|
|
7ad8b3366d | ||
|
|
c6c8f77bc0 | ||
|
|
f415a70c0b | ||
|
|
da31d94c2a | ||
|
|
5c0db5a293 | ||
|
|
d533d7c97c | ||
|
|
490802099d | ||
|
|
34dd42dc7f | ||
|
|
b374868750 | ||
|
|
538688486e | ||
|
|
27111bd76d | ||
|
|
4a3f380fd2 | ||
|
|
4ec7e66e90 | ||
|
|
a42e425d44 | ||
|
|
2179c3e420 | ||
|
|
d5c9196348 | ||
|
|
97156f3382 | ||
|
|
27c58c764d | ||
|
|
1564584ba9 | ||
|
|
fd10db5a62 | ||
|
|
6f683da2e9 | ||
|
|
a6a06c5aa6 | ||
|
|
4d1ab1ba2a | ||
|
|
d7a6a8e35b | ||
|
|
bf2e078ecf | ||
|
|
a25ce36925 | ||
|
|
a0f4038df2 | ||
|
|
7d8c1ae295 | ||
|
|
df7c2e605b | ||
|
|
ea51cdb3f2 | ||
|
|
fe986a52d6 | ||
|
|
34fd261a4f |
2
.github/CONTRIBUTING.md
vendored
2
.github/CONTRIBUTING.md
vendored
@@ -63,7 +63,7 @@ tmux -vv -Ltest -f/dev/null new
|
|||||||
|
|
||||||
Or if you need your configuration:
|
Or if you need your configuration:
|
||||||
|
|
||||||
~~~base
|
~~~bash
|
||||||
tmux kill-server
|
tmux kill-server
|
||||||
tmux -vv new
|
tmux -vv new
|
||||||
~~~
|
~~~
|
||||||
|
|||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -7,6 +7,8 @@
|
|||||||
*~
|
*~
|
||||||
.deps/
|
.deps/
|
||||||
.dirstamp
|
.dirstamp
|
||||||
|
.serena/
|
||||||
|
AGENTS.md
|
||||||
Makefile
|
Makefile
|
||||||
Makefile.in
|
Makefile.in
|
||||||
aclocal.m4
|
aclocal.m4
|
||||||
|
|||||||
@@ -184,6 +184,8 @@ dist_tmux_SOURCES = \
|
|||||||
paste.c \
|
paste.c \
|
||||||
popup.c \
|
popup.c \
|
||||||
proc.c \
|
proc.c \
|
||||||
|
prompt.c \
|
||||||
|
prompt-history.c \
|
||||||
regsub.c \
|
regsub.c \
|
||||||
resize.c \
|
resize.c \
|
||||||
screen-redraw.c \
|
screen-redraw.c \
|
||||||
@@ -209,12 +211,14 @@ dist_tmux_SOURCES = \
|
|||||||
tty.c \
|
tty.c \
|
||||||
utf8-combined.c \
|
utf8-combined.c \
|
||||||
utf8.c \
|
utf8.c \
|
||||||
|
window-border.c \
|
||||||
window-buffer.c \
|
window-buffer.c \
|
||||||
window-client.c \
|
window-client.c \
|
||||||
window-clock.c \
|
window-clock.c \
|
||||||
window-copy.c \
|
window-copy.c \
|
||||||
window-customize.c \
|
window-customize.c \
|
||||||
window-tree.c \
|
window-tree.c \
|
||||||
|
window-visible.c \
|
||||||
window.c \
|
window.c \
|
||||||
xmalloc.c \
|
xmalloc.c \
|
||||||
xmalloc.h
|
xmalloc.h
|
||||||
|
|||||||
@@ -998,7 +998,7 @@ args_string_percentage(const char *value, long long minval, long long maxval,
|
|||||||
copy = xstrdup(value);
|
copy = xstrdup(value);
|
||||||
copy[valuelen - 1] = '\0';
|
copy[valuelen - 1] = '\0';
|
||||||
|
|
||||||
ll = strtonum(copy, 0, 100, &errstr);
|
ll = strtonum(copy, 0, 1000, &errstr);
|
||||||
free(copy);
|
free(copy);
|
||||||
if (errstr != NULL) {
|
if (errstr != NULL) {
|
||||||
*cause = xstrdup(errstr);
|
*cause = xstrdup(errstr);
|
||||||
@@ -1066,7 +1066,7 @@ args_string_percentage_and_expand(const char *value, long long minval,
|
|||||||
copy[valuelen - 1] = '\0';
|
copy[valuelen - 1] = '\0';
|
||||||
|
|
||||||
f = format_single_from_target(item, copy);
|
f = format_single_from_target(item, copy);
|
||||||
ll = strtonum(f, 0, 100, &errstr);
|
ll = strtonum(f, 0, 1000, &errstr);
|
||||||
free(f);
|
free(f);
|
||||||
free(copy);
|
free(copy);
|
||||||
if (errstr != NULL) {
|
if (errstr != NULL) {
|
||||||
|
|||||||
2
cfg.c
2
cfg.c
@@ -56,7 +56,7 @@ cfg_done(__unused struct cmdq_item *item, __unused void *data)
|
|||||||
if (cfg_item != NULL)
|
if (cfg_item != NULL)
|
||||||
cmdq_continue(cfg_item);
|
cmdq_continue(cfg_item);
|
||||||
|
|
||||||
status_prompt_load_history();
|
prompt_load_history();
|
||||||
|
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,9 +58,14 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
struct session *dst_s = target->s;
|
struct session *dst_s = target->s;
|
||||||
struct window_pane *wp = source->wp;
|
struct window_pane *wp = source->wp;
|
||||||
struct window *w = wl->window;
|
struct window *w = wl->window;
|
||||||
char *name, *cause, *cp;
|
char *newname, *cause, *cp;
|
||||||
int idx = target->idx, before;
|
int idx = target->idx, before;
|
||||||
const char *template;
|
const char *template, *name = args_get(args, 'n');
|
||||||
|
|
||||||
|
if (name != NULL && !check_name(name, WINDOW_NAME_FORBID)) {
|
||||||
|
cmdq_error(item, "invalid window name: %s", name);
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
before = args_has(args, 'b');
|
before = args_has(args, 'b');
|
||||||
if (args_has(args, 'a') || before) {
|
if (args_has(args, 'a') || before) {
|
||||||
@@ -80,8 +85,8 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
free(cause);
|
free(cause);
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
if (args_has(args, 'n')) {
|
if (name != NULL) {
|
||||||
window_set_name(w, args_get(args, 'n'));
|
window_set_name(w, name, WINDOW_NAME_FORBID);
|
||||||
options_set_number(w->options, "automatic-rename", 0);
|
options_set_number(w->options, "automatic-rename", 0);
|
||||||
}
|
}
|
||||||
server_unlink_window(src_s, wl);
|
server_unlink_window(src_s, wl);
|
||||||
@@ -109,12 +114,12 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
w->active = wp;
|
w->active = wp;
|
||||||
w->latest = tc;
|
w->latest = tc;
|
||||||
|
|
||||||
if (!args_has(args, 'n')) {
|
if (name == NULL) {
|
||||||
name = default_window_name(w);
|
newname = default_window_name(w);
|
||||||
window_set_name(w, name);
|
window_set_name(w, newname, WINDOW_NAME_FORBID);
|
||||||
free(name);
|
free(newname);
|
||||||
} else {
|
} else {
|
||||||
window_set_name(w, args_get(args, 'n'));
|
window_set_name(w, name, 0);
|
||||||
options_set_number(w->options, "automatic-rename", 0);
|
options_set_number(w->options, "automatic-rename", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -318,6 +318,7 @@ cmd_capture_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
grid_clear_history(wp->base.grid);
|
grid_clear_history(wp->base.grid);
|
||||||
if (args_has(args, 'H'))
|
if (args_has(args, 'H'))
|
||||||
screen_reset_hyperlinks(wp->screen);
|
screen_reset_hyperlinks(wp->screen);
|
||||||
|
server_redraw_window(wp->window);
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ const struct cmd_entry cmd_choose_tree_entry = {
|
|||||||
.name = "choose-tree",
|
.name = "choose-tree",
|
||||||
.alias = NULL,
|
.alias = NULL,
|
||||||
|
|
||||||
.args = { "F:f:GK:NO:rst:wyZ", 0, 1, cmd_choose_tree_args_parse },
|
.args = { "F:f:GhK:kNO:rst:wyZ", 0, 1, cmd_choose_tree_args_parse },
|
||||||
.usage = "[-GNrswZ] [-F format] [-f filter] [-K key-format] "
|
.usage = "[-GhkNrswZ] [-F format] [-f filter] [-K key-format] "
|
||||||
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",
|
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_PANE, 0 },
|
.target = { 't', CMD_FIND_PANE, 0 },
|
||||||
@@ -47,8 +47,8 @@ const struct cmd_entry cmd_choose_client_entry = {
|
|||||||
.name = "choose-client",
|
.name = "choose-client",
|
||||||
.alias = NULL,
|
.alias = NULL,
|
||||||
|
|
||||||
.args = { "F:f:K:NO:rt:yZ", 0, 1, cmd_choose_tree_args_parse },
|
.args = { "F:f:hiK:kNO:rt:yZ", 0, 1, cmd_choose_tree_args_parse },
|
||||||
.usage = "[-NrZ] [-F format] [-f filter] [-K key-format] "
|
.usage = "[-hikNrZ] [-F format] [-f filter] [-K key-format] "
|
||||||
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",
|
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_PANE, 0 },
|
.target = { 't', CMD_FIND_PANE, 0 },
|
||||||
@@ -61,8 +61,8 @@ const struct cmd_entry cmd_choose_buffer_entry = {
|
|||||||
.name = "choose-buffer",
|
.name = "choose-buffer",
|
||||||
.alias = NULL,
|
.alias = NULL,
|
||||||
|
|
||||||
.args = { "F:f:K:NO:rt:yZ", 0, 1, cmd_choose_tree_args_parse },
|
.args = { "F:f:K:kNO:rt:yZ", 0, 1, cmd_choose_tree_args_parse },
|
||||||
.usage = "[-NrZ] [-F format] [-f filter] [-K key-format] "
|
.usage = "[-kNrZ] [-F format] [-f filter] [-K key-format] "
|
||||||
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",
|
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_PANE, 0 },
|
.target = { 't', CMD_FIND_PANE, 0 },
|
||||||
@@ -75,8 +75,8 @@ const struct cmd_entry cmd_customize_mode_entry = {
|
|||||||
.name = "customize-mode",
|
.name = "customize-mode",
|
||||||
.alias = NULL,
|
.alias = NULL,
|
||||||
|
|
||||||
.args = { "F:f:Nt:yZ", 0, 0, NULL },
|
.args = { "F:f:kNt:yZ", 0, 0, NULL },
|
||||||
.usage = "[-NZ] [-F format] [-f filter] " CMD_TARGET_PANE_USAGE,
|
.usage = "[-kNZ] [-F format] [-f filter] " CMD_TARGET_PANE_USAGE,
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_PANE, 0 },
|
.target = { 't', CMD_FIND_PANE, 0 },
|
||||||
|
|
||||||
|
|||||||
@@ -34,16 +34,16 @@ static enum args_parse_type cmd_command_prompt_args_parse(struct args *,
|
|||||||
static enum cmd_retval cmd_command_prompt_exec(struct cmd *,
|
static enum cmd_retval cmd_command_prompt_exec(struct cmd *,
|
||||||
struct cmdq_item *);
|
struct cmdq_item *);
|
||||||
|
|
||||||
static int cmd_command_prompt_callback(struct client *, void *,
|
static enum prompt_result cmd_command_prompt_callback(struct client *, void *,
|
||||||
const char *, int);
|
const char *, enum prompt_key_result);
|
||||||
static void cmd_command_prompt_free(void *);
|
static void cmd_command_prompt_free(void *);
|
||||||
|
|
||||||
const struct cmd_entry cmd_command_prompt_entry = {
|
const struct cmd_entry cmd_command_prompt_entry = {
|
||||||
.name = "command-prompt",
|
.name = "command-prompt",
|
||||||
.alias = NULL,
|
.alias = NULL,
|
||||||
|
|
||||||
.args = { "1CbeFiklI:Np:t:T:", 0, 1, cmd_command_prompt_args_parse },
|
.args = { "1CbeFiklI:NPp:t:T:", 0, 1, cmd_command_prompt_args_parse },
|
||||||
.usage = "[-1CbeFiklN] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE
|
.usage = "[-1CbeFiklNP] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE
|
||||||
" [-T prompt-type] [template]",
|
" [-T prompt-type] [template]",
|
||||||
|
|
||||||
.flags = CMD_CLIENT_TFLAG,
|
.flags = CMD_CLIENT_TFLAG,
|
||||||
@@ -62,6 +62,8 @@ struct cmd_command_prompt_cdata {
|
|||||||
int flags;
|
int flags;
|
||||||
enum prompt_type prompt_type;
|
enum prompt_type prompt_type;
|
||||||
|
|
||||||
|
struct window_pane *wp;
|
||||||
|
|
||||||
struct cmd_command_prompt_prompt *prompts;
|
struct cmd_command_prompt_prompt *prompts;
|
||||||
u_int count;
|
u_int count;
|
||||||
u_int current;
|
u_int current;
|
||||||
@@ -87,10 +89,15 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
struct cmd_command_prompt_cdata *cdata;
|
struct cmd_command_prompt_cdata *cdata;
|
||||||
char *tmp, *prompts, *prompt, *next_prompt;
|
char *tmp, *prompts, *prompt, *next_prompt;
|
||||||
char *inputs = NULL, *next_input;
|
char *inputs = NULL, *next_input;
|
||||||
|
struct window_pane *wp = target->wp;
|
||||||
u_int count = args_count(args);
|
u_int count = args_count(args);
|
||||||
int wait = !args_has(args, 'b'), space = 1;
|
int wait = !args_has(args, 'b'), space = 1;
|
||||||
|
int pane = args_has(args, 'P');
|
||||||
|
|
||||||
if (tc->prompt_string != NULL)
|
if (pane) {
|
||||||
|
if (wp == NULL || window_pane_has_prompt(wp))
|
||||||
|
return (CMD_RETURN_NORMAL);
|
||||||
|
} else if (tc->prompt != NULL)
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
if (args_has(args, 'i'))
|
if (args_has(args, 'i'))
|
||||||
wait = 0;
|
wait = 0;
|
||||||
@@ -98,6 +105,8 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
cdata = xcalloc(1, sizeof *cdata);
|
cdata = xcalloc(1, sizeof *cdata);
|
||||||
if (wait)
|
if (wait)
|
||||||
cdata->item = item;
|
cdata->item = item;
|
||||||
|
if (pane)
|
||||||
|
cdata->wp = wp;
|
||||||
cdata->state = args_make_commands_prepare(self, item, 0, "%1", wait,
|
cdata->state = args_make_commands_prepare(self, item, 0, "%1", wait,
|
||||||
args_has(args, 'F'));
|
args_has(args, 'F'));
|
||||||
|
|
||||||
@@ -146,7 +155,7 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((type = args_get(args, 'T')) != NULL) {
|
if ((type = args_get(args, 'T')) != NULL) {
|
||||||
cdata->prompt_type = status_prompt_type(type);
|
cdata->prompt_type = prompt_type(type);
|
||||||
if (cdata->prompt_type == PROMPT_TYPE_INVALID) {
|
if (cdata->prompt_type == PROMPT_TYPE_INVALID) {
|
||||||
cmdq_error(item, "unknown type: %s", type);
|
cmdq_error(item, "unknown type: %s", type);
|
||||||
cmd_command_prompt_free(cdata);
|
cmd_command_prompt_free(cdata);
|
||||||
@@ -167,18 +176,27 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
cdata->flags |= PROMPT_BSPACE_EXIT;
|
cdata->flags |= PROMPT_BSPACE_EXIT;
|
||||||
if (args_has(args, 'C'))
|
if (args_has(args, 'C'))
|
||||||
cdata->flags |= PROMPT_NOFREEZE;
|
cdata->flags |= PROMPT_NOFREEZE;
|
||||||
status_prompt_set(tc, target, cdata->prompts[0].prompt,
|
if (pane) {
|
||||||
cdata->prompts[0].input, cmd_command_prompt_callback,
|
cdata->flags |= PROMPT_ISPANE;
|
||||||
cmd_command_prompt_free, cdata, cdata->flags, cdata->prompt_type);
|
window_pane_set_prompt(wp, tc, target, cdata->prompts[0].prompt,
|
||||||
|
cdata->prompts[0].input, cmd_command_prompt_callback,
|
||||||
|
cmd_command_prompt_free, cdata, cdata->flags,
|
||||||
|
cdata->prompt_type);
|
||||||
|
} else {
|
||||||
|
status_prompt_set(tc, target, cdata->prompts[0].prompt,
|
||||||
|
cdata->prompts[0].input, cmd_command_prompt_callback,
|
||||||
|
cmd_command_prompt_free, cdata, cdata->flags,
|
||||||
|
cdata->prompt_type);
|
||||||
|
}
|
||||||
|
|
||||||
if (!wait)
|
if (!wait)
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
return (CMD_RETURN_WAIT);
|
return (CMD_RETURN_WAIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static enum prompt_result
|
||||||
cmd_command_prompt_callback(struct client *c, void *data, const char *s,
|
cmd_command_prompt_callback(struct client *c, void *data, const char *s,
|
||||||
int done)
|
enum prompt_key_result key)
|
||||||
{
|
{
|
||||||
struct cmd_command_prompt_cdata *cdata = data;
|
struct cmd_command_prompt_cdata *cdata = data;
|
||||||
char *error;
|
char *error;
|
||||||
@@ -188,26 +206,30 @@ cmd_command_prompt_callback(struct client *c, void *data, const char *s,
|
|||||||
int argc = 0;
|
int argc = 0;
|
||||||
char **argv = NULL;
|
char **argv = NULL;
|
||||||
|
|
||||||
if (s == NULL)
|
if (s == NULL || key == PROMPT_KEY_MOVE)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (done) {
|
if (key == PROMPT_KEY_CLOSE) {
|
||||||
if (cdata->flags & PROMPT_INCREMENTAL)
|
if (cdata->flags & PROMPT_INCREMENTAL)
|
||||||
goto out;
|
goto out;
|
||||||
cmd_append_argv(&cdata->argc, &cdata->argv, s);
|
cmd_append_argv(&cdata->argc, &cdata->argv, s);
|
||||||
if (++cdata->current != cdata->count) {
|
if (++cdata->current != cdata->count) {
|
||||||
prompt = &cdata->prompts[cdata->current];
|
prompt = &cdata->prompts[cdata->current];
|
||||||
status_prompt_update(c, prompt->prompt, prompt->input);
|
if (cdata->wp != NULL) {
|
||||||
return (1);
|
window_pane_update_prompt(cdata->wp,
|
||||||
|
prompt->prompt, prompt->input);
|
||||||
|
} else
|
||||||
|
status_prompt_update(c, prompt->prompt,
|
||||||
|
prompt->input);
|
||||||
|
return (PROMPT_CONTINUE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
argc = cdata->argc;
|
argc = cdata->argc;
|
||||||
argv = cmd_copy_argv(cdata->argc, cdata->argv);
|
argv = cmd_copy_argv(cdata->argc, cdata->argv);
|
||||||
if (!done)
|
if (key != PROMPT_KEY_CLOSE)
|
||||||
cmd_append_argv(&argc, &argv, s);
|
cmd_append_argv(&argc, &argv, s);
|
||||||
|
else {
|
||||||
if (done) {
|
|
||||||
cmd_free_argv(cdata->argc, cdata->argv);
|
cmd_free_argv(cdata->argc, cdata->argv);
|
||||||
cdata->argc = argc;
|
cdata->argc = argc;
|
||||||
cdata->argv = cmd_copy_argv(argc, argv);
|
cdata->argv = cmd_copy_argv(argc, argv);
|
||||||
@@ -226,13 +248,20 @@ cmd_command_prompt_callback(struct client *c, void *data, const char *s,
|
|||||||
}
|
}
|
||||||
cmd_free_argv(argc, argv);
|
cmd_free_argv(argc, argv);
|
||||||
|
|
||||||
if (c->prompt_inputcb != cmd_command_prompt_callback)
|
/*
|
||||||
return (1);
|
* An incremental prompt fires its callback on every edit but must stay
|
||||||
|
* open for further typing; only an explicit close (handled above) ends
|
||||||
|
* it.
|
||||||
|
*/
|
||||||
|
if (cdata->flags & PROMPT_INCREMENTAL)
|
||||||
|
return (PROMPT_CONTINUE);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (item != NULL)
|
if (item != NULL) {
|
||||||
|
cdata->item = NULL;
|
||||||
cmdq_continue(item);
|
cmdq_continue(item);
|
||||||
return (0);
|
}
|
||||||
|
return (PROMPT_CLOSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -241,6 +270,11 @@ cmd_command_prompt_free(void *data)
|
|||||||
struct cmd_command_prompt_cdata *cdata = data;
|
struct cmd_command_prompt_cdata *cdata = data;
|
||||||
u_int i;
|
u_int i;
|
||||||
|
|
||||||
|
if (cdata->item != NULL) {
|
||||||
|
cmdq_continue(cdata->item);
|
||||||
|
cdata->item = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < cdata->count; i++) {
|
for (i = 0; i < cdata->count; i++) {
|
||||||
free(cdata->prompts[i].prompt);
|
free(cdata->prompts[i].prompt);
|
||||||
free(cdata->prompts[i].input);
|
free(cdata->prompts[i].input);
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ static enum args_parse_type cmd_confirm_before_args_parse(struct args *,
|
|||||||
static enum cmd_retval cmd_confirm_before_exec(struct cmd *,
|
static enum cmd_retval cmd_confirm_before_exec(struct cmd *,
|
||||||
struct cmdq_item *);
|
struct cmdq_item *);
|
||||||
|
|
||||||
static int cmd_confirm_before_callback(struct client *, void *,
|
static enum prompt_result cmd_confirm_before_callback(struct client *, void *,
|
||||||
const char *, int);
|
const char *, enum prompt_key_result);
|
||||||
static void cmd_confirm_before_free(void *);
|
static void cmd_confirm_before_free(void *);
|
||||||
|
|
||||||
const struct cmd_entry cmd_confirm_before_entry = {
|
const struct cmd_entry cmd_confirm_before_entry = {
|
||||||
@@ -118,9 +118,9 @@ cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
return (CMD_RETURN_WAIT);
|
return (CMD_RETURN_WAIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static enum prompt_result
|
||||||
cmd_confirm_before_callback(struct client *c, void *data, const char *s,
|
cmd_confirm_before_callback(struct client *c, void *data, const char *s,
|
||||||
__unused int done)
|
__unused enum prompt_key_result key)
|
||||||
{
|
{
|
||||||
struct cmd_confirm_before_data *cdata = data;
|
struct cmd_confirm_before_data *cdata = data;
|
||||||
struct cmdq_item *item = cdata->item, *new_item;
|
struct cmdq_item *item = cdata->item, *new_item;
|
||||||
@@ -151,7 +151,7 @@ out:
|
|||||||
cmdq_get_client(item)->retval = retcode;
|
cmdq_get_client(item)->retval = retcode;
|
||||||
cmdq_continue(item);
|
cmdq_continue(item);
|
||||||
}
|
}
|
||||||
return (0);
|
return (PROMPT_CLOSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|||||||
@@ -48,6 +48,16 @@ struct cmd_display_panes_data {
|
|||||||
struct args_command_state *state;
|
struct args_command_state *state;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct cmd_display_panes_ctx {
|
||||||
|
struct client *c;
|
||||||
|
int ox;
|
||||||
|
int oy;
|
||||||
|
u_int sx;
|
||||||
|
u_int sy;
|
||||||
|
u_int statuslines;
|
||||||
|
int statustop;
|
||||||
|
};
|
||||||
|
|
||||||
static enum args_parse_type
|
static enum args_parse_type
|
||||||
cmd_display_panes_args_parse(__unused struct args *args, __unused u_int idx,
|
cmd_display_panes_args_parse(__unused struct args *args, __unused u_int idx,
|
||||||
__unused char **cause)
|
__unused char **cause)
|
||||||
@@ -56,7 +66,7 @@ cmd_display_panes_args_parse(__unused struct args *args, __unused u_int idx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
cmd_display_panes_put(struct screen_redraw_ctx *ctx,
|
cmd_display_panes_put(struct cmd_display_panes_ctx *ctx,
|
||||||
struct window_pane *wp, u_int cx, u_int cy, const char *buf, size_t len)
|
struct window_pane *wp, u_int cx, u_int cy, const char *buf, size_t len)
|
||||||
{
|
{
|
||||||
struct client *c = ctx->c;
|
struct client *c = ctx->c;
|
||||||
@@ -65,8 +75,7 @@ cmd_display_panes_put(struct screen_redraw_ctx *ctx,
|
|||||||
struct visible_range *ri;
|
struct visible_range *ri;
|
||||||
u_int i, j;
|
u_int i, j;
|
||||||
|
|
||||||
r = screen_redraw_get_visible_ranges(wp, ctx->ox + cx, ctx->oy + cy,
|
r = window_visible_ranges(wp, ctx->ox + cx, ctx->oy + cy, len, NULL);
|
||||||
len, NULL);
|
|
||||||
for (i = 0; i < r->used; i++) {
|
for (i = 0; i < r->used; i++) {
|
||||||
ri = &r->ranges[i];
|
ri = &r->ranges[i];
|
||||||
for (j = ri->px; j < ri->px + ri->nx; j++) {
|
for (j = ri->px; j < ri->px + ri->nx; j++) {
|
||||||
@@ -77,7 +86,43 @@ cmd_display_panes_put(struct screen_redraw_ctx *ctx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
|
cmd_display_panes_draw_format(struct cmd_display_panes_ctx *ctx,
|
||||||
|
struct window_pane *wp, u_int xoff, u_int yoff, u_int sx,
|
||||||
|
const struct grid_cell *gc)
|
||||||
|
{
|
||||||
|
struct client *c = ctx->c;
|
||||||
|
struct tty *tty = &c->tty;
|
||||||
|
struct session *s = c->session;
|
||||||
|
struct screen *sc = wp->screen, screen;
|
||||||
|
struct screen_write_ctx sctx;
|
||||||
|
struct visible_ranges *r;
|
||||||
|
struct visible_range *ri;
|
||||||
|
const char *format;
|
||||||
|
char *expanded;
|
||||||
|
u_int i, px = ctx->ox + xoff;
|
||||||
|
|
||||||
|
format = options_get_string(s->options, "display-panes-format");
|
||||||
|
expanded = format_single(NULL, format, c, s, s->curw, wp);
|
||||||
|
|
||||||
|
screen_init(&screen, sx, 1, 0);
|
||||||
|
screen_write_start(&sctx, &screen);
|
||||||
|
screen_write_fast_copy(&sctx, sc, 0, sc->grid->hsize, sx, 1);
|
||||||
|
screen_write_cursormove(&sctx, 0, 0, 0);
|
||||||
|
format_draw(&sctx, gc, sx, expanded, NULL, 0);
|
||||||
|
screen_write_stop(&sctx);
|
||||||
|
free(expanded);
|
||||||
|
|
||||||
|
r = window_visible_ranges(wp, px, wp->yoff, sx, NULL);
|
||||||
|
for (i = 0; i < r->used; i++) {
|
||||||
|
ri = &r->ranges[i];
|
||||||
|
tty_draw_line(tty, &screen, ri->px - px, 0, ri->nx,
|
||||||
|
ri->px - ctx->ox, yoff, NULL);
|
||||||
|
}
|
||||||
|
screen_free(&screen);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cmd_display_panes_draw_pane(struct cmd_display_panes_ctx *ctx,
|
||||||
struct window_pane *wp)
|
struct window_pane *wp)
|
||||||
{
|
{
|
||||||
struct client *c = ctx->c;
|
struct client *c = ctx->c;
|
||||||
@@ -88,9 +133,10 @@ cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
|
|||||||
struct grid_cell fgc, bgc;
|
struct grid_cell fgc, bgc;
|
||||||
u_int pane, idx, px, py, i, j, xoff, yoff, sx, sy;
|
u_int pane, idx, px, py, i, j, xoff, yoff, sx, sy;
|
||||||
u_int cx, cy;
|
u_int cx, cy;
|
||||||
int colour, active_colour;
|
const char *name;
|
||||||
char buf[16], lbuf[16], rbuf[16], *ptr;
|
struct format_tree *ft;
|
||||||
size_t len, llen, rlen;
|
char buf[16], lbuf[16], *ptr;
|
||||||
|
size_t len, llen;
|
||||||
|
|
||||||
if (wp->xoff + (int)wp->sx <= ctx->ox ||
|
if (wp->xoff + (int)wp->sx <= ctx->ox ||
|
||||||
wp->xoff >= ctx->ox + (int)ctx->sx ||
|
wp->xoff >= ctx->ox + (int)ctx->sx ||
|
||||||
@@ -146,27 +192,24 @@ cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
|
|||||||
|
|
||||||
if (sx < len)
|
if (sx < len)
|
||||||
return;
|
return;
|
||||||
colour = options_get_number(oo, "display-panes-colour");
|
if (w->active == wp)
|
||||||
active_colour = options_get_number(oo, "display-panes-active-colour");
|
name = "display-panes-active-colour";
|
||||||
|
else
|
||||||
|
name = "display-panes-colour";
|
||||||
|
ft = format_create_defaults(NULL, c, s, NULL, wp);
|
||||||
|
style_apply(&fgc, oo, name, ft);
|
||||||
|
format_free(ft);
|
||||||
|
|
||||||
memcpy(&fgc, &grid_default_cell, sizeof fgc);
|
|
||||||
memcpy(&bgc, &grid_default_cell, sizeof bgc);
|
memcpy(&bgc, &grid_default_cell, sizeof bgc);
|
||||||
if (w->active == wp) {
|
bgc.bg = fgc.fg;
|
||||||
fgc.fg = active_colour;
|
|
||||||
bgc.bg = active_colour;
|
|
||||||
} else {
|
|
||||||
fgc.fg = colour;
|
|
||||||
bgc.bg = colour;
|
|
||||||
}
|
|
||||||
|
|
||||||
rlen = xsnprintf(rbuf, sizeof rbuf, "%ux%u", wp->sx, wp->sy);
|
|
||||||
if (pane > 9 && pane < 35)
|
if (pane > 9 && pane < 35)
|
||||||
llen = xsnprintf(lbuf, sizeof lbuf, "%c", 'a' + (pane - 10));
|
llen = xsnprintf(lbuf, sizeof lbuf, "%c", 'a' + (pane - 10));
|
||||||
else
|
else
|
||||||
llen = 0;
|
llen = 0;
|
||||||
|
|
||||||
if (sx < len * 6 || sy < 5) {
|
if (sx < len * 6 || sy < 5) {
|
||||||
tty_attributes(tty, &fgc, &grid_default_cell, NULL, NULL);
|
tty_attributes(tty, &fgc, NULL);
|
||||||
if (sx >= len + llen + 1) {
|
if (sx >= len + llen + 1) {
|
||||||
len += llen + 1;
|
len += llen + 1;
|
||||||
cx = xoff + px - len / 2;
|
cx = xoff + px - len / 2;
|
||||||
@@ -187,7 +230,7 @@ cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
|
|||||||
px -= len * 3;
|
px -= len * 3;
|
||||||
py -= 2;
|
py -= 2;
|
||||||
|
|
||||||
tty_attributes(tty, &bgc, &grid_default_cell, NULL, NULL);
|
tty_attributes(tty, &bgc, NULL);
|
||||||
for (ptr = buf; *ptr != '\0'; ptr++) {
|
for (ptr = buf; *ptr != '\0'; ptr++) {
|
||||||
if (*ptr < '0' || *ptr > '9')
|
if (*ptr < '0' || *ptr > '9')
|
||||||
continue;
|
continue;
|
||||||
@@ -207,13 +250,9 @@ cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
|
|||||||
|
|
||||||
if (sy <= 6)
|
if (sy <= 6)
|
||||||
goto out;
|
goto out;
|
||||||
tty_attributes(tty, &fgc, &grid_default_cell, NULL, NULL);
|
cmd_display_panes_draw_format(ctx, wp, xoff, yoff, sx, &fgc);
|
||||||
if (rlen != 0 && sx >= rlen) {
|
|
||||||
cx = xoff + sx - rlen;
|
|
||||||
cy = yoff;
|
|
||||||
cmd_display_panes_put(ctx, wp, cx, cy, rbuf, rlen);
|
|
||||||
}
|
|
||||||
if (llen != 0) {
|
if (llen != 0) {
|
||||||
|
tty_attributes(tty, &fgc, NULL);
|
||||||
cx = xoff + sx / 2 + len * 3 - llen - 1;
|
cx = xoff + sx / 2 + len * 3 - llen - 1;
|
||||||
cy = yoff + py + 5;
|
cy = yoff + py + 5;
|
||||||
cmd_display_panes_put(ctx, wp, cx, cy, lbuf, llen);
|
cmd_display_panes_put(ctx, wp, cx, cy, lbuf, llen);
|
||||||
@@ -224,17 +263,30 @@ out:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
cmd_display_panes_draw(struct client *c, __unused void *data,
|
cmd_display_panes_draw(struct client *c, __unused void *data)
|
||||||
struct screen_redraw_ctx *ctx)
|
|
||||||
{
|
{
|
||||||
struct window *w = c->session->curw->window;
|
struct session *s = c->session;
|
||||||
struct window_pane *wp;
|
struct window *w = s->curw->window;
|
||||||
|
struct window_pane *wp;
|
||||||
|
struct cmd_display_panes_ctx ctx;
|
||||||
|
u_int lines;
|
||||||
|
|
||||||
log_debug("%s: %s @%u", __func__, c->name, w->id);
|
log_debug("%s: %s @%u", __func__, c->name, w->id);
|
||||||
|
|
||||||
|
memset(&ctx, 0, sizeof ctx);
|
||||||
|
ctx.c = c;
|
||||||
|
tty_window_offset(&c->tty, &ctx.ox, &ctx.oy, &ctx.sx, &ctx.sy);
|
||||||
|
if (options_get_number(s->options, "status-position") == 0) {
|
||||||
|
lines = status_line_size(c);
|
||||||
|
if (c->message_string != NULL || c->prompt != NULL)
|
||||||
|
lines = (lines == 0 ? 1 : lines);
|
||||||
|
ctx.statuslines = lines;
|
||||||
|
ctx.statustop = 1;
|
||||||
|
}
|
||||||
|
|
||||||
TAILQ_FOREACH(wp, &w->panes, entry) {
|
TAILQ_FOREACH(wp, &w->panes, entry) {
|
||||||
if (window_pane_visible(wp))
|
if (window_pane_is_visible(wp))
|
||||||
cmd_display_panes_draw_pane(ctx, wp);
|
cmd_display_panes_draw_pane(&ctx, wp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
16
cmd-find.c
16
cmd-find.c
@@ -147,6 +147,18 @@ cmd_find_session_better(struct session *s, struct session *than, int flags)
|
|||||||
return (timercmp(&s->activity_time, &than->activity_time, >));
|
return (timercmp(&s->activity_time, &than->activity_time, >));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Can this session be usefully targeted? */
|
||||||
|
static int
|
||||||
|
cmd_find_session_valid(struct session *s)
|
||||||
|
{
|
||||||
|
if (!session_alive(s) ||
|
||||||
|
s->curw == NULL ||
|
||||||
|
s->curw->window == NULL ||
|
||||||
|
s->curw->window->active == NULL)
|
||||||
|
return (0);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|
||||||
/* Find best session from a list, or all if list is NULL. */
|
/* Find best session from a list, or all if list is NULL. */
|
||||||
static struct session *
|
static struct session *
|
||||||
cmd_find_best_session(struct session **slist, u_int ssize, int flags)
|
cmd_find_best_session(struct session **slist, u_int ssize, int flags)
|
||||||
@@ -159,11 +171,15 @@ cmd_find_best_session(struct session **slist, u_int ssize, int flags)
|
|||||||
s = NULL;
|
s = NULL;
|
||||||
if (slist != NULL) {
|
if (slist != NULL) {
|
||||||
for (i = 0; i < ssize; i++) {
|
for (i = 0; i < ssize; i++) {
|
||||||
|
if (!cmd_find_session_valid(slist[i]))
|
||||||
|
continue;
|
||||||
if (cmd_find_session_better(slist[i], s, flags))
|
if (cmd_find_session_better(slist[i], s, flags))
|
||||||
s = slist[i];
|
s = slist[i];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
RB_FOREACH(s_loop, sessions, &sessions) {
|
RB_FOREACH(s_loop, sessions, &sessions) {
|
||||||
|
if (!cmd_find_session_valid(s_loop))
|
||||||
|
continue;
|
||||||
if (cmd_find_session_better(s_loop, s, flags))
|
if (cmd_find_session_better(s_loop, s, flags))
|
||||||
s = s_loop;
|
s = s_loop;
|
||||||
}
|
}
|
||||||
|
|||||||
329
cmd-join-pane.c
329
cmd-join-pane.c
@@ -30,6 +30,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
static enum cmd_retval cmd_join_pane_exec(struct cmd *, struct cmdq_item *);
|
static enum cmd_retval cmd_join_pane_exec(struct cmd *, struct cmdq_item *);
|
||||||
|
static enum cmd_retval cmd_join_pane_mouse_update(struct cmdq_item *);
|
||||||
|
static void cmd_join_pane_mouse_move(struct client *,
|
||||||
|
struct mouse_event *);
|
||||||
|
|
||||||
const struct cmd_entry cmd_join_pane_entry = {
|
const struct cmd_entry cmd_join_pane_entry = {
|
||||||
.name = "join-pane",
|
.name = "join-pane",
|
||||||
@@ -49,8 +52,10 @@ const struct cmd_entry cmd_move_pane_entry = {
|
|||||||
.name = "move-pane",
|
.name = "move-pane",
|
||||||
.alias = "movep",
|
.alias = "movep",
|
||||||
|
|
||||||
.args = { "bdfhvp:l:s:t:", 0, 0, NULL },
|
.args = { "bdfhMvl:L::P:R::s:t:U::X:Y:z:", 0, 0, NULL },
|
||||||
.usage = "[-bdfhv] [-l size] " CMD_SRCDST_PANE_USAGE,
|
.usage = "[-bdfhMv] [-D lines] [-l size] [-L columns] [-P position] "
|
||||||
|
"[-R columns] " CMD_SRCDST_PANE_USAGE " [-U lines] "
|
||||||
|
"[-X x-position] [-Y y-position] [-z z-index]",
|
||||||
|
|
||||||
.source = { 's', CMD_FIND_PANE, CMD_FIND_DEFAULT_MARKED },
|
.source = { 's', CMD_FIND_PANE, CMD_FIND_DEFAULT_MARKED },
|
||||||
.target = { 't', CMD_FIND_PANE, 0 },
|
.target = { 't', CMD_FIND_PANE, 0 },
|
||||||
@@ -59,6 +64,305 @@ const struct cmd_entry cmd_move_pane_entry = {
|
|||||||
.exec = cmd_join_pane_exec
|
.exec = cmd_join_pane_exec
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static enum cmd_retval
|
||||||
|
cmd_join_pane_place(struct cmdq_item *item, struct winlink *wl,
|
||||||
|
struct window_pane *wp, const char *position)
|
||||||
|
{
|
||||||
|
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 border = 1;
|
||||||
|
|
||||||
|
if (window_pane_get_pane_lines(wp) == PANE_LINES_NONE)
|
||||||
|
border = 0;
|
||||||
|
|
||||||
|
if (strcmp(position, "top-left") == 0) {
|
||||||
|
xoff = border;
|
||||||
|
yoff = border;
|
||||||
|
} else if (strcmp(position, "top-centre") == 0 ||
|
||||||
|
strcmp(position, "top-center") == 0) {
|
||||||
|
xoff = (wx - px) / 2;
|
||||||
|
yoff = border;
|
||||||
|
} else if (strcmp(position, "top-right") == 0) {
|
||||||
|
xoff = wx - px - border;
|
||||||
|
yoff = border;
|
||||||
|
} else if (strcmp(position, "centre-left") == 0 ||
|
||||||
|
strcmp(position, "center-left") == 0) {
|
||||||
|
xoff = border;
|
||||||
|
yoff = (wy - py) / 2;
|
||||||
|
} else if (strcmp(position, "centre") == 0 ||
|
||||||
|
strcmp(position, "center") == 0) {
|
||||||
|
xoff = (wx - px) / 2;
|
||||||
|
yoff = (wy - py) / 2;
|
||||||
|
} else if (strcmp(position, "centre-right") == 0 ||
|
||||||
|
strcmp(position, "center-right") == 0) {
|
||||||
|
xoff = wx - px - border;
|
||||||
|
yoff = (wy - py) / 2;
|
||||||
|
} else if (strcmp(position, "bottom-left") == 0) {
|
||||||
|
xoff = border;
|
||||||
|
yoff = wy - py - border;
|
||||||
|
} else if (strcmp(position, "bottom-centre") == 0 ||
|
||||||
|
strcmp(position, "bottom-center") == 0) {
|
||||||
|
xoff = (wx - px) / 2;
|
||||||
|
yoff = wy - py - border;
|
||||||
|
} else if (strcmp(position, "bottom-right") == 0) {
|
||||||
|
xoff = wx - px - border;
|
||||||
|
yoff = wy - py - border;
|
||||||
|
} else if (strcmp(position, "top-left-centre") == 0 ||
|
||||||
|
strcmp(position, "top-left-center") == 0) {
|
||||||
|
xoff = wx / 4 - px / 2;
|
||||||
|
yoff = wy / 4 - py / 2;
|
||||||
|
} else if (strcmp(position, "top-right-centre") == 0 ||
|
||||||
|
strcmp(position, "top-right-center") == 0) {
|
||||||
|
xoff = (3 * wx) / 4 - px / 2;
|
||||||
|
yoff = wy / 4 - py / 2;
|
||||||
|
} else if (strcmp(position, "bottom-left-centre") == 0 ||
|
||||||
|
strcmp(position, "bottom-left-center") == 0) {
|
||||||
|
xoff = wx / 4 - px / 2;
|
||||||
|
yoff = (3 * wy) / 4 - py / 2;
|
||||||
|
} else if (strcmp(position, "bottom-right-centre") == 0 ||
|
||||||
|
strcmp(position, "bottom-right-center") == 0) {
|
||||||
|
xoff = (3 * wx) / 4 - px / 2;
|
||||||
|
yoff = (3 * wy) / 4 - py / 2;
|
||||||
|
} else if (strcmp(position, "front") == 0) {
|
||||||
|
TAILQ_REMOVE(&w->z_index, wp, zentry);
|
||||||
|
TAILQ_INSERT_HEAD(&w->z_index, wp, zentry);
|
||||||
|
} else if (strcmp(position, "back") == 0) {
|
||||||
|
TAILQ_REMOVE(&w->z_index, wp, zentry);
|
||||||
|
TAILQ_FOREACH(owp, &w->z_index, zentry) {
|
||||||
|
if (!window_pane_is_floating(owp))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (owp != NULL)
|
||||||
|
TAILQ_INSERT_BEFORE(owp, wp, zentry);
|
||||||
|
else
|
||||||
|
TAILQ_INSERT_TAIL(&w->z_index, wp, zentry);
|
||||||
|
} else if (strcmp(position, "forward") == 0) {
|
||||||
|
owp = TAILQ_PREV(wp, window_panes_zindex, zentry);
|
||||||
|
if (owp != NULL) {
|
||||||
|
TAILQ_REMOVE(&w->z_index, wp, zentry);
|
||||||
|
TAILQ_INSERT_BEFORE(owp, wp, zentry);
|
||||||
|
}
|
||||||
|
} else if (strcmp(position, "backward") == 0) {
|
||||||
|
owp = TAILQ_NEXT(wp, zentry);
|
||||||
|
if (owp != NULL && window_pane_is_floating(owp)) {
|
||||||
|
TAILQ_REMOVE(&w->z_index, wp, zentry);
|
||||||
|
TAILQ_INSERT_AFTER(&w->z_index, owp, wp, zentry);
|
||||||
|
}
|
||||||
|
} else if (strcmp(position, "forward-loop") == 0) {
|
||||||
|
owp = TAILQ_PREV(wp, window_panes_zindex, zentry);
|
||||||
|
TAILQ_REMOVE(&w->z_index, wp, zentry);
|
||||||
|
if (owp != NULL)
|
||||||
|
TAILQ_INSERT_BEFORE(owp, wp, zentry);
|
||||||
|
else {
|
||||||
|
TAILQ_FOREACH(owp, &w->z_index, zentry) {
|
||||||
|
if (!window_pane_is_floating(owp))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (owp != NULL)
|
||||||
|
TAILQ_INSERT_BEFORE(owp, wp, zentry);
|
||||||
|
else
|
||||||
|
TAILQ_INSERT_TAIL(&w->z_index, wp, zentry);
|
||||||
|
}
|
||||||
|
} else if (strcmp(position, "backward-loop") == 0) {
|
||||||
|
owp = TAILQ_NEXT(wp, zentry);
|
||||||
|
if (owp != NULL && window_pane_is_floating(owp)) {
|
||||||
|
TAILQ_REMOVE(&w->z_index, wp, zentry);
|
||||||
|
TAILQ_INSERT_AFTER(&w->z_index, owp, wp, zentry);
|
||||||
|
} else {
|
||||||
|
TAILQ_REMOVE(&w->z_index, wp, zentry);
|
||||||
|
TAILQ_INSERT_HEAD(&w->z_index, wp, zentry);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cmdq_error(item, "unknown position: %s", position);
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xoff != lc->xoff || yoff != lc->yoff) {
|
||||||
|
lc->xoff = xoff;
|
||||||
|
lc->yoff = yoff;
|
||||||
|
layout_fix_panes(w, NULL);
|
||||||
|
}
|
||||||
|
notify_window("window-layout-changed", w);
|
||||||
|
server_redraw_window(w);
|
||||||
|
|
||||||
|
return (CMD_RETURN_NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum cmd_retval
|
||||||
|
cmd_join_pane_move(struct cmdq_item *item, struct args *args,
|
||||||
|
struct winlink *wl, struct window_pane *wp)
|
||||||
|
{
|
||||||
|
struct window *w = wl->window;
|
||||||
|
struct layout_cell *lc = wp->layout_cell;
|
||||||
|
const char *errstr, *argval;
|
||||||
|
const char flags[] = { 'U', 'D', 'L', 'R' };
|
||||||
|
char *cause = NULL, flag;
|
||||||
|
int xoff = lc->xoff, yoff = lc->yoff, adjust;
|
||||||
|
u_int i;
|
||||||
|
enum pane_lines lines = window_pane_get_pane_lines(wp);
|
||||||
|
|
||||||
|
if (args_has(args, 'X')) {
|
||||||
|
xoff = args_percentage_and_expand(args, 'X', -(int)w->sx,
|
||||||
|
w->sx, w->sx, item, &cause);
|
||||||
|
if (cause != NULL) {
|
||||||
|
cmdq_error(item, "position %s", cause);
|
||||||
|
free(cause);
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
if (lines != PANE_LINES_NONE)
|
||||||
|
xoff += 1;
|
||||||
|
}
|
||||||
|
if (args_has(args, 'Y')) {
|
||||||
|
yoff = args_percentage_and_expand(args, 'Y', -(int)w->sy,
|
||||||
|
w->sy, w->sy, item, &cause);
|
||||||
|
if (cause != NULL) {
|
||||||
|
cmdq_error(item, "position %s", cause);
|
||||||
|
free(cause);
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
if (lines != PANE_LINES_NONE)
|
||||||
|
yoff += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < nitems(flags); i++) {
|
||||||
|
flag = flags[i];
|
||||||
|
if (!args_has(args, flag))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
argval = args_get(args, flag);
|
||||||
|
if (argval == NULL)
|
||||||
|
argval = "1";
|
||||||
|
adjust = strtonum(argval, INT_MIN, INT_MAX, &errstr);
|
||||||
|
if (errstr != NULL) {
|
||||||
|
cmdq_error(item, "offset %s", errstr);
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flag == 'U')
|
||||||
|
yoff -= adjust;
|
||||||
|
else if (flag == 'D')
|
||||||
|
yoff += adjust;
|
||||||
|
else if (flag == 'L')
|
||||||
|
xoff -= adjust;
|
||||||
|
else
|
||||||
|
xoff += adjust;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xoff != lc->xoff || yoff != lc->yoff) {
|
||||||
|
lc->xoff = xoff;
|
||||||
|
lc->yoff = yoff;
|
||||||
|
layout_fix_panes(w, NULL);
|
||||||
|
notify_window("window-layout-changed", w);
|
||||||
|
server_redraw_window(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (CMD_RETURN_NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum cmd_retval
|
||||||
|
cmd_join_pane_mouse_update(struct cmdq_item *item)
|
||||||
|
{
|
||||||
|
struct cmd_find_state *target = cmdq_get_target(item);
|
||||||
|
struct key_event *event = cmdq_get_event(item);
|
||||||
|
struct client *c = cmdq_get_client(item);
|
||||||
|
struct session *s = target->s;
|
||||||
|
struct winlink *wl;
|
||||||
|
struct window *w;
|
||||||
|
struct window_pane *wp;
|
||||||
|
|
||||||
|
if (!event->m.valid)
|
||||||
|
return (CMD_RETURN_NORMAL);
|
||||||
|
wp = cmd_mouse_pane(&event->m, &s, &wl);
|
||||||
|
if (wp == NULL || c == NULL || c->session != s)
|
||||||
|
return (CMD_RETURN_NORMAL);
|
||||||
|
if (!window_pane_is_floating(wp))
|
||||||
|
return (CMD_RETURN_NORMAL);
|
||||||
|
|
||||||
|
w = wl->window;
|
||||||
|
window_redraw_active_switch(w, wp);
|
||||||
|
window_set_active_pane(w, wp, 1);
|
||||||
|
|
||||||
|
c->tty.mouse_drag_update = cmd_join_pane_mouse_move;
|
||||||
|
cmd_join_pane_mouse_move(c, &event->m);
|
||||||
|
return (CMD_RETURN_NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
cmd_join_pane_mouse_move(struct client *c, struct mouse_event *m)
|
||||||
|
{
|
||||||
|
struct winlink *wl;
|
||||||
|
struct window *w;
|
||||||
|
struct window_pane *wp;
|
||||||
|
struct layout_cell *lc;
|
||||||
|
int y, ly, x, lx;
|
||||||
|
|
||||||
|
wp = cmd_mouse_pane(m, NULL, &wl);
|
||||||
|
if (wp == NULL) {
|
||||||
|
c->tty.mouse_drag_update = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
w = wl->window;
|
||||||
|
lc = wp->layout_cell;
|
||||||
|
|
||||||
|
y = m->y + m->oy; x = m->x + m->ox;
|
||||||
|
if (m->statusat == 0 && y >= (int)m->statuslines)
|
||||||
|
y -= m->statuslines;
|
||||||
|
else if (m->statusat > 0 && y >= m->statusat)
|
||||||
|
y = m->statusat - 1;
|
||||||
|
ly = m->ly + m->oy; lx = m->lx + m->ox;
|
||||||
|
if (m->statusat == 0 && ly >= (int)m->statuslines)
|
||||||
|
ly -= m->statuslines;
|
||||||
|
else if (m->statusat > 0 && ly >= m->statusat)
|
||||||
|
ly = m->statusat - 1;
|
||||||
|
|
||||||
|
if (x != lx || y != ly) {
|
||||||
|
lc->xoff += x - lx;
|
||||||
|
lc->yoff += y - ly;
|
||||||
|
layout_fix_panes(w, NULL);
|
||||||
|
server_redraw_window(w);
|
||||||
|
server_redraw_window_borders(w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum cmd_retval
|
||||||
|
cmd_join_pane_zindex(struct cmdq_item *item, struct winlink *wl,
|
||||||
|
struct window_pane *wp, const char *s)
|
||||||
|
{
|
||||||
|
struct window *w = wl->window;
|
||||||
|
struct window_pane *owp;
|
||||||
|
const char *errstr;
|
||||||
|
u_int n, z;
|
||||||
|
|
||||||
|
z = strtonum(s, 0, UINT_MAX, &errstr);
|
||||||
|
if (errstr != NULL) {
|
||||||
|
cmdq_error(item, "z-index %s", errstr);
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
TAILQ_REMOVE(&w->z_index, wp, zentry);
|
||||||
|
|
||||||
|
n = 0;
|
||||||
|
TAILQ_FOREACH(owp, &w->z_index, zentry) {
|
||||||
|
if (!window_pane_is_floating(owp))
|
||||||
|
break;
|
||||||
|
if (n >= z)
|
||||||
|
break;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (owp != NULL)
|
||||||
|
TAILQ_INSERT_BEFORE(owp, wp, zentry);
|
||||||
|
else
|
||||||
|
TAILQ_INSERT_TAIL(&w->z_index, wp, zentry);
|
||||||
|
|
||||||
|
notify_window("window-layout-changed", w);
|
||||||
|
server_redraw_window(w);
|
||||||
|
|
||||||
|
return (CMD_RETURN_NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
static enum cmd_retval
|
static enum cmd_retval
|
||||||
cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
|
cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||||
{
|
{
|
||||||
@@ -70,6 +374,7 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
struct winlink *src_wl, *dst_wl;
|
struct winlink *src_wl, *dst_wl;
|
||||||
struct window *src_w, *dst_w;
|
struct window *src_w, *dst_w;
|
||||||
struct window_pane *src_wp, *dst_wp;
|
struct window_pane *src_wp, *dst_wp;
|
||||||
|
const char *s;
|
||||||
char *cause = NULL;
|
char *cause = NULL;
|
||||||
int flags = 0, dst_idx;
|
int flags = 0, dst_idx;
|
||||||
struct layout_cell *lc;
|
struct layout_cell *lc;
|
||||||
@@ -81,6 +386,26 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
dst_idx = dst_wl->idx;
|
dst_idx = dst_wl->idx;
|
||||||
server_unzoom_window(dst_w);
|
server_unzoom_window(dst_w);
|
||||||
|
|
||||||
|
if (cmd_get_entry(self) == &cmd_move_pane_entry) {
|
||||||
|
if (args_has(args, 'M'))
|
||||||
|
return (cmd_join_pane_mouse_update(item));
|
||||||
|
if (!window_pane_is_floating(dst_wp)) {
|
||||||
|
cmdq_error(item, "pane is not floating");
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
if ((s = args_get(args, 'P')) != NULL)
|
||||||
|
return (cmd_join_pane_place(item, dst_wl, dst_wp, s));
|
||||||
|
if ((s = args_get(args, 'z')) != NULL)
|
||||||
|
return (cmd_join_pane_zindex(item, dst_wl, dst_wp, s));
|
||||||
|
if (args_has(args, 'X') ||
|
||||||
|
args_has(args, 'Y') ||
|
||||||
|
args_has(args, 'U') ||
|
||||||
|
args_has(args, 'D') ||
|
||||||
|
args_has(args, 'L') ||
|
||||||
|
args_has(args, 'R'))
|
||||||
|
return (cmd_join_pane_move(item, args, dst_wl, dst_wp));
|
||||||
|
}
|
||||||
|
|
||||||
src_wl = source->wl;
|
src_wl = source->wl;
|
||||||
src_wp = source->wp;
|
src_wp = source->wp;
|
||||||
src_w = src_wl->window;
|
src_w = src_wl->window;
|
||||||
|
|||||||
@@ -27,13 +27,17 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
static enum cmd_retval cmd_kill_pane_exec(struct cmd *, struct cmdq_item *);
|
static enum cmd_retval cmd_kill_pane_exec(struct cmd *, struct cmdq_item *);
|
||||||
|
static enum cmd_retval cmd_kill_pane_all(struct cmdq_item *, const char *);
|
||||||
|
static int cmd_kill_pane_filter(struct cmdq_item *,
|
||||||
|
struct session *, struct winlink *,
|
||||||
|
struct window_pane *, const char *);
|
||||||
|
|
||||||
const struct cmd_entry cmd_kill_pane_entry = {
|
const struct cmd_entry cmd_kill_pane_entry = {
|
||||||
.name = "kill-pane",
|
.name = "kill-pane",
|
||||||
.alias = "killp",
|
.alias = "killp",
|
||||||
|
|
||||||
.args = { "at:", 0, 0, NULL },
|
.args = { "af:t:", 0, 0, NULL },
|
||||||
.usage = "[-a] " CMD_TARGET_PANE_USAGE,
|
.usage = "[-a] [-f filter] " CMD_TARGET_PANE_USAGE,
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_PANE, 0 },
|
.target = { 't', CMD_FIND_PANE, 0 },
|
||||||
|
|
||||||
@@ -46,22 +50,17 @@ cmd_kill_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
{
|
{
|
||||||
struct args *args = cmd_get_args(self);
|
struct args *args = cmd_get_args(self);
|
||||||
struct cmd_find_state *target = cmdq_get_target(item);
|
struct cmd_find_state *target = cmdq_get_target(item);
|
||||||
struct winlink *wl = target->wl;
|
struct window_pane *wp = target->wp;
|
||||||
struct window_pane *loopwp, *tmpwp, *wp = target->wp;
|
const char *filter = args_get(args, 'f');
|
||||||
|
|
||||||
if (args_has(args, 'a')) {
|
if (filter != NULL && !args_has(args, 'a')) {
|
||||||
server_unzoom_window(wl->window);
|
cmdq_error(item, "-f only valid with -a");
|
||||||
TAILQ_FOREACH_SAFE(loopwp, &wl->window->panes, entry, tmpwp) {
|
return (CMD_RETURN_ERROR);
|
||||||
if (loopwp == wp)
|
|
||||||
continue;
|
|
||||||
server_client_remove_pane(loopwp);
|
|
||||||
layout_close_pane(loopwp);
|
|
||||||
window_remove_pane(wl->window, loopwp);
|
|
||||||
}
|
|
||||||
server_redraw_window(wl->window);
|
|
||||||
return (CMD_RETURN_NORMAL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (args_has(args, 'a'))
|
||||||
|
return (cmd_kill_pane_all(item, filter));
|
||||||
|
|
||||||
if (wp == NULL) {
|
if (wp == NULL) {
|
||||||
cmdq_error(item, "no active pane to kill");
|
cmdq_error(item, "no active pane to kill");
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
@@ -69,3 +68,48 @@ cmd_kill_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
server_kill_pane(wp);
|
server_kill_pane(wp);
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static enum cmd_retval
|
||||||
|
cmd_kill_pane_all(struct cmdq_item *item, const char *filter)
|
||||||
|
{
|
||||||
|
struct cmd_find_state *target = cmdq_get_target(item);
|
||||||
|
struct session *s = target->s;
|
||||||
|
struct winlink *wl = target->wl;
|
||||||
|
struct window_pane *wp = target->wp;
|
||||||
|
struct window_pane *loopwp, *tmpwp;
|
||||||
|
|
||||||
|
server_unzoom_window(wl->window);
|
||||||
|
TAILQ_FOREACH_SAFE(loopwp, &wl->window->panes, entry, tmpwp) {
|
||||||
|
if (loopwp == wp)
|
||||||
|
continue;
|
||||||
|
if (!cmd_kill_pane_filter(item, s, wl, loopwp, filter))
|
||||||
|
continue;
|
||||||
|
server_client_remove_pane(loopwp);
|
||||||
|
layout_close_pane(loopwp);
|
||||||
|
window_remove_pane(wl->window, loopwp);
|
||||||
|
}
|
||||||
|
server_redraw_window(wl->window);
|
||||||
|
return (CMD_RETURN_NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
cmd_kill_pane_filter(struct cmdq_item *item, struct session *s,
|
||||||
|
struct winlink *wl, struct window_pane *wp, const char *filter)
|
||||||
|
{
|
||||||
|
struct format_tree *ft;
|
||||||
|
char *expanded;
|
||||||
|
int flag;
|
||||||
|
|
||||||
|
if (filter == NULL)
|
||||||
|
return (1);
|
||||||
|
|
||||||
|
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
|
||||||
|
format_defaults(ft, NULL, s, wl, wp);
|
||||||
|
|
||||||
|
expanded = format_expand(ft, filter);
|
||||||
|
flag = format_true(expanded);
|
||||||
|
free(expanded);
|
||||||
|
|
||||||
|
format_free(ft);
|
||||||
|
return (flag);
|
||||||
|
}
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "tmux.h"
|
#include "tmux.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -28,13 +30,16 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
static enum cmd_retval cmd_kill_session_exec(struct cmd *, struct cmdq_item *);
|
static enum cmd_retval cmd_kill_session_exec(struct cmd *, struct cmdq_item *);
|
||||||
|
static enum cmd_retval cmd_kill_session_all(struct cmdq_item *, const char *);
|
||||||
|
static int cmd_kill_session_filter(struct cmdq_item *,
|
||||||
|
struct session *, const char *);
|
||||||
|
|
||||||
const struct cmd_entry cmd_kill_session_entry = {
|
const struct cmd_entry cmd_kill_session_entry = {
|
||||||
.name = "kill-session",
|
.name = "kill-session",
|
||||||
.alias = NULL,
|
.alias = NULL,
|
||||||
|
|
||||||
.args = { "aCgt:", 0, 0, NULL },
|
.args = { "aCgf:t:", 0, 0, NULL },
|
||||||
.usage = "[-aCg] " CMD_TARGET_SESSION_USAGE,
|
.usage = "[-aCg] [-f filter] " CMD_TARGET_SESSION_USAGE,
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_SESSION, 0 },
|
.target = { 't', CMD_FIND_SESSION, 0 },
|
||||||
|
|
||||||
@@ -50,6 +55,12 @@ cmd_kill_session_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
struct session *s = target->s, *sloop, *stmp;
|
struct session *s = target->s, *sloop, *stmp;
|
||||||
struct session_group *sg;
|
struct session_group *sg;
|
||||||
struct winlink *wl;
|
struct winlink *wl;
|
||||||
|
const char *filter = args_get(args, 'f');
|
||||||
|
|
||||||
|
if (filter != NULL && (!args_has(args, 'a') || args_has(args, 'C'))) {
|
||||||
|
cmdq_error(item, "-f only valid with -a");
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
if (args_has(args, 'C')) {
|
if (args_has(args, 'C')) {
|
||||||
RB_FOREACH(wl, winlinks, &s->windows) {
|
RB_FOREACH(wl, winlinks, &s->windows) {
|
||||||
@@ -57,14 +68,9 @@ cmd_kill_session_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
wl->flags &= ~WINLINK_ALERTFLAGS;
|
wl->flags &= ~WINLINK_ALERTFLAGS;
|
||||||
}
|
}
|
||||||
server_redraw_session(s);
|
server_redraw_session(s);
|
||||||
} else if (args_has(args, 'a')) {
|
} else if (args_has(args, 'a'))
|
||||||
RB_FOREACH_SAFE(sloop, sessions, &sessions, stmp) {
|
return (cmd_kill_session_all(item, filter));
|
||||||
if (sloop != s) {
|
else if (args_has(args, 'g') &&
|
||||||
server_destroy_session(sloop);
|
|
||||||
session_destroy(sloop, 1, __func__);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (args_has(args, 'g') &&
|
|
||||||
(sg = session_group_contains(s)) != NULL) {
|
(sg = session_group_contains(s)) != NULL) {
|
||||||
TAILQ_FOREACH_SAFE(sloop, &sg->sessions, gentry, stmp) {
|
TAILQ_FOREACH_SAFE(sloop, &sg->sessions, gentry, stmp) {
|
||||||
server_destroy_session(sloop);
|
server_destroy_session(sloop);
|
||||||
@@ -76,3 +82,42 @@ cmd_kill_session_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
}
|
}
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static enum cmd_retval
|
||||||
|
cmd_kill_session_all(struct cmdq_item *item, const char *filter)
|
||||||
|
{
|
||||||
|
struct session *s = cmdq_get_target(item)->s;
|
||||||
|
struct session *sloop, *stmp;
|
||||||
|
|
||||||
|
RB_FOREACH_SAFE(sloop, sessions, &sessions, stmp) {
|
||||||
|
if (sloop == s)
|
||||||
|
continue;
|
||||||
|
if (!cmd_kill_session_filter(item, sloop, filter))
|
||||||
|
continue;
|
||||||
|
server_destroy_session(sloop);
|
||||||
|
session_destroy(sloop, 1, __func__);
|
||||||
|
}
|
||||||
|
return (CMD_RETURN_NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
cmd_kill_session_filter(struct cmdq_item *item, struct session *s,
|
||||||
|
const char *filter)
|
||||||
|
{
|
||||||
|
struct format_tree *ft;
|
||||||
|
char *expanded;
|
||||||
|
int flag;
|
||||||
|
|
||||||
|
if (filter == NULL)
|
||||||
|
return (1);
|
||||||
|
|
||||||
|
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
|
||||||
|
format_defaults(ft, NULL, s, NULL, NULL);
|
||||||
|
|
||||||
|
expanded = format_expand(ft, filter);
|
||||||
|
flag = format_true(expanded);
|
||||||
|
free(expanded);
|
||||||
|
|
||||||
|
format_free(ft);
|
||||||
|
return (flag);
|
||||||
|
}
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "tmux.h"
|
#include "tmux.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -25,13 +27,16 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
static enum cmd_retval cmd_kill_window_exec(struct cmd *, struct cmdq_item *);
|
static enum cmd_retval cmd_kill_window_exec(struct cmd *, struct cmdq_item *);
|
||||||
|
static enum cmd_retval cmd_kill_window_all(struct cmdq_item *, const char *);
|
||||||
|
static int cmd_kill_window_filter(struct cmdq_item *,
|
||||||
|
struct session *, struct winlink *, const char *);
|
||||||
|
|
||||||
const struct cmd_entry cmd_kill_window_entry = {
|
const struct cmd_entry cmd_kill_window_entry = {
|
||||||
.name = "kill-window",
|
.name = "kill-window",
|
||||||
.alias = "killw",
|
.alias = "killw",
|
||||||
|
|
||||||
.args = { "at:", 0, 0, NULL },
|
.args = { "af:t:", 0, 0, NULL },
|
||||||
.usage = "[-a] " CMD_TARGET_WINDOW_USAGE,
|
.usage = "[-a] [-f filter] " CMD_TARGET_WINDOW_USAGE,
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_WINDOW, 0 },
|
.target = { 't', CMD_FIND_WINDOW, 0 },
|
||||||
|
|
||||||
@@ -57,10 +62,15 @@ cmd_kill_window_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
{
|
{
|
||||||
struct args *args = cmd_get_args(self);
|
struct args *args = cmd_get_args(self);
|
||||||
struct cmd_find_state *target = cmdq_get_target(item);
|
struct cmd_find_state *target = cmdq_get_target(item);
|
||||||
struct winlink *wl = target->wl, *loop;
|
struct winlink *wl = target->wl;
|
||||||
struct window *w = wl->window;
|
struct window *w = wl->window;
|
||||||
struct session *s = target->s;
|
struct session *s = target->s;
|
||||||
u_int found;
|
const char *filter = args_get(args, 'f');
|
||||||
|
|
||||||
|
if (filter != NULL && !args_has(args, 'a')) {
|
||||||
|
cmdq_error(item, "-f only valid with -a");
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
if (cmd_get_entry(self) == &cmd_unlink_window_entry) {
|
if (cmd_get_entry(self) == &cmd_unlink_window_entry) {
|
||||||
if (!args_has(args, 'k') && !session_is_linked(s, w)) {
|
if (!args_has(args, 'k') && !session_is_linked(s, w)) {
|
||||||
@@ -72,39 +82,76 @@ cmd_kill_window_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args_has(args, 'a')) {
|
if (args_has(args, 'a'))
|
||||||
if (RB_PREV(winlinks, &s->windows, wl) == NULL &&
|
return (cmd_kill_window_all(item, filter));
|
||||||
RB_NEXT(winlinks, &s->windows, wl) == NULL)
|
|
||||||
return (CMD_RETURN_NORMAL);
|
|
||||||
|
|
||||||
/* Kill all windows except the current one. */
|
|
||||||
do {
|
|
||||||
found = 0;
|
|
||||||
RB_FOREACH(loop, winlinks, &s->windows) {
|
|
||||||
if (loop->window != wl->window) {
|
|
||||||
server_kill_window(loop->window, 0);
|
|
||||||
found++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (found != 0);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If the current window appears in the session more than once,
|
|
||||||
* kill it as well.
|
|
||||||
*/
|
|
||||||
found = 0;
|
|
||||||
RB_FOREACH(loop, winlinks, &s->windows) {
|
|
||||||
if (loop->window == wl->window)
|
|
||||||
found++;
|
|
||||||
}
|
|
||||||
if (found > 1)
|
|
||||||
server_kill_window(wl->window, 0);
|
|
||||||
|
|
||||||
server_renumber_all();
|
|
||||||
return (CMD_RETURN_NORMAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
server_kill_window(wl->window, 1);
|
server_kill_window(wl->window, 1);
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static enum cmd_retval
|
||||||
|
cmd_kill_window_all(struct cmdq_item *item, const char *filter)
|
||||||
|
{
|
||||||
|
struct cmd_find_state *target = cmdq_get_target(item);
|
||||||
|
struct session *s = target->s;
|
||||||
|
struct winlink *wl = target->wl;
|
||||||
|
struct winlink *loop;
|
||||||
|
u_int found, kill_current;
|
||||||
|
|
||||||
|
if (RB_PREV(winlinks, &s->windows, wl) == NULL &&
|
||||||
|
RB_NEXT(winlinks, &s->windows, wl) == NULL)
|
||||||
|
return (CMD_RETURN_NORMAL);
|
||||||
|
|
||||||
|
/* Kill all windows except the current one. */
|
||||||
|
do {
|
||||||
|
found = 0;
|
||||||
|
RB_FOREACH(loop, winlinks, &s->windows) {
|
||||||
|
if (loop->window != wl->window &&
|
||||||
|
cmd_kill_window_filter(item, s, loop, filter)) {
|
||||||
|
server_kill_window(loop->window, 0);
|
||||||
|
found++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (found != 0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the current window appears in the session more than once, kill it
|
||||||
|
* as well if it matches the filter.
|
||||||
|
*/
|
||||||
|
found = kill_current = 0;
|
||||||
|
RB_FOREACH(loop, winlinks, &s->windows) {
|
||||||
|
if (loop->window == wl->window) {
|
||||||
|
found++;
|
||||||
|
if (cmd_kill_window_filter(item, s, loop, filter))
|
||||||
|
kill_current = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (kill_current && found > 1)
|
||||||
|
server_kill_window(wl->window, 0);
|
||||||
|
|
||||||
|
server_renumber_all();
|
||||||
|
return (CMD_RETURN_NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
cmd_kill_window_filter(struct cmdq_item *item, struct session *s,
|
||||||
|
struct winlink *wl, const char *filter)
|
||||||
|
{
|
||||||
|
struct format_tree *ft;
|
||||||
|
char *expanded;
|
||||||
|
int flag;
|
||||||
|
|
||||||
|
if (filter == NULL)
|
||||||
|
return (1);
|
||||||
|
|
||||||
|
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
|
||||||
|
format_defaults(ft, NULL, s, wl, NULL);
|
||||||
|
|
||||||
|
expanded = format_expand(ft, filter);
|
||||||
|
flag = format_true(expanded);
|
||||||
|
free(expanded);
|
||||||
|
|
||||||
|
format_free(ft);
|
||||||
|
return (flag);
|
||||||
|
}
|
||||||
|
|||||||
@@ -223,7 +223,12 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
cmd_list_keys_filter_key_list(filter_notes, filter_key, only, l,
|
cmd_list_keys_filter_key_list(filter_notes, filter_key, only, l,
|
||||||
&n);
|
&n);
|
||||||
}
|
}
|
||||||
if (single)
|
if (filter_key && n == 0) {
|
||||||
|
cmdq_error(item, "unknown key: %s", keystr);
|
||||||
|
free(prefix);
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
if (single && n > 1)
|
||||||
n = 1;
|
n = 1;
|
||||||
|
|
||||||
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
|
ft = format_create(cmdq_get_client(item), item, FORMAT_NONE, 0);
|
||||||
@@ -237,7 +242,7 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
cmd_list_keys_format_add_key_binding(ft, l[i], prefix);
|
cmd_list_keys_format_add_key_binding(ft, l[i], prefix);
|
||||||
|
|
||||||
line = format_expand(ft, template);
|
line = format_expand(ft, template);
|
||||||
if ((single && tc != NULL) || n == 1)
|
if (single && tc != NULL && (~tc->flags & CLIENT_CONTROL))
|
||||||
status_message_set(tc, -1, 1, 0, 0, "%s", line);
|
status_message_set(tc, -1, 1, 0, 0, "%s", line);
|
||||||
else if (*line != '\0')
|
else if (*line != '\0')
|
||||||
cmdq_print(item, "%s", line);
|
cmdq_print(item, "%s", line);
|
||||||
|
|||||||
@@ -77,8 +77,8 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
struct termios tio, *tiop;
|
struct termios tio, *tiop;
|
||||||
struct session_group *sg = NULL;
|
struct session_group *sg = NULL;
|
||||||
const char *errstr, *template, *group, *tmp;
|
const char *errstr, *template, *group, *tmp;
|
||||||
char *cause, *cwd = NULL, *cp, *newname = NULL;
|
char *cause, *cwd = NULL, *cp, *ename;
|
||||||
char *name, *prefix = NULL;
|
char *wname = NULL, *sname = NULL, *prefix = NULL;
|
||||||
int detached, already_attached, is_control = 0;
|
int detached, already_attached, is_control = 0;
|
||||||
u_int sx, sy, dsx, dsy, count = args_count(args);
|
u_int sx, sy, dsx, dsy, count = args_count(args);
|
||||||
struct spawn_context sc = { 0 };
|
struct spawn_context sc = { 0 };
|
||||||
@@ -99,20 +99,29 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp = args_get(args, 's');
|
if ((tmp = args_get(args, 'n')) != NULL) {
|
||||||
if (tmp != NULL) {
|
ename = format_single(item, tmp, c, NULL, NULL, NULL);
|
||||||
name = format_single(item, tmp, c, NULL, NULL, NULL);
|
if (!check_name(ename, WINDOW_NAME_FORBID)) {
|
||||||
newname = clean_name(name, "#:.");
|
cmdq_error(item, "invalid window name: %s", ename);
|
||||||
if (newname == NULL) {
|
free(ename);
|
||||||
cmdq_error(item, "invalid session: %s", name);
|
|
||||||
free(name);
|
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
free(name);
|
wname = clean_name(ename, WINDOW_NAME_FORBID);
|
||||||
|
free(ename);
|
||||||
|
}
|
||||||
|
if ((tmp = args_get(args, 's')) != NULL) {
|
||||||
|
ename = format_single(item, tmp, c, NULL, NULL, NULL);
|
||||||
|
if (!check_name(ename, SESSION_NAME_FORBID)) {
|
||||||
|
cmdq_error(item, "invalid session name: %s", ename);
|
||||||
|
free(ename);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
sname = clean_name(ename, SESSION_NAME_FORBID);
|
||||||
|
free(ename);
|
||||||
}
|
}
|
||||||
if (args_has(args, 'A')) {
|
if (args_has(args, 'A')) {
|
||||||
if (newname != NULL)
|
if (sname != NULL)
|
||||||
as = session_find(newname);
|
as = session_find(sname);
|
||||||
else
|
else
|
||||||
as = target->s;
|
as = target->s;
|
||||||
if (as != NULL) {
|
if (as != NULL) {
|
||||||
@@ -120,12 +129,13 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
args_has(args, 'D'), args_has(args, 'X'), 0,
|
args_has(args, 'D'), args_has(args, 'X'), 0,
|
||||||
args_get(args, 'c'), args_has(args, 'E'),
|
args_get(args, 'c'), args_has(args, 'E'),
|
||||||
args_get(args, 'f'));
|
args_get(args, 'f'));
|
||||||
free(newname);
|
free(wname);
|
||||||
|
free(sname);
|
||||||
return (retval);
|
return (retval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (newname != NULL && session_find(newname) != NULL) {
|
if (sname != NULL && session_find(sname) != NULL) {
|
||||||
cmdq_error(item, "duplicate session: %s", newname);
|
cmdq_error(item, "duplicate session: %s", sname);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,12 +152,12 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
else if (groupwith != NULL)
|
else if (groupwith != NULL)
|
||||||
prefix = xstrdup(groupwith->name);
|
prefix = xstrdup(groupwith->name);
|
||||||
else {
|
else {
|
||||||
prefix = clean_name(group, "#:.");
|
if (!check_name(group, SESSION_NAME_FORBID)) {
|
||||||
if (prefix == NULL) {
|
cmdq_error(item,
|
||||||
cmdq_error(item, "invalid session group: %s",
|
"invalid session group name: %s", group);
|
||||||
group);
|
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
prefix = clean_name(group, SESSION_NAME_FORBID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,7 +286,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
environ_put(env, av->string, 0);
|
environ_put(env, av->string, 0);
|
||||||
av = args_next_value(av);
|
av = args_next_value(av);
|
||||||
}
|
}
|
||||||
s = session_create(prefix, newname, cwd, env, oo, tiop);
|
s = session_create(prefix, sname, cwd, env, oo, tiop);
|
||||||
|
|
||||||
/* Spawn the initial window. */
|
/* Spawn the initial window. */
|
||||||
sc.item = item;
|
sc.item = item;
|
||||||
@@ -284,7 +294,7 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
if (!detached)
|
if (!detached)
|
||||||
sc.tc = c;
|
sc.tc = c;
|
||||||
|
|
||||||
sc.name = args_get(args, 'n');
|
sc.name = wname;
|
||||||
args_to_vector(args, &sc.argc, &sc.argv);
|
args_to_vector(args, &sc.argc, &sc.argv);
|
||||||
|
|
||||||
sc.idx = -1;
|
sc.idx = -1;
|
||||||
@@ -357,7 +367,8 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
if (sc.argv != NULL)
|
if (sc.argv != NULL)
|
||||||
cmd_free_argv(sc.argc, sc.argv);
|
cmd_free_argv(sc.argc, sc.argv);
|
||||||
free(cwd);
|
free(cwd);
|
||||||
free(newname);
|
free(wname);
|
||||||
|
free(sname);
|
||||||
free(prefix);
|
free(prefix);
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
|
|
||||||
@@ -365,7 +376,8 @@ fail:
|
|||||||
if (sc.argv != NULL)
|
if (sc.argv != NULL)
|
||||||
cmd_free_argv(sc.argc, sc.argv);
|
cmd_free_argv(sc.argc, sc.argv);
|
||||||
free(cwd);
|
free(cwd);
|
||||||
free(newname);
|
free(wname);
|
||||||
|
free(sname);
|
||||||
free(prefix);
|
free(prefix);
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
struct session *s = target->s;
|
struct session *s = target->s;
|
||||||
struct winlink *wl = target->wl, *new_wl = NULL;
|
struct winlink *wl = target->wl, *new_wl = NULL;
|
||||||
int idx = target->idx, before;
|
int idx = target->idx, before;
|
||||||
char *cause = NULL, *cp, *expanded;
|
char *cause = NULL, *cp, *expanded, *wname = NULL;
|
||||||
const char *template, *name;
|
const char *template, *name;
|
||||||
struct cmd_find_state fs;
|
struct cmd_find_state fs;
|
||||||
struct args_value *av;
|
struct args_value *av;
|
||||||
@@ -71,8 +71,18 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
* name already exists, select it.
|
* name already exists, select it.
|
||||||
*/
|
*/
|
||||||
name = args_get(args, 'n');
|
name = args_get(args, 'n');
|
||||||
if (args_has(args, 'S') && name != NULL && target->idx == -1) {
|
if (name != NULL) {
|
||||||
expanded = format_single(item, name, c, s, NULL, NULL);
|
expanded = format_single(item, name, c, s, NULL, NULL);
|
||||||
|
if (!check_name(expanded, WINDOW_NAME_FORBID)) {
|
||||||
|
cmdq_error(item, "invalid window name: %s", expanded);
|
||||||
|
free(expanded);
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
wname = clean_name(expanded, WINDOW_NAME_FORBID);
|
||||||
|
free(expanded);
|
||||||
|
}
|
||||||
|
if (args_has(args, 'S') && wname != NULL && target->idx == -1) {
|
||||||
|
expanded = format_single(item, wname, c, s, NULL, NULL);
|
||||||
RB_FOREACH(wl, winlinks, &s->windows) {
|
RB_FOREACH(wl, winlinks, &s->windows) {
|
||||||
if (strcmp(wl->window->name, expanded) != 0)
|
if (strcmp(wl->window->name, expanded) != 0)
|
||||||
continue;
|
continue;
|
||||||
@@ -80,12 +90,14 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
new_wl = wl;
|
new_wl = wl;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
cmdq_error(item, "multiple windows named %s", name);
|
cmdq_error(item, "multiple windows named %s", wname);
|
||||||
|
free(wname);
|
||||||
free(expanded);
|
free(expanded);
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
free(expanded);
|
free(expanded);
|
||||||
if (new_wl != NULL) {
|
if (new_wl != NULL) {
|
||||||
|
free(wname);
|
||||||
if (args_has(args, 'd'))
|
if (args_has(args, 'd'))
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
if (session_set_current(s, new_wl) == 0)
|
if (session_set_current(s, new_wl) == 0)
|
||||||
@@ -108,7 +120,7 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
sc.s = s;
|
sc.s = s;
|
||||||
sc.tc = tc;
|
sc.tc = tc;
|
||||||
|
|
||||||
sc.name = args_get(args, 'n');
|
sc.name = wname;
|
||||||
args_to_vector(args, &sc.argc, &sc.argv);
|
args_to_vector(args, &sc.argc, &sc.argv);
|
||||||
sc.environ = environ_create();
|
sc.environ = environ_create();
|
||||||
|
|
||||||
@@ -130,10 +142,7 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
if ((new_wl = spawn_window(&sc, &cause)) == NULL) {
|
if ((new_wl = spawn_window(&sc, &cause)) == NULL) {
|
||||||
cmdq_error(item, "create window failed: %s", cause);
|
cmdq_error(item, "create window failed: %s", cause);
|
||||||
free(cause);
|
free(cause);
|
||||||
if (sc.argv != NULL)
|
goto fail;
|
||||||
cmd_free_argv(sc.argc, sc.argv);
|
|
||||||
environ_free(sc.environ);
|
|
||||||
return (CMD_RETURN_ERROR);
|
|
||||||
}
|
}
|
||||||
if (!args_has(args, 'd') || new_wl == s->curw) {
|
if (!args_has(args, 'd') || new_wl == s->curw) {
|
||||||
cmd_find_from_winlink(current, new_wl, 0);
|
cmd_find_from_winlink(current, new_wl, 0);
|
||||||
@@ -156,5 +165,13 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
if (sc.argv != NULL)
|
if (sc.argv != NULL)
|
||||||
cmd_free_argv(sc.argc, sc.argv);
|
cmd_free_argv(sc.argc, sc.argv);
|
||||||
environ_free(sc.environ);
|
environ_free(sc.environ);
|
||||||
|
free(wname);
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
|
|
||||||
|
fail:
|
||||||
|
if (sc.argv != NULL)
|
||||||
|
cmd_free_argv(sc.argc, sc.argv);
|
||||||
|
environ_free(sc.environ);
|
||||||
|
free(wname);
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -168,6 +168,7 @@ cmd_refresh_report(struct tty *tty, const char *value)
|
|||||||
{
|
{
|
||||||
struct window_pane *wp;
|
struct window_pane *wp;
|
||||||
u_int pane;
|
u_int pane;
|
||||||
|
int fg, bg;
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
char *copy, *split;
|
char *copy, *split;
|
||||||
|
|
||||||
@@ -184,8 +185,14 @@ cmd_refresh_report(struct tty *tty, const char *value)
|
|||||||
if (wp == NULL)
|
if (wp == NULL)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
tty_keys_colours(tty, split, strlen(split), &size, &wp->control_fg,
|
fg = wp->control_fg;
|
||||||
&wp->control_bg);
|
bg = wp->control_bg;
|
||||||
|
if (tty_keys_colours(tty, split, strlen(split), &size, &fg, &bg) == 0) {
|
||||||
|
if (bg != wp->control_bg)
|
||||||
|
wp->flags |= PANE_THEMECHANGED;
|
||||||
|
wp->control_fg = fg;
|
||||||
|
wp->control_bg = bg;
|
||||||
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
free(copy);
|
free(copy);
|
||||||
|
|||||||
@@ -52,12 +52,12 @@ cmd_rename_session_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
char *newname, *tmp;
|
char *newname, *tmp;
|
||||||
|
|
||||||
tmp = format_single_from_target(item, args_string(args, 0));
|
tmp = format_single_from_target(item, args_string(args, 0));
|
||||||
newname = clean_name(tmp, "#:.");
|
if (!check_name(tmp, SESSION_NAME_FORBID)) {
|
||||||
if (newname == NULL) {
|
cmdq_error(item, "invalid session name: %s", tmp);
|
||||||
cmdq_error(item, "invalid session: %s", tmp);
|
|
||||||
free(tmp);
|
free(tmp);
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
|
newname = clean_name(tmp, SESSION_NAME_FORBID);
|
||||||
free(tmp);
|
free(tmp);
|
||||||
if (strcmp(newname, s->name) == 0) {
|
if (strcmp(newname, s->name) == 0) {
|
||||||
free(newname);
|
free(newname);
|
||||||
|
|||||||
@@ -48,15 +48,21 @@ cmd_rename_window_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
struct args *args = cmd_get_args(self);
|
struct args *args = cmd_get_args(self);
|
||||||
struct cmd_find_state *target = cmdq_get_target(item);
|
struct cmd_find_state *target = cmdq_get_target(item);
|
||||||
struct winlink *wl = target->wl;
|
struct winlink *wl = target->wl;
|
||||||
char *newname;
|
char *name;
|
||||||
|
|
||||||
newname = format_single_from_target(item, args_string(args, 0));
|
name = format_single_from_target(item, args_string(args, 0));
|
||||||
window_set_name(wl->window, newname);
|
if (!check_name(name, WINDOW_NAME_FORBID)) {
|
||||||
|
cmdq_error(item, "invalid window name: %s", name);
|
||||||
|
free(name);
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
window_set_name(wl->window, name, WINDOW_NAME_FORBID);
|
||||||
options_set_number(wl->window->options, "automatic-rename", 0);
|
options_set_number(wl->window->options, "automatic-rename", 0);
|
||||||
|
free(name);
|
||||||
|
|
||||||
server_redraw_window_borders(wl->window);
|
server_redraw_window_borders(wl->window);
|
||||||
server_status_window(wl->window);
|
server_status_window(wl->window);
|
||||||
free(newname);
|
|
||||||
|
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,18 +31,18 @@ static enum cmd_retval cmd_resize_pane_exec(struct cmd *, struct cmdq_item *);
|
|||||||
|
|
||||||
static enum cmd_retval cmd_resize_pane_mouse_update(struct cmd *,
|
static enum cmd_retval cmd_resize_pane_mouse_update(struct cmd *,
|
||||||
struct cmdq_item *);
|
struct cmdq_item *);
|
||||||
static void cmd_resize_pane_mouse_update_floating(struct client *,
|
static void cmd_resize_pane_mouse_resize_move_floating(
|
||||||
struct mouse_event *);
|
struct client *, struct mouse_event *);
|
||||||
static void cmd_resize_pane_mouse_update_tiled(struct client *,
|
static void cmd_resize_pane_mouse_resize_tiled(struct client *,
|
||||||
struct mouse_event *);
|
struct mouse_event *);
|
||||||
|
|
||||||
const struct cmd_entry cmd_resize_pane_entry = {
|
const struct cmd_entry cmd_resize_pane_entry = {
|
||||||
.name = "resize-pane",
|
.name = "resize-pane",
|
||||||
.alias = "resizep",
|
.alias = "resizep",
|
||||||
|
|
||||||
.args = { "DLMRTt:Ux:y:Z", 0, 1, NULL },
|
.args = { "D::L::MR::Tt:U::x:y:Z", 0, 1, NULL },
|
||||||
.usage = "[-DLMRTUZ] [-x width] [-y height] " CMD_TARGET_PANE_USAGE " "
|
.usage = "[-MTZ] [-D lines] [-L columns] [-R columns] [-U lines] "
|
||||||
"[adjustment]",
|
"[-x width] [-y height] " CMD_TARGET_PANE_USAGE,
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_PANE, 0 },
|
.target = { 't', CMD_FIND_PANE, 0 },
|
||||||
|
|
||||||
@@ -58,17 +58,21 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
struct window_pane *wp = target->wp;
|
struct window_pane *wp = target->wp;
|
||||||
struct winlink *wl = target->wl;
|
struct winlink *wl = target->wl;
|
||||||
struct window *w = wl->window;
|
struct window *w = wl->window;
|
||||||
const char *errstr;
|
struct layout_cell *lc = wp->layout_cell;
|
||||||
char *cause;
|
enum layout_type type;
|
||||||
u_int adjust;
|
const char *errstr, *argval;
|
||||||
int x, y, status;
|
const char flags[4] = { 'U', 'D', 'L', 'R' };
|
||||||
|
char *cause = NULL, flag;
|
||||||
|
u_int opposite = 0;
|
||||||
|
int adjust, x, y, status;
|
||||||
|
long unsigned i;
|
||||||
struct grid *gd = wp->base.grid;
|
struct grid *gd = wp->base.grid;
|
||||||
|
|
||||||
if (args_has(args, 'T')) {
|
if (args_has(args, 'T')) {
|
||||||
if (!TAILQ_EMPTY(&wp->modes))
|
if (!TAILQ_EMPTY(&wp->modes))
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
adjust = screen_size_y(&wp->base) - 1 - wp->base.cy;
|
adjust = screen_size_y(&wp->base) - 1 - wp->base.cy;
|
||||||
if (adjust > gd->hsize)
|
if (adjust > (int)gd->hsize)
|
||||||
adjust = gd->hsize;
|
adjust = gd->hsize;
|
||||||
grid_remove_history(gd, adjust);
|
grid_remove_history(gd, adjust);
|
||||||
wp->base.cy += adjust;
|
wp->base.cy += adjust;
|
||||||
@@ -89,33 +93,32 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
}
|
}
|
||||||
server_unzoom_window(w);
|
server_unzoom_window(w);
|
||||||
|
|
||||||
if (args_count(args) == 0)
|
|
||||||
adjust = 1;
|
|
||||||
else {
|
|
||||||
adjust = strtonum(args_string(args, 0), 1, INT_MAX, &errstr);
|
|
||||||
if (errstr != NULL) {
|
|
||||||
cmdq_error(item, "adjustment %s", errstr);
|
|
||||||
return (CMD_RETURN_ERROR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (args_has(args, 'x')) {
|
if (args_has(args, 'x')) {
|
||||||
x = args_percentage(args, 'x', 0, INT_MAX, w->sx, &cause);
|
x = args_percentage(args, 'x', 0, PANE_MAXIMUM, w->sx, &cause);
|
||||||
if (cause != NULL) {
|
if (cause != NULL) {
|
||||||
cmdq_error(item, "width %s", cause);
|
cmdq_error(item, "width %s", cause);
|
||||||
free(cause);
|
free(cause);
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
layout_resize_pane_to(wp, LAYOUT_LEFTRIGHT, x);
|
if (window_pane_is_floating(wp)) {
|
||||||
|
layout_resize_floating_pane_to(wp, LAYOUT_LEFTRIGHT, x,
|
||||||
|
&cause);
|
||||||
|
if (cause != NULL) {
|
||||||
|
cmdq_error(item, "size %s", cause);
|
||||||
|
free(cause);
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
layout_resize_pane_to(wp, LAYOUT_LEFTRIGHT, x);
|
||||||
}
|
}
|
||||||
if (args_has(args, 'y')) {
|
if (args_has(args, 'y')) {
|
||||||
y = args_percentage(args, 'y', 0, INT_MAX, w->sy, &cause);
|
y = args_percentage(args, 'y', 0, PANE_MAXIMUM, w->sy, &cause);
|
||||||
if (cause != NULL) {
|
if (cause != NULL) {
|
||||||
cmdq_error(item, "height %s", cause);
|
cmdq_error(item, "height %s", cause);
|
||||||
free(cause);
|
free(cause);
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
status = options_get_number(w->options, "pane-border-status");
|
status = window_get_pane_status(w);
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case PANE_STATUS_TOP:
|
case PANE_STATUS_TOP:
|
||||||
if (y != INT_MAX && wp->yoff == 1)
|
if (y != INT_MAX && wp->yoff == 1)
|
||||||
@@ -126,18 +129,60 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
y++;
|
y++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
layout_resize_pane_to(wp, LAYOUT_TOPBOTTOM, y);
|
if (window_pane_is_floating(wp)) {
|
||||||
|
layout_resize_floating_pane_to(wp, LAYOUT_TOPBOTTOM, y,
|
||||||
|
&cause);
|
||||||
|
if (cause != NULL) {
|
||||||
|
cmdq_error(item, "size %s", cause);
|
||||||
|
free(cause);
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
layout_resize_pane_to(wp, LAYOUT_TOPBOTTOM, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args_has(args, 'L'))
|
for (i = 0; i < nitems(flags); i++) {
|
||||||
layout_resize_pane(wp, LAYOUT_LEFTRIGHT, -adjust, 1);
|
flag = flags[i];
|
||||||
else if (args_has(args, 'R'))
|
if (!args_has(args, flag))
|
||||||
layout_resize_pane(wp, LAYOUT_LEFTRIGHT, adjust, 1);
|
continue;
|
||||||
else if (args_has(args, 'U'))
|
|
||||||
layout_resize_pane(wp, LAYOUT_TOPBOTTOM, -adjust, 1);
|
argval = args_get(args, flag);
|
||||||
else if (args_has(args, 'D'))
|
if (argval == NULL)
|
||||||
layout_resize_pane(wp, LAYOUT_TOPBOTTOM, adjust, 1);
|
argval = "1";
|
||||||
server_redraw_window(wl->window);
|
|
||||||
|
adjust = strtonum(argval, INT_MIN, INT_MAX, &errstr);
|
||||||
|
if (errstr != NULL) {
|
||||||
|
cmdq_error(item, "adjustment %s", errstr);
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
type = LAYOUT_TOPBOTTOM;
|
||||||
|
if (flag == 'L' || flag == 'R')
|
||||||
|
type = LAYOUT_LEFTRIGHT;
|
||||||
|
|
||||||
|
if (window_pane_is_floating(wp)) {
|
||||||
|
if (flag == 'L' || flag == 'U')
|
||||||
|
opposite = 1;
|
||||||
|
|
||||||
|
layout_resize_floating_pane(wp, type, adjust, opposite,
|
||||||
|
&cause);
|
||||||
|
if (cause != NULL) {
|
||||||
|
cmdq_error(item, "adjustment %s", cause);
|
||||||
|
free(cause);
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (flag == 'L' || flag == 'U')
|
||||||
|
adjust = -adjust;
|
||||||
|
layout_resize_pane(wp, type, adjust, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lc->parent != NULL)
|
||||||
|
layout_fix_offsets(w);
|
||||||
|
layout_fix_panes(w, NULL);
|
||||||
|
notify_window("window-layout-changed", w);
|
||||||
|
server_redraw_window(w);
|
||||||
|
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
@@ -160,27 +205,36 @@ cmd_resize_pane_mouse_update(__unused struct cmd *self, struct cmdq_item *item)
|
|||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
|
|
||||||
if (!window_pane_is_floating(wp)) {
|
if (!window_pane_is_floating(wp)) {
|
||||||
c->tty.mouse_drag_update = cmd_resize_pane_mouse_update_tiled;
|
c->tty.mouse_drag_update = cmd_resize_pane_mouse_resize_tiled;
|
||||||
cmd_resize_pane_mouse_update_tiled(c, &event->m);
|
cmd_resize_pane_mouse_resize_tiled(c, &event->m);
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
window_redraw_active_switch(w, wp);
|
window_redraw_active_switch(w, wp);
|
||||||
window_set_active_pane(w, wp, 1);
|
window_set_active_pane(w, wp, 1);
|
||||||
|
|
||||||
c->tty.mouse_drag_update = cmd_resize_pane_mouse_update_floating;
|
c->tty.mouse_drag_update = cmd_resize_pane_mouse_resize_move_floating;
|
||||||
cmd_resize_pane_mouse_update_floating(c, &event->m);
|
cmd_resize_pane_mouse_resize_move_floating(c, &event->m);
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Resizes or moves the pane by dragging. Resize a floating pane by dragging
|
||||||
|
* the borders or corners. Grabbing an edge only resizes that axis (special
|
||||||
|
* case). Moves the pane if dragging the top border. Since characters are
|
||||||
|
* generally rectangular, to make it easier to grab the corner, the character
|
||||||
|
* next to the corner is also considered the corner.
|
||||||
|
*/
|
||||||
static void
|
static void
|
||||||
cmd_resize_pane_mouse_update_floating(struct client *c, struct mouse_event *m)
|
cmd_resize_pane_mouse_resize_move_floating(struct client *c,
|
||||||
|
struct mouse_event *m)
|
||||||
{
|
{
|
||||||
struct winlink *wl;
|
struct winlink *wl;
|
||||||
struct window *w;
|
struct window *w;
|
||||||
struct window_pane *wp;
|
struct window_pane *wp;
|
||||||
struct layout_cell *lc;
|
struct layout_cell *lc;
|
||||||
int y, ly, x, lx, sx, sy, new_sx, new_sy;
|
int y, ly, x, lx, sx, sy, new_sx, new_sy;
|
||||||
|
int scrollbars, sb_pos, left, right;
|
||||||
int new_xoff, new_yoff, resizes = 0;
|
int new_xoff, new_yoff, resizes = 0;
|
||||||
|
|
||||||
wp = cmd_mouse_pane(m, NULL, &wl);
|
wp = cmd_mouse_pane(m, NULL, &wl);
|
||||||
@@ -192,6 +246,17 @@ cmd_resize_pane_mouse_update_floating(struct client *c, struct mouse_event *m)
|
|||||||
lc = wp->layout_cell;
|
lc = wp->layout_cell;
|
||||||
sx = wp->sx;
|
sx = wp->sx;
|
||||||
sy = wp->sy;
|
sy = wp->sy;
|
||||||
|
scrollbars = options_get_number(w->options, "pane-scrollbars");
|
||||||
|
sb_pos = options_get_number(w->options, "pane-scrollbars-position");
|
||||||
|
left = wp->xoff - 1;
|
||||||
|
right = wp->xoff + sx;
|
||||||
|
if (window_pane_show_scrollbar(wp, scrollbars) &&
|
||||||
|
sb_pos == PANE_SCROLLBARS_LEFT) {
|
||||||
|
left -= wp->scrollbar_style.width + wp->scrollbar_style.pad;
|
||||||
|
} else if (window_pane_show_scrollbar(wp, scrollbars) &&
|
||||||
|
sb_pos == PANE_SCROLLBARS_RIGHT) {
|
||||||
|
right += wp->scrollbar_style.width + wp->scrollbar_style.pad;
|
||||||
|
}
|
||||||
|
|
||||||
y = m->y + m->oy; x = m->x + m->ox;
|
y = m->y + m->oy; x = m->x + m->ox;
|
||||||
if (m->statusat == 0 && y >= (int)m->statuslines)
|
if (m->statusat == 0 && y >= (int)m->statuslines)
|
||||||
@@ -204,7 +269,7 @@ cmd_resize_pane_mouse_update_floating(struct client *c, struct mouse_event *m)
|
|||||||
else if (m->statusat > 0 && ly >= m->statusat)
|
else if (m->statusat > 0 && ly >= m->statusat)
|
||||||
ly = m->statusat - 1;
|
ly = m->statusat - 1;
|
||||||
|
|
||||||
if ((lx == wp->xoff - 1 || lx == wp->xoff) && ly == wp->yoff - 1) {
|
if ((lx == left || lx == left + 1) && ly == wp->yoff - 1) {
|
||||||
/* Top left corner. */
|
/* Top left corner. */
|
||||||
new_sx = lc->sx + (lx - x);
|
new_sx = lc->sx + (lx - x);
|
||||||
if (new_sx < PANE_MINIMUM)
|
if (new_sx < PANE_MINIMUM)
|
||||||
@@ -216,7 +281,7 @@ cmd_resize_pane_mouse_update_floating(struct client *c, struct mouse_event *m)
|
|||||||
new_yoff = y + 1;
|
new_yoff = y + 1;
|
||||||
layout_set_size(lc, new_sx, new_sy, new_xoff, new_yoff);
|
layout_set_size(lc, new_sx, new_sy, new_xoff, new_yoff);
|
||||||
resizes++;
|
resizes++;
|
||||||
} else if ((lx == wp->xoff + sx + 1 || lx == wp->xoff + sx) &&
|
} else if ((lx == right + 1 || lx == right) &&
|
||||||
ly == wp->yoff - 1) {
|
ly == wp->yoff - 1) {
|
||||||
/* Top right corner. */
|
/* Top right corner. */
|
||||||
new_sx = x - lc->xoff;
|
new_sx = x - lc->xoff;
|
||||||
@@ -228,7 +293,7 @@ cmd_resize_pane_mouse_update_floating(struct client *c, struct mouse_event *m)
|
|||||||
new_yoff = y + 1;
|
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->xoff, new_yoff);
|
||||||
resizes++;
|
resizes++;
|
||||||
} else if ((lx == wp->xoff - 1 || lx == wp->xoff) &&
|
} else if ((lx == left || lx == left + 1) &&
|
||||||
ly == wp->yoff + sy) {
|
ly == wp->yoff + sy) {
|
||||||
/* Bottom left corner. */
|
/* Bottom left corner. */
|
||||||
new_sx = lc->sx + (lx - x);
|
new_sx = lc->sx + (lx - x);
|
||||||
@@ -240,7 +305,7 @@ cmd_resize_pane_mouse_update_floating(struct client *c, struct mouse_event *m)
|
|||||||
new_xoff = x + 1;
|
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->yoff);
|
||||||
resizes++;
|
resizes++;
|
||||||
} else if ((lx == wp->xoff + sx + 1 || lx == wp->xoff + sx) &&
|
} else if ((lx == right + 1 || lx == right) &&
|
||||||
ly == wp->yoff + sy) {
|
ly == wp->yoff + sy) {
|
||||||
/* Bottom right corner. */
|
/* Bottom right corner. */
|
||||||
new_sx = x - lc->xoff;
|
new_sx = x - lc->xoff;
|
||||||
@@ -251,14 +316,14 @@ cmd_resize_pane_mouse_update_floating(struct client *c, struct mouse_event *m)
|
|||||||
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->xoff, lc->yoff);
|
||||||
resizes++;
|
resizes++;
|
||||||
} else if (lx == wp->xoff + sx + 1) {
|
} else if (lx == right) {
|
||||||
/* Right border. */
|
/* Right border. */
|
||||||
new_sx = x - lc->xoff;
|
new_sx = x - lc->xoff;
|
||||||
if (new_sx < PANE_MINIMUM)
|
if (new_sx < PANE_MINIMUM)
|
||||||
return;
|
return;
|
||||||
layout_set_size(lc, new_sx, lc->sy, lc->xoff, lc->yoff);
|
layout_set_size(lc, new_sx, lc->sy, lc->xoff, lc->yoff);
|
||||||
resizes++;
|
resizes++;
|
||||||
} else if (lx == wp->xoff - 1) {
|
} else if (lx == left) {
|
||||||
/* Left border. */
|
/* Left border. */
|
||||||
new_sx = lc->sx + (lx - x);
|
new_sx = lc->sx + (lx - x);
|
||||||
if (new_sx < PANE_MINIMUM)
|
if (new_sx < PANE_MINIMUM)
|
||||||
@@ -288,7 +353,7 @@ cmd_resize_pane_mouse_update_floating(struct client *c, struct mouse_event *m)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
cmd_resize_pane_mouse_update_tiled(struct client *c, struct mouse_event *m)
|
cmd_resize_pane_mouse_resize_tiled(struct client *c, struct mouse_event *m)
|
||||||
{
|
{
|
||||||
struct winlink *wl;
|
struct winlink *wl;
|
||||||
struct window *w;
|
struct window *w;
|
||||||
|
|||||||
@@ -109,6 +109,7 @@ cmd_rotate_window_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
window_set_active_pane(w, wp, 1);
|
window_set_active_pane(w, wp, 1);
|
||||||
cmd_find_from_winlink_pane(current, wl, wp, 0);
|
cmd_find_from_winlink_pane(current, wl, wp, 0);
|
||||||
window_pop_zoom(w);
|
window_pop_zoom(w);
|
||||||
|
redraw_invalidate_scene(w);
|
||||||
server_redraw_window(w);
|
server_redraw_window(w);
|
||||||
|
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (args_has(args, 'm') || args_has(args, 'M')) {
|
if (args_has(args, 'm') || args_has(args, 'M')) {
|
||||||
if (args_has(args, 'm') && !window_pane_visible(wp))
|
if (args_has(args, 'm') && !window_pane_is_visible(wp))
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
if (server_check_marked())
|
if (server_check_marked())
|
||||||
lastwp = marked_pane.wp;
|
lastwp = marked_pane.wp;
|
||||||
@@ -217,7 +217,7 @@ cmd_select_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
|
|
||||||
if (args_has(args, 'T')) {
|
if (args_has(args, 'T')) {
|
||||||
title = format_single_from_target(item, args_get(args, 'T'));
|
title = format_single_from_target(item, args_get(args, 'T'));
|
||||||
if (screen_set_title(&wp->base, title)) {
|
if (screen_set_title(&wp->base, title, 0)) {
|
||||||
notify_pane("pane-title-changed", wp);
|
notify_pane("pane-title-changed", wp);
|
||||||
server_redraw_window_borders(wp->window);
|
server_redraw_window_borders(wp->window);
|
||||||
server_status_window(wp->window);
|
server_status_window(wp->window);
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ cmd_send_keys_inject_key(struct cmdq_item *item, struct cmdq_item *after,
|
|||||||
struct key_table *table = NULL;
|
struct key_table *table = NULL;
|
||||||
struct key_binding *bd;
|
struct key_binding *bd;
|
||||||
struct key_event *event;
|
struct key_event *event;
|
||||||
|
struct cmdq_item *new_after = after;
|
||||||
|
|
||||||
if (args_has(args, 'K')) {
|
if (args_has(args, 'K')) {
|
||||||
if (tc == NULL)
|
if (tc == NULL)
|
||||||
@@ -77,10 +78,16 @@ cmd_send_keys_inject_key(struct cmdq_item *item, struct cmdq_item *after,
|
|||||||
event = xcalloc(1, sizeof *event);
|
event = xcalloc(1, sizeof *event);
|
||||||
event->key = key|KEYC_SENT;
|
event->key = key|KEYC_SENT;
|
||||||
memset(&event->m, 0, sizeof event->m);
|
memset(&event->m, 0, sizeof event->m);
|
||||||
if (server_client_handle_key(tc, event) == 0) {
|
if (after == NULL) {
|
||||||
free(event->buf);
|
if (server_client_handle_key(tc, event) != 0)
|
||||||
free(event);
|
return (item);
|
||||||
|
} else {
|
||||||
|
if (server_client_handle_key_after(tc, event, after,
|
||||||
|
&new_after) != 0)
|
||||||
|
return (new_after);
|
||||||
}
|
}
|
||||||
|
free(event->buf);
|
||||||
|
free(event);
|
||||||
return (item);
|
return (item);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -229,8 +236,10 @@ cmd_send_keys_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
if (args_has(args, 'N') || args_has(args, 'R'))
|
if (args_has(args, 'N') || args_has(args, 'R'))
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
|
after = args_has(args, 'K') ? item : NULL;
|
||||||
for (; np != 0; np--)
|
for (; np != 0; np--)
|
||||||
cmd_send_keys_inject_key(item, NULL, args, event->key);
|
after = cmd_send_keys_inject_key(item, after, args,
|
||||||
|
event->key);
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <grp.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -37,67 +38,71 @@ const struct cmd_entry cmd_server_access_entry = {
|
|||||||
.name = "server-access",
|
.name = "server-access",
|
||||||
.alias = NULL,
|
.alias = NULL,
|
||||||
|
|
||||||
.args = { "adlrw", 0, 1, NULL },
|
.args = { "adglrw", 0, 1, NULL },
|
||||||
.usage = "[-adlrw] " CMD_TARGET_PANE_USAGE " [user]",
|
.usage = "[-adglrw] " CMD_TARGET_PANE_USAGE " [user|group]",
|
||||||
|
|
||||||
.flags = CMD_CLIENT_CANFAIL,
|
.flags = CMD_CLIENT_CANFAIL,
|
||||||
.exec = cmd_server_access_exec
|
.exec = cmd_server_access_exec
|
||||||
};
|
};
|
||||||
|
|
||||||
static enum cmd_retval
|
static enum cmd_retval
|
||||||
cmd_server_access_deny(struct cmdq_item *item, struct passwd *pw)
|
cmd_server_access_deny(struct cmdq_item *item, id_t id, int flags,
|
||||||
|
const char *type, const char *name)
|
||||||
{
|
{
|
||||||
struct client *loop;
|
if (!server_acl_find(id, flags)) {
|
||||||
struct server_acl_user *user;
|
cmdq_error(item, "%s %s not found", type, name);
|
||||||
uid_t uid;
|
|
||||||
|
|
||||||
if ((user = server_acl_user_find(pw->pw_uid)) == NULL) {
|
|
||||||
cmdq_error(item, "user %s not found", pw->pw_name);
|
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
TAILQ_FOREACH(loop, &clients, entry) {
|
server_acl_deny(id, flags);
|
||||||
uid = proc_get_peer_uid(loop->peer);
|
|
||||||
if (uid == server_acl_get_uid(user)) {
|
|
||||||
loop->exit_message = xstrdup("access not allowed");
|
|
||||||
loop->flags |= CLIENT_EXIT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
server_acl_user_deny(pw->pw_uid);
|
|
||||||
|
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum cmd_retval
|
static enum cmd_retval
|
||||||
cmd_server_access_exec(struct cmd *self, struct cmdq_item *item)
|
cmd_server_access_exec(struct cmd *self, struct cmdq_item *item)
|
||||||
{
|
{
|
||||||
|
|
||||||
struct args *args = cmd_get_args(self);
|
struct args *args = cmd_get_args(self);
|
||||||
struct client *c = cmdq_get_target_client(item);
|
struct client *c = cmdq_get_target_client(item);
|
||||||
char *name;
|
char *arg;
|
||||||
struct passwd *pw = NULL;
|
const char *name = NULL, *type;
|
||||||
|
struct passwd *pw;
|
||||||
|
struct group *gr;
|
||||||
|
id_t id;
|
||||||
|
int flags = 0;
|
||||||
|
|
||||||
if (args_has(args, 'l')) {
|
if (args_has(args, 'l')) {
|
||||||
server_acl_display(item);
|
server_acl_display(item);
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
if (args_count(args) == 0) {
|
if (args_count(args) == 0) {
|
||||||
cmdq_error(item, "missing user argument");
|
cmdq_error(item, "missing user or group argument");
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
name = format_single(item, args_string(args, 0), c, NULL, NULL, NULL);
|
arg = format_single(item, args_string(args, 0), c, NULL, NULL, NULL);
|
||||||
if (*name != '\0')
|
if (args_has(args, 'g')) {
|
||||||
pw = getpwnam(name);
|
type = "group";
|
||||||
if (pw == NULL) {
|
if ((gr = getgrnam(arg)) != NULL) {
|
||||||
cmdq_error(item, "unknown user: %s", name);
|
id = gr->gr_gid;
|
||||||
free(name);
|
name = gr->gr_name;
|
||||||
|
flags |= SERVER_ACL_IS_GROUP;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
type = "user";
|
||||||
|
if ((pw = getpwnam(arg)) != NULL) {
|
||||||
|
id = pw->pw_uid;
|
||||||
|
name = pw->pw_name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (name == NULL) {
|
||||||
|
cmdq_error(item, "unknown %s: %s", type, arg);
|
||||||
|
free(arg);
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
free(name);
|
free(arg);
|
||||||
|
|
||||||
if (pw->pw_uid == 0 || pw->pw_uid == getuid()) {
|
if ((~flags & SERVER_ACL_IS_GROUP) && (id == 0 || id == getuid())) {
|
||||||
cmdq_error(item, "%s owns the server, can't change access",
|
cmdq_error(item, "%s owns the server, can't change access",
|
||||||
pw->pw_name);
|
name);
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,36 +116,35 @@ cmd_server_access_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (args_has(args, 'd'))
|
if (args_has(args, 'd'))
|
||||||
return (cmd_server_access_deny(item, pw));
|
return (cmd_server_access_deny(item, id, flags, type, name));
|
||||||
if (args_has(args, 'a')) {
|
if (args_has(args, 'a')) {
|
||||||
if (server_acl_user_find(pw->pw_uid) != NULL) {
|
if (server_acl_find(id, flags)) {
|
||||||
cmdq_error(item, "user %s is already added",
|
cmdq_error(item, "%s %s is already added", type, name);
|
||||||
pw->pw_name);
|
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
server_acl_user_allow(pw->pw_uid);
|
server_acl_allow(id, flags);
|
||||||
/* Do not return - allow -r or -w with -a. */
|
/* Do not return - allow -r or -w with -a. */
|
||||||
} else if (args_has(args, 'r') || args_has(args, 'w')) {
|
} else if (args_has(args, 'r') || args_has(args, 'w')) {
|
||||||
/* -r or -w implies -a if user does not exist. */
|
/* -r or -w implies -a if the entry does not exist. */
|
||||||
if (server_acl_user_find(pw->pw_uid) == NULL)
|
if (!server_acl_find(id, flags))
|
||||||
server_acl_user_allow(pw->pw_uid);
|
server_acl_allow(id, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args_has(args, 'w')) {
|
if (args_has(args, 'w')) {
|
||||||
if (server_acl_user_find(pw->pw_uid) == NULL) {
|
if (!server_acl_find(id, flags)) {
|
||||||
cmdq_error(item, "user %s not found", pw->pw_name);
|
cmdq_error(item, "%s %s not found", type, name);
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
server_acl_user_allow_write(pw->pw_uid);
|
server_acl_allow_write(id, flags);
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (args_has(args, 'r')) {
|
if (args_has(args, 'r')) {
|
||||||
if (server_acl_user_find(pw->pw_uid) == NULL) {
|
if (!server_acl_find(id, flags)) {
|
||||||
cmdq_error(item, "user %s not found", pw->pw_name);
|
cmdq_error(item, "%s %s not found", type, name);
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
server_acl_user_deny_write(pw->pw_uid);
|
server_acl_deny_write(id, flags);
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -55,56 +55,44 @@ cmd_show_prompt_history_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
struct args *args = cmd_get_args(self);
|
struct args *args = cmd_get_args(self);
|
||||||
const char *typestr = args_get(args, 'T');
|
const char *typestr = args_get(args, 'T');
|
||||||
enum prompt_type type;
|
enum prompt_type type;
|
||||||
u_int tidx, hidx;
|
u_int t, h;
|
||||||
|
const char *v;
|
||||||
|
|
||||||
if (cmd_get_entry(self) == &cmd_clear_prompt_history_entry) {
|
if (cmd_get_entry(self) == &cmd_clear_prompt_history_entry) {
|
||||||
if (typestr == NULL) {
|
if (typestr == NULL) {
|
||||||
for (tidx = 0; tidx < PROMPT_NTYPES; tidx++) {
|
for (t = 0; t < PROMPT_NTYPES; t++)
|
||||||
for (hidx = 0; hidx < status_prompt_hsize[tidx];
|
prompt_history_clear(t);
|
||||||
hidx++)
|
|
||||||
free(status_prompt_hlist[tidx][hidx]);
|
|
||||||
free(status_prompt_hlist[tidx]);
|
|
||||||
status_prompt_hlist[tidx] = NULL;
|
|
||||||
status_prompt_hsize[tidx] = 0;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
type = status_prompt_type(typestr);
|
type = prompt_type(typestr);
|
||||||
if (type == PROMPT_TYPE_INVALID) {
|
if (type == PROMPT_TYPE_INVALID) {
|
||||||
cmdq_error(item, "invalid type: %s", typestr);
|
cmdq_error(item, "invalid type: %s", typestr);
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
for (hidx = 0; hidx < status_prompt_hsize[type]; hidx++)
|
prompt_history_clear(type);
|
||||||
free(status_prompt_hlist[type][hidx]);
|
|
||||||
free(status_prompt_hlist[type]);
|
|
||||||
status_prompt_hlist[type] = NULL;
|
|
||||||
status_prompt_hsize[type] = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typestr == NULL) {
|
if (typestr == NULL) {
|
||||||
for (tidx = 0; tidx < PROMPT_NTYPES; tidx++) {
|
for (t = 0; t < PROMPT_NTYPES; t++) {
|
||||||
cmdq_print(item, "History for %s:\n",
|
typestr = prompt_type_string(t);
|
||||||
status_prompt_type_string(tidx));
|
cmdq_print(item, "History for %s:\n", typestr);
|
||||||
for (hidx = 0; hidx < status_prompt_hsize[tidx];
|
for (h = 0; h < prompt_history_size(t); h++) {
|
||||||
hidx++) {
|
v = prompt_history_get(t, h);
|
||||||
cmdq_print(item, "%d: %s", hidx + 1,
|
cmdq_print(item, "%d: %s", h + 1, v);
|
||||||
status_prompt_hlist[tidx][hidx]);
|
|
||||||
}
|
}
|
||||||
cmdq_print(item, "%s", "");
|
cmdq_print(item, "%s", "");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
type = status_prompt_type(typestr);
|
type = prompt_type(typestr);
|
||||||
if (type == PROMPT_TYPE_INVALID) {
|
if (type == PROMPT_TYPE_INVALID) {
|
||||||
cmdq_error(item, "invalid type: %s", typestr);
|
cmdq_error(item, "invalid type: %s", typestr);
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
cmdq_print(item, "History for %s:\n",
|
cmdq_print(item, "History for %s:\n", prompt_type_string(type));
|
||||||
status_prompt_type_string(type));
|
for (h = 0; h < prompt_history_size(type); h++) {
|
||||||
for (hidx = 0; hidx < status_prompt_hsize[type]; hidx++) {
|
v = prompt_history_get(type, h);
|
||||||
cmdq_print(item, "%d: %s", hidx + 1,
|
cmdq_print(item, "%d: %s", h + 1, v);
|
||||||
status_prompt_hlist[type][hidx]);
|
|
||||||
}
|
}
|
||||||
cmdq_print(item, "%s", "");
|
cmdq_print(item, "%s", "");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,11 +38,12 @@ const struct cmd_entry cmd_new_pane_entry = {
|
|||||||
.name = "new-pane",
|
.name = "new-pane",
|
||||||
.alias = "newp",
|
.alias = "newp",
|
||||||
|
|
||||||
.args = { "bc:de:EfF:hIkl:Lm:p:PR:s:S:t:vx:X:y:Y:Z", 0, -1, NULL },
|
.args = { "bB:c:de:EfF:hIkl:Lm:p:PR:s:S:t:T:vWx:X:y:Y:Z", 0, -1, NULL },
|
||||||
.usage = "[-bdefhIklPvZ] [-c start-directory] [-e environment] "
|
.usage = "[-bdefhIklPvWZ] [-B border-lines] "
|
||||||
"[-F format] [-l size] [-m message] [-p percentage] "
|
"[-c start-directory] [-e environment] "
|
||||||
|
"[-F format] [-l size] [-m message] [-p percentage] "
|
||||||
"[-s style] [-S active-border-style] "
|
"[-s style] [-S active-border-style] "
|
||||||
"[-R inactive-border-style] [-x width] [-y height] "
|
"[-R inactive-border-style] [-T title] [-x width] [-y height] "
|
||||||
"[-X x-position] [-Y y-position] " CMD_TARGET_PANE_USAGE " "
|
"[-X x-position] [-Y y-position] " CMD_TARGET_PANE_USAGE " "
|
||||||
"[shell-command [argument ...]]",
|
"[shell-command [argument ...]]",
|
||||||
|
|
||||||
@@ -56,11 +57,11 @@ const struct cmd_entry cmd_split_window_entry = {
|
|||||||
.name = "split-window",
|
.name = "split-window",
|
||||||
.alias = "splitw",
|
.alias = "splitw",
|
||||||
|
|
||||||
.args = { "bc:de:EfF:hIkl:m:p:PR:s:S:t:vZ", 0, -1, NULL },
|
.args = { "bc:de:EfF:hIkl:m:p:PR:s:S:t:T:vWZ", 0, -1, NULL },
|
||||||
.usage = "[-bdefhIklPvZ] [-c start-directory] [-e environment] "
|
.usage = "[-bdefhIklPvWZ] [-c start-directory] [-e environment] "
|
||||||
"[-F format] [-l size] [-m message] [-p percentage] "
|
"[-F format] [-l size] [-m message] [-p percentage] "
|
||||||
"[-s style] [-S active-border-style] "
|
"[-s style] [-S active-border-style] "
|
||||||
"[-R inactive-border-style] " CMD_TARGET_PANE_USAGE " "
|
"[-R inactive-border-style] [-T title] " CMD_TARGET_PANE_USAGE " "
|
||||||
"[shell-command [argument ...]]",
|
"[shell-command [argument ...]]",
|
||||||
|
|
||||||
.target = { 't', CMD_FIND_PANE, 0 },
|
.target = { 't', CMD_FIND_PANE, 0 },
|
||||||
@@ -84,9 +85,11 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
struct layout_cell *lc = NULL;
|
struct layout_cell *lc = NULL;
|
||||||
struct cmd_find_state fs;
|
struct cmd_find_state fs;
|
||||||
int input, empty, is_floating, flags = 0;
|
int input, empty, is_floating, flags = 0;
|
||||||
const char *template, *style;
|
const char *template, *style, *value;
|
||||||
char *cause = NULL, *cp;
|
char *cause = NULL, *cp, *title;
|
||||||
|
const struct options_table_entry *oe;
|
||||||
struct args_value *av;
|
struct args_value *av;
|
||||||
|
enum pane_lines lines;
|
||||||
u_int count = args_count(args);
|
u_int count = args_count(args);
|
||||||
|
|
||||||
if (cmd_get_entry(self) == &cmd_new_pane_entry)
|
if (cmd_get_entry(self) == &cmd_new_pane_entry)
|
||||||
@@ -114,12 +117,24 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
if (empty)
|
if (empty)
|
||||||
flags |= SPAWN_EMPTY;
|
flags |= SPAWN_EMPTY;
|
||||||
|
|
||||||
|
if ((value = args_get(args, 'B')) == NULL)
|
||||||
|
lines = window_get_pane_lines(w);
|
||||||
|
else {
|
||||||
|
oe = options_search("pane-border-lines");
|
||||||
|
lines = options_find_choice(oe, value, &cause);
|
||||||
|
if (cause != NULL) {
|
||||||
|
cmdq_error(item, "pane-border-lines %s", cause);
|
||||||
|
free(cause);
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (is_floating)
|
if (is_floating)
|
||||||
lc = layout_get_floating_cell(item, args, w, wp, &cause);
|
lc = layout_get_floating_cell(item, args, lines, w, wp, &cause);
|
||||||
else
|
else
|
||||||
lc = layout_get_tiled_cell(item, args, w, wp, flags, &cause);
|
lc = layout_get_tiled_cell(item, args, w, wp, flags, &cause);
|
||||||
if (cause != NULL) {
|
if (cause != NULL) {
|
||||||
cmdq_error(item, "size or position %s", cause);
|
cmdq_error(item, "%s", cause);
|
||||||
free(cause);
|
free(cause);
|
||||||
return (CMD_RETURN_ERROR);
|
return (CMD_RETURN_ERROR);
|
||||||
}
|
}
|
||||||
@@ -152,10 +167,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
if ((new_wp = spawn_pane(&sc, &cause)) == NULL) {
|
if ((new_wp = spawn_pane(&sc, &cause)) == NULL) {
|
||||||
cmdq_error(item, "create pane failed: %s", cause);
|
cmdq_error(item, "create pane failed: %s", cause);
|
||||||
free(cause);
|
free(cause);
|
||||||
if (sc.argv != NULL)
|
goto fail;
|
||||||
cmd_free_argv(sc.argc, sc.argv);
|
|
||||||
environ_free(sc.environ);
|
|
||||||
return (CMD_RETURN_ERROR);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
style = args_get(args, 's');
|
style = args_get(args, 's');
|
||||||
@@ -163,7 +175,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
if (options_set_string(new_wp->options, "window-style", 0,
|
if (options_set_string(new_wp->options, "window-style", 0,
|
||||||
"%s", style) == NULL) {
|
"%s", style) == NULL) {
|
||||||
cmdq_error(item, "bad style: %s", style);
|
cmdq_error(item, "bad style: %s", style);
|
||||||
return (CMD_RETURN_ERROR);
|
goto fail;
|
||||||
}
|
}
|
||||||
options_set_string(new_wp->options, "window-active-style", 0,
|
options_set_string(new_wp->options, "window-active-style", 0,
|
||||||
"%s", style);
|
"%s", style);
|
||||||
@@ -175,7 +187,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
if (options_set_string(new_wp->options,
|
if (options_set_string(new_wp->options,
|
||||||
"pane-active-border-style", 0, "%s", style) == NULL) {
|
"pane-active-border-style", 0, "%s", style) == NULL) {
|
||||||
cmdq_error(item, "bad active border style: %s", style);
|
cmdq_error(item, "bad active border style: %s", style);
|
||||||
return (CMD_RETURN_ERROR);
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
style = args_get(args, 'R');
|
style = args_get(args, 'R');
|
||||||
@@ -184,15 +196,24 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
"%s", style) == NULL) {
|
"%s", style) == NULL) {
|
||||||
cmdq_error(item, "bad inactive border style: %s",
|
cmdq_error(item, "bad inactive border style: %s",
|
||||||
style);
|
style);
|
||||||
return (CMD_RETURN_ERROR);
|
goto fail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (args_has(args, 'B'))
|
||||||
|
options_set_number(new_wp->options, "pane-border-lines", lines);
|
||||||
if (args_has(args, 'k') || args_has(args, 'm')) {
|
if (args_has(args, 'k') || args_has(args, 'm')) {
|
||||||
options_set_number(new_wp->options, "remain-on-exit", 3);
|
options_set_number(new_wp->options, "remain-on-exit", 3);
|
||||||
if (args_has(args, 'm'))
|
if (args_has(args, 'm')) {
|
||||||
options_set_string(new_wp->options,
|
options_set_string(new_wp->options,
|
||||||
"remain-on-exit-format",
|
"remain-on-exit-format", 0, "%s",
|
||||||
0, "%s", args_get(args, 'm'));
|
args_get(args, 'm'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (args_has(args, 'T')) {
|
||||||
|
title = format_single_from_target(item, args_get(args, 'T'));
|
||||||
|
screen_set_title(&new_wp->base, title, 0);
|
||||||
|
notify_pane("pane-title-changed", new_wp);
|
||||||
|
free(title);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (input) {
|
if (input) {
|
||||||
@@ -204,10 +225,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
window_remove_pane(wp->window, new_wp);
|
window_remove_pane(wp->window, new_wp);
|
||||||
cmdq_error(item, "%s", cause);
|
cmdq_error(item, "%s", cause);
|
||||||
free(cause);
|
free(cause);
|
||||||
if (sc.argv != NULL)
|
goto fail;
|
||||||
cmd_free_argv(sc.argc, sc.argv);
|
|
||||||
environ_free(sc.environ);
|
|
||||||
return (CMD_RETURN_ERROR);
|
|
||||||
case 1:
|
case 1:
|
||||||
input = 0;
|
input = 0;
|
||||||
break;
|
break;
|
||||||
@@ -238,5 +256,24 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
environ_free(sc.environ);
|
environ_free(sc.environ);
|
||||||
if (input)
|
if (input)
|
||||||
return (CMD_RETURN_WAIT);
|
return (CMD_RETURN_WAIT);
|
||||||
|
|
||||||
|
if (args_has(args, 'W')) {
|
||||||
|
/*
|
||||||
|
* With -W, block this command queue item until the pane's
|
||||||
|
* command exits; window_pane_wait_finish will be called to
|
||||||
|
* continue it.
|
||||||
|
*/
|
||||||
|
new_wp->wait_item = item;
|
||||||
|
return (CMD_RETURN_WAIT);
|
||||||
|
}
|
||||||
return (CMD_RETURN_NORMAL);
|
return (CMD_RETURN_NORMAL);
|
||||||
|
|
||||||
|
fail:
|
||||||
|
if (sc.argv != NULL)
|
||||||
|
cmd_free_argv(sc.argc, sc.argv);
|
||||||
|
environ_free(sc.environ);
|
||||||
|
layout_destroy_cell(w, lc, &w->layout_root);
|
||||||
|
|
||||||
|
return (CMD_RETURN_ERROR);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -114,10 +114,6 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
dst_wp->layout_cell = src_lc;
|
dst_wp->layout_cell = src_lc;
|
||||||
dst_lc->wp = src_wp;
|
dst_lc->wp = src_wp;
|
||||||
src_wp->layout_cell = dst_lc;
|
src_wp->layout_cell = dst_lc;
|
||||||
if (window_pane_is_floating(src_wp) != window_pane_is_floating(dst_wp)) {
|
|
||||||
src_wp->layout_cell->flags ^= LAYOUT_CELL_FLOATING;
|
|
||||||
dst_wp->layout_cell->flags ^= LAYOUT_CELL_FLOATING;
|
|
||||||
}
|
|
||||||
|
|
||||||
src_wp->window = dst_w;
|
src_wp->window = dst_w;
|
||||||
options_set_parent(src_wp->options, dst_w->options);
|
options_set_parent(src_wp->options, dst_w->options);
|
||||||
@@ -153,9 +149,11 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
|
|||||||
colour_palette_from_option(&src_wp->palette, src_wp->options);
|
colour_palette_from_option(&src_wp->palette, src_wp->options);
|
||||||
colour_palette_from_option(&dst_wp->palette, dst_wp->options);
|
colour_palette_from_option(&dst_wp->palette, dst_wp->options);
|
||||||
layout_fix_panes(src_w, NULL);
|
layout_fix_panes(src_w, NULL);
|
||||||
|
redraw_invalidate_scene(src_w);
|
||||||
server_redraw_window(src_w);
|
server_redraw_window(src_w);
|
||||||
}
|
}
|
||||||
layout_fix_panes(dst_w, NULL);
|
layout_fix_panes(dst_w, NULL);
|
||||||
|
redraw_invalidate_scene(dst_w);
|
||||||
server_redraw_window(dst_w);
|
server_redraw_window(dst_w);
|
||||||
|
|
||||||
notify_window("window-layout-changed", src_w);
|
notify_window("window-layout-changed", src_w);
|
||||||
|
|||||||
22
colour.c
22
colour.c
@@ -120,6 +120,28 @@ colour_force_rgb(int c)
|
|||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Dim colour by a percentage. */
|
||||||
|
int
|
||||||
|
colour_dim(int c, u_int dim)
|
||||||
|
{
|
||||||
|
u_char r, g, b;
|
||||||
|
|
||||||
|
if (dim == 0 || COLOUR_DEFAULT(c))
|
||||||
|
return (c);
|
||||||
|
if (dim >= 100)
|
||||||
|
return (colour_join_rgb(0, 0, 0));
|
||||||
|
|
||||||
|
c = colour_force_rgb(c);
|
||||||
|
if (c == -1)
|
||||||
|
return (-1);
|
||||||
|
colour_split_rgb(c, &r, &g, &b);
|
||||||
|
|
||||||
|
r = (r * (100 - dim)) / 100;
|
||||||
|
g = (g * (100 - dim)) / 100;
|
||||||
|
b = (b * (100 - dim)) / 100;
|
||||||
|
return (colour_join_rgb(r, g, b));
|
||||||
|
}
|
||||||
|
|
||||||
/* Convert colour to a string. */
|
/* Convert colour to a string. */
|
||||||
const char *
|
const char *
|
||||||
colour_tostring(int c)
|
colour_tostring(int c)
|
||||||
|
|||||||
@@ -339,7 +339,7 @@ static int
|
|||||||
getopt_internal(int nargc, char * const *nargv, const char *options,
|
getopt_internal(int nargc, char * const *nargv, const char *options,
|
||||||
const struct option *long_options, int *idx, int flags)
|
const struct option *long_options, int *idx, int flags)
|
||||||
{
|
{
|
||||||
char *oli; /* option letter list index */
|
const char *oli; /* option letter list index */
|
||||||
int optchar, short_too;
|
int optchar, short_too;
|
||||||
static int posixly_correct = -1;
|
static int posixly_correct = -1;
|
||||||
|
|
||||||
|
|||||||
35
configure.ac
35
configure.ac
@@ -297,24 +297,24 @@ fi
|
|||||||
# Look for ncurses or curses. Try pkg-config first then directly for the
|
# Look for ncurses or curses. Try pkg-config first then directly for the
|
||||||
# library.
|
# library.
|
||||||
PKG_CHECK_MODULES(
|
PKG_CHECK_MODULES(
|
||||||
LIBTINFO,
|
LIBTINFOW,
|
||||||
tinfo,
|
tinfow,
|
||||||
[
|
[
|
||||||
AM_CPPFLAGS="$LIBTINFO_CFLAGS $AM_CPPFLAGS"
|
AM_CPPFLAGS="$LIBTINFOW_CFLAGS $AM_CPPFLAGS"
|
||||||
CPPFLAGS="$LIBTINFO_CFLAGS $SAVED_CPPFLAGS"
|
CPPFLAGS="$LIBTINFOW_CFLAGS $SAVED_CPPFLAGS"
|
||||||
LIBS="$LIBTINFO_LIBS $LIBS"
|
LIBS="$LIBTINFOW_LIBS $LIBS"
|
||||||
found_ncurses=yes
|
found_ncurses=yes
|
||||||
],
|
],
|
||||||
found_ncurses=no
|
found_ncurses=no
|
||||||
)
|
)
|
||||||
if test "x$found_ncurses" = xno; then
|
if test "x$found_ncurses" = xno; then
|
||||||
PKG_CHECK_MODULES(
|
PKG_CHECK_MODULES(
|
||||||
LIBNCURSES,
|
LIBTINFO,
|
||||||
ncurses,
|
tinfo,
|
||||||
[
|
[
|
||||||
AM_CPPFLAGS="$LIBNCURSES_CFLAGS $AM_CPPFLAGS"
|
AM_CPPFLAGS="$LIBTINFO_CFLAGS $AM_CPPFLAGS"
|
||||||
CPPFLAGS="$LIBNCURSES_CFLAGS $SAVED_CPPFLAGS"
|
CPPFLAGS="$LIBTINFO_CFLAGS $SAVED_CPPFLAGS"
|
||||||
LIBS="$LIBNCURSES_LIBS $LIBS"
|
LIBS="$LIBTINFO_LIBS $LIBS"
|
||||||
found_ncurses=yes
|
found_ncurses=yes
|
||||||
],
|
],
|
||||||
found_ncurses=no
|
found_ncurses=no
|
||||||
@@ -333,10 +333,23 @@ if test "x$found_ncurses" = xno; then
|
|||||||
found_ncurses=no
|
found_ncurses=no
|
||||||
)
|
)
|
||||||
fi
|
fi
|
||||||
|
if test "x$found_ncurses" = xno; then
|
||||||
|
PKG_CHECK_MODULES(
|
||||||
|
LIBNCURSES,
|
||||||
|
ncurses,
|
||||||
|
[
|
||||||
|
AM_CPPFLAGS="$LIBNCURSES_CFLAGS $AM_CPPFLAGS"
|
||||||
|
CPPFLAGS="$LIBNCURSES_CFLAGS $SAVED_CPPFLAGS"
|
||||||
|
LIBS="$LIBNCURSES_LIBS $LIBS"
|
||||||
|
found_ncurses=yes
|
||||||
|
],
|
||||||
|
found_ncurses=no
|
||||||
|
)
|
||||||
|
fi
|
||||||
if test "x$found_ncurses" = xno; then
|
if test "x$found_ncurses" = xno; then
|
||||||
AC_SEARCH_LIBS(
|
AC_SEARCH_LIBS(
|
||||||
setupterm,
|
setupterm,
|
||||||
[tinfo terminfo ncurses ncursesw],
|
[tinfow tinfo terminfo ncursesw ncurses],
|
||||||
found_ncurses=yes,
|
found_ncurses=yes,
|
||||||
found_ncurses=no
|
found_ncurses=no
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -224,6 +224,14 @@ control_notify_session_window_changed(struct session *s)
|
|||||||
{
|
{
|
||||||
struct client *c;
|
struct client *c;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A deferred session-window-changed notification can fire after the
|
||||||
|
* session has been destroyed (which sets curw to NULL) but is kept
|
||||||
|
* alive by the notification's reference. Skip the notification.
|
||||||
|
*/
|
||||||
|
if (s->curw == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
TAILQ_FOREACH(c, &clients, entry) {
|
TAILQ_FOREACH(c, &clients, entry) {
|
||||||
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
|
if (!CONTROL_SHOULD_NOTIFY_CLIENT(c))
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -152,7 +152,8 @@ environ_clear(struct environ *env, const char *name)
|
|||||||
void
|
void
|
||||||
environ_put(struct environ *env, const char *var, int flags)
|
environ_put(struct environ *env, const char *var, int flags)
|
||||||
{
|
{
|
||||||
char *name, *value;
|
char *name;
|
||||||
|
const char *value;
|
||||||
|
|
||||||
value = strchr(var, '=');
|
value = strchr(var, '=');
|
||||||
if (value == NULL)
|
if (value == NULL)
|
||||||
|
|||||||
320
format.c
320
format.c
@@ -117,6 +117,10 @@ format_job_cmp(struct format_job *fj1, struct format_job *fj2)
|
|||||||
#define FORMAT_NOT_NOT 0x100000
|
#define FORMAT_NOT_NOT 0x100000
|
||||||
#define FORMAT_REPEAT 0x200000
|
#define FORMAT_REPEAT 0x200000
|
||||||
#define FORMAT_QUOTE_ARGUMENTS 0x400000
|
#define FORMAT_QUOTE_ARGUMENTS 0x400000
|
||||||
|
#define FORMAT_RELATIVE 0x800000
|
||||||
|
#define FORMAT_CLIENT_TERMCAP 0x1000000
|
||||||
|
#define FORMAT_CLIENT_TERMFEAT 0x2000000
|
||||||
|
#define FORMAT_CLIENT_ENVIRON 0x4000000
|
||||||
|
|
||||||
/* Limit on recursion. */
|
/* Limit on recursion. */
|
||||||
#define FORMAT_LOOP_LIMIT 100
|
#define FORMAT_LOOP_LIMIT 100
|
||||||
@@ -124,6 +128,9 @@ format_job_cmp(struct format_job *fj1, struct format_job *fj2)
|
|||||||
/* Limit on time taken (milliseconds). */
|
/* Limit on time taken (milliseconds). */
|
||||||
#define FORMAT_TIME_LIMIT 100
|
#define FORMAT_TIME_LIMIT 100
|
||||||
|
|
||||||
|
/* How often to check the time in long loops. */
|
||||||
|
#define FORMAT_TIME_LOOP_CHECK 10000
|
||||||
|
|
||||||
/* Format expand flags. */
|
/* Format expand flags. */
|
||||||
#define FORMAT_EXPAND_TIME 0x1
|
#define FORMAT_EXPAND_TIME 0x1
|
||||||
#define FORMAT_EXPAND_NOJOBS 0x2
|
#define FORMAT_EXPAND_NOJOBS 0x2
|
||||||
@@ -569,7 +576,7 @@ format_cb_session_attached_list(struct format_tree *ft)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((size = EVBUFFER_LENGTH(buffer)) != 0)
|
if ((size = EVBUFFER_LENGTH(buffer)) != 0)
|
||||||
xasprintf(&value, "%.*s", size, EVBUFFER_DATA(buffer));
|
value = xmemdup(EVBUFFER_DATA(buffer), size);
|
||||||
evbuffer_free(buffer);
|
evbuffer_free(buffer);
|
||||||
return (value);
|
return (value);
|
||||||
}
|
}
|
||||||
@@ -708,7 +715,7 @@ format_cb_window_linked_sessions_list(struct format_tree *ft)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((size = EVBUFFER_LENGTH(buffer)) != 0)
|
if ((size = EVBUFFER_LENGTH(buffer)) != 0)
|
||||||
xasprintf(&value, "%.*s", size, EVBUFFER_DATA(buffer));
|
value = xmemdup(EVBUFFER_DATA(buffer), size);
|
||||||
evbuffer_free(buffer);
|
evbuffer_free(buffer);
|
||||||
return (value);
|
return (value);
|
||||||
}
|
}
|
||||||
@@ -762,7 +769,7 @@ format_cb_window_active_sessions_list(struct format_tree *ft)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((size = EVBUFFER_LENGTH(buffer)) != 0)
|
if ((size = EVBUFFER_LENGTH(buffer)) != 0)
|
||||||
xasprintf(&value, "%.*s", size, EVBUFFER_DATA(buffer));
|
value = xmemdup(EVBUFFER_DATA(buffer), size);
|
||||||
evbuffer_free(buffer);
|
evbuffer_free(buffer);
|
||||||
return (value);
|
return (value);
|
||||||
}
|
}
|
||||||
@@ -826,7 +833,7 @@ format_cb_window_active_clients_list(struct format_tree *ft)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((size = EVBUFFER_LENGTH(buffer)) != 0)
|
if ((size = EVBUFFER_LENGTH(buffer)) != 0)
|
||||||
xasprintf(&value, "%.*s", size, EVBUFFER_DATA(buffer));
|
value = xmemdup(EVBUFFER_DATA(buffer), size);
|
||||||
evbuffer_free(buffer);
|
evbuffer_free(buffer);
|
||||||
return (value);
|
return (value);
|
||||||
}
|
}
|
||||||
@@ -1001,7 +1008,7 @@ format_cb_pane_tabs(struct format_tree *ft)
|
|||||||
evbuffer_add_printf(buffer, "%u", i);
|
evbuffer_add_printf(buffer, "%u", i);
|
||||||
}
|
}
|
||||||
if ((size = EVBUFFER_LENGTH(buffer)) != 0)
|
if ((size = EVBUFFER_LENGTH(buffer)) != 0)
|
||||||
xasprintf(&value, "%.*s", size, EVBUFFER_DATA(buffer));
|
value = xmemdup(EVBUFFER_DATA(buffer), size);
|
||||||
evbuffer_free(buffer);
|
evbuffer_free(buffer);
|
||||||
return (value);
|
return (value);
|
||||||
}
|
}
|
||||||
@@ -1016,7 +1023,7 @@ format_cb_pane_fg(struct format_tree *ft)
|
|||||||
if (wp == NULL)
|
if (wp == NULL)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
|
||||||
tty_default_colours(&gc, wp);
|
tty_default_colours(&gc, wp, NULL);
|
||||||
return (xstrdup(colour_tostring(gc.fg)));
|
return (xstrdup(colour_tostring(gc.fg)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1053,7 +1060,7 @@ format_cb_pane_bg(struct format_tree *ft)
|
|||||||
if (wp == NULL)
|
if (wp == NULL)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
|
||||||
tty_default_colours(&gc, wp);
|
tty_default_colours(&gc, wp, NULL);
|
||||||
return (xstrdup(colour_tostring(gc.bg)));
|
return (xstrdup(colour_tostring(gc.bg)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1085,7 +1092,7 @@ format_cb_session_group_list(struct format_tree *ft)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((size = EVBUFFER_LENGTH(buffer)) != 0)
|
if ((size = EVBUFFER_LENGTH(buffer)) != 0)
|
||||||
xasprintf(&value, "%.*s", size, EVBUFFER_DATA(buffer));
|
value = xmemdup(EVBUFFER_DATA(buffer), size);
|
||||||
evbuffer_free(buffer);
|
evbuffer_free(buffer);
|
||||||
return (value);
|
return (value);
|
||||||
}
|
}
|
||||||
@@ -1125,7 +1132,7 @@ format_cb_session_group_attached_list(struct format_tree *ft)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((size = EVBUFFER_LENGTH(buffer)) != 0)
|
if ((size = EVBUFFER_LENGTH(buffer)) != 0)
|
||||||
xasprintf(&value, "%.*s", size, EVBUFFER_DATA(buffer));
|
value = xmemdup(EVBUFFER_DATA(buffer), size);
|
||||||
evbuffer_free(buffer);
|
evbuffer_free(buffer);
|
||||||
return (value);
|
return (value);
|
||||||
}
|
}
|
||||||
@@ -1153,15 +1160,13 @@ static void *
|
|||||||
format_cb_pane_at_top(struct format_tree *ft)
|
format_cb_pane_at_top(struct format_tree *ft)
|
||||||
{
|
{
|
||||||
struct window_pane *wp = ft->wp;
|
struct window_pane *wp = ft->wp;
|
||||||
struct window *w;
|
|
||||||
int status, flag;
|
int status, flag;
|
||||||
char *value;
|
char *value;
|
||||||
|
|
||||||
if (wp == NULL)
|
if (wp == NULL)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
w = wp->window;
|
|
||||||
|
|
||||||
status = options_get_number(w->options, "pane-border-status");
|
status = window_pane_get_pane_status(wp);
|
||||||
if (status == PANE_STATUS_TOP)
|
if (status == PANE_STATUS_TOP)
|
||||||
flag = (wp->yoff == 1);
|
flag = (wp->yoff == 1);
|
||||||
else
|
else
|
||||||
@@ -1183,7 +1188,7 @@ format_cb_pane_at_bottom(struct format_tree *ft)
|
|||||||
return (NULL);
|
return (NULL);
|
||||||
w = wp->window;
|
w = wp->window;
|
||||||
|
|
||||||
status = options_get_number(w->options, "pane-border-status");
|
status = window_pane_get_pane_status(wp);
|
||||||
if (status == PANE_STATUS_BOTTOM)
|
if (status == PANE_STATUS_BOTTOM)
|
||||||
flag = (wp->yoff + (int)wp->sy == (int)w->sy - 1);
|
flag = (wp->yoff + (int)wp->sy == (int)w->sy - 1);
|
||||||
else
|
else
|
||||||
@@ -1472,6 +1477,33 @@ format_cb_client_cell_width(struct format_tree *ft)
|
|||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Callback for client_colours. */
|
||||||
|
static void *
|
||||||
|
format_cb_client_colours(struct format_tree *ft)
|
||||||
|
{
|
||||||
|
struct tty_term *term;
|
||||||
|
u_int colours;
|
||||||
|
|
||||||
|
if (ft->c == NULL || (~ft->c->tty.flags & TTY_STARTED))
|
||||||
|
return (NULL);
|
||||||
|
term = ft->c->tty.term;
|
||||||
|
|
||||||
|
if (term->flags & TERM_RGBCOLOURS)
|
||||||
|
colours = 16777216;
|
||||||
|
else if (term->flags & TERM_256COLOURS)
|
||||||
|
colours = 256;
|
||||||
|
else {
|
||||||
|
colours = tty_term_number(term, TTYC_COLORS);
|
||||||
|
if (colours < 8)
|
||||||
|
colours = 2;
|
||||||
|
else if (colours < 16)
|
||||||
|
colours = 8;
|
||||||
|
else
|
||||||
|
colours = 16;
|
||||||
|
}
|
||||||
|
return (format_printf("%u", colours));
|
||||||
|
}
|
||||||
|
|
||||||
/* Callback for client_control_mode. */
|
/* Callback for client_control_mode. */
|
||||||
static void *
|
static void *
|
||||||
format_cb_client_control_mode(struct format_tree *ft)
|
format_cb_client_control_mode(struct format_tree *ft)
|
||||||
@@ -1851,15 +1883,6 @@ format_cb_keypad_flag(struct format_tree *ft)
|
|||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Callback for loop_last_flag. */
|
|
||||||
static void *
|
|
||||||
format_cb_loop_last_flag(struct format_tree *ft)
|
|
||||||
{
|
|
||||||
if (ft->flags & FORMAT_LAST)
|
|
||||||
return (xstrdup("1"));
|
|
||||||
return (xstrdup("0"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Callback for mouse_all_flag. */
|
/* Callback for mouse_all_flag. */
|
||||||
static void *
|
static void *
|
||||||
format_cb_mouse_all_flag(struct format_tree *ft)
|
format_cb_mouse_all_flag(struct format_tree *ft)
|
||||||
@@ -3218,6 +3241,9 @@ static const struct format_table_entry format_table[] = {
|
|||||||
{ "client_cell_width", FORMAT_TABLE_STRING,
|
{ "client_cell_width", FORMAT_TABLE_STRING,
|
||||||
format_cb_client_cell_width
|
format_cb_client_cell_width
|
||||||
},
|
},
|
||||||
|
{ "client_colours", FORMAT_TABLE_STRING,
|
||||||
|
format_cb_client_colours
|
||||||
|
},
|
||||||
{ "client_control_mode", FORMAT_TABLE_STRING,
|
{ "client_control_mode", FORMAT_TABLE_STRING,
|
||||||
format_cb_client_control_mode
|
format_cb_client_control_mode
|
||||||
},
|
},
|
||||||
@@ -3344,9 +3370,6 @@ static const struct format_table_entry format_table[] = {
|
|||||||
{ "last_window_index", FORMAT_TABLE_STRING,
|
{ "last_window_index", FORMAT_TABLE_STRING,
|
||||||
format_cb_last_window_index
|
format_cb_last_window_index
|
||||||
},
|
},
|
||||||
{ "loop_last_flag", FORMAT_TABLE_STRING,
|
|
||||||
format_cb_loop_last_flag
|
|
||||||
},
|
|
||||||
{ "mouse_all_flag", FORMAT_TABLE_STRING,
|
{ "mouse_all_flag", FORMAT_TABLE_STRING,
|
||||||
format_cb_mouse_all_flag
|
format_cb_mouse_all_flag
|
||||||
},
|
},
|
||||||
@@ -3774,7 +3797,7 @@ format_table_compare(const void *key0, const void *entry0)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Get a format callback. */
|
/* Get a format callback. */
|
||||||
static struct format_table_entry *
|
static const struct format_table_entry *
|
||||||
format_table_get(const char *key)
|
format_table_get(const char *key)
|
||||||
{
|
{
|
||||||
return (bsearch(key, format_table, nitems(format_table),
|
return (bsearch(key, format_table, nitems(format_table),
|
||||||
@@ -4063,12 +4086,52 @@ format_pretty_time(time_t t, int seconds)
|
|||||||
return (xstrdup(s));
|
return (xstrdup(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Make a relative time. */
|
||||||
|
static char *
|
||||||
|
format_relative_time(time_t t)
|
||||||
|
{
|
||||||
|
time_t now, age;
|
||||||
|
u_int d, h, m, s;
|
||||||
|
char out[32];
|
||||||
|
|
||||||
|
time(&now);
|
||||||
|
if (t > now)
|
||||||
|
return (NULL);
|
||||||
|
if (t == now)
|
||||||
|
return (xstrdup("0s"));
|
||||||
|
age = now - t;
|
||||||
|
|
||||||
|
d = age / 86400;
|
||||||
|
h = (age % 86400) / 3600;
|
||||||
|
m = (age % 3600) / 60;
|
||||||
|
s = age % 60;
|
||||||
|
|
||||||
|
if (d != 0) {
|
||||||
|
if (h != 0)
|
||||||
|
xsnprintf(out, sizeof out, "%ud%uh", d, h);
|
||||||
|
else
|
||||||
|
xsnprintf(out, sizeof out, "%ud", d);
|
||||||
|
} else if (h != 0) {
|
||||||
|
if (m != 0)
|
||||||
|
xsnprintf(out, sizeof out, "%uh%um", h, m);
|
||||||
|
else
|
||||||
|
xsnprintf(out, sizeof out, "%uh", h);
|
||||||
|
} else if (m != 0) {
|
||||||
|
if (s != 0)
|
||||||
|
xsnprintf(out, sizeof out, "%um%us", m, s);
|
||||||
|
else
|
||||||
|
xsnprintf(out, sizeof out, "%um", m);
|
||||||
|
} else
|
||||||
|
xsnprintf(out, sizeof out, "%us", s);
|
||||||
|
return (xstrdup(out));
|
||||||
|
}
|
||||||
|
|
||||||
/* Find a format entry. */
|
/* Find a format entry. */
|
||||||
static char *
|
static char *
|
||||||
format_find(struct format_tree *ft, const char *key, int modifiers,
|
format_find(struct format_tree *ft, const char *key, int modifiers,
|
||||||
const char *time_format)
|
const char *time_format)
|
||||||
{
|
{
|
||||||
struct format_table_entry *fte;
|
const struct format_table_entry *fte;
|
||||||
void *value;
|
void *value;
|
||||||
struct format_entry *fe, fe_find;
|
struct format_entry *fe, fe_find;
|
||||||
struct environ_entry *envent;
|
struct environ_entry *envent;
|
||||||
@@ -4144,7 +4207,9 @@ found:
|
|||||||
}
|
}
|
||||||
if (t == 0)
|
if (t == 0)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
if (modifiers & FORMAT_PRETTY)
|
if (modifiers & FORMAT_RELATIVE)
|
||||||
|
found = format_relative_time(t);
|
||||||
|
else if (modifiers & FORMAT_PRETTY)
|
||||||
found = format_pretty_time(t, 0);
|
found = format_pretty_time(t, 0);
|
||||||
else {
|
else {
|
||||||
if (time_format != NULL) {
|
if (time_format != NULL) {
|
||||||
@@ -4193,10 +4258,14 @@ found:
|
|||||||
|
|
||||||
/* Check if format has not taken too long. */
|
/* Check if format has not taken too long. */
|
||||||
static int
|
static int
|
||||||
format_check_time(struct format_expand_state *es)
|
format_check_time(struct format_expand_state *es, u_int *check)
|
||||||
{
|
{
|
||||||
uint64_t t = get_timer();
|
uint64_t t;
|
||||||
|
|
||||||
|
if (check != NULL && ++*check % FORMAT_TIME_LOOP_CHECK != 0)
|
||||||
|
return (1);
|
||||||
|
|
||||||
|
t = get_timer();
|
||||||
if (t - es->start_time < FORMAT_TIME_LIMIT)
|
if (t - es->start_time < FORMAT_TIME_LIMIT)
|
||||||
return (1);
|
return (1);
|
||||||
t -= es->start_time;
|
t -= es->start_time;
|
||||||
@@ -4207,21 +4276,24 @@ format_check_time(struct format_expand_state *es)
|
|||||||
|
|
||||||
/* Unescape escaped characters. */
|
/* Unescape escaped characters. */
|
||||||
static char *
|
static char *
|
||||||
format_unescape(struct format_expand_state *es, const char *s)
|
format_unescape(struct format_expand_state *es, const char *s, size_t n)
|
||||||
{
|
{
|
||||||
char *out, *cp;
|
const char *end = s + n;
|
||||||
int brackets = 0;
|
char *out, *cp;
|
||||||
|
int brackets = 0;
|
||||||
|
u_int check = 0;
|
||||||
|
|
||||||
cp = out = xmalloc(strlen(s) + 1);
|
cp = out = xmalloc(n + 1);
|
||||||
for (; *s != '\0'; s++) {
|
for (; s != end; s++) {
|
||||||
if (!format_check_time(es)){
|
if (!format_check_time(es, &check)) {
|
||||||
free(out);
|
free(out);
|
||||||
return (xstrdup(""));
|
return (xstrdup(""));
|
||||||
}
|
}
|
||||||
if (*s == '#' && s[1] == '{')
|
if (*s == '#' && s + 1 != end && s[1] == '{')
|
||||||
brackets++;
|
brackets++;
|
||||||
if (brackets == 0 &&
|
if (brackets == 0 &&
|
||||||
*s == '#' &&
|
*s == '#' &&
|
||||||
|
s + 1 != end &&
|
||||||
strchr(",#{}:", s[1]) != NULL) {
|
strchr(",#{}:", s[1]) != NULL) {
|
||||||
*cp++ = *++s;
|
*cp++ = *++s;
|
||||||
continue;
|
continue;
|
||||||
@@ -4240,10 +4312,11 @@ format_strip(struct format_expand_state *es, const char *s)
|
|||||||
{
|
{
|
||||||
char *out, *cp;
|
char *out, *cp;
|
||||||
int brackets = 0;
|
int brackets = 0;
|
||||||
|
u_int check = 0;
|
||||||
|
|
||||||
cp = out = xmalloc(strlen(s) + 1);
|
cp = out = xmalloc(strlen(s) + 1);
|
||||||
for (; *s != '\0'; s++) {
|
for (; *s != '\0'; s++) {
|
||||||
if (!format_check_time(es)){
|
if (!format_check_time(es, &check)) {
|
||||||
free(out);
|
free(out);
|
||||||
return (xstrdup(""));
|
return (xstrdup(""));
|
||||||
}
|
}
|
||||||
@@ -4267,9 +4340,10 @@ static const char *
|
|||||||
format_skip1(struct format_expand_state *es, const char *s, const char *end)
|
format_skip1(struct format_expand_state *es, const char *s, const char *end)
|
||||||
{
|
{
|
||||||
int brackets = 0;
|
int brackets = 0;
|
||||||
|
u_int check = 0;
|
||||||
|
|
||||||
for (; *s != '\0'; s++) {
|
for (; *s != '\0'; s++) {
|
||||||
if (es != NULL && !format_check_time(es))
|
if (es != NULL && !format_check_time(es, &check))
|
||||||
return (NULL);
|
return (NULL);
|
||||||
if (*s == '#' && s[1] == '{')
|
if (*s == '#' && s[1] == '{')
|
||||||
brackets++;
|
brackets++;
|
||||||
@@ -4379,7 +4453,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Modifiers are a ; separated list of the forms:
|
* Modifiers are a ; separated list of the forms:
|
||||||
* l,m,C,a,b,c,d,n,t,w,q,E,T,S,W,P,R,<,>
|
* l,m,C,a,b,c,d,I,n,t,w,q,E,T,S,W,P,R,<,>
|
||||||
* =a
|
* =a
|
||||||
* =/a
|
* =/a
|
||||||
* =/a/
|
* =/a/
|
||||||
@@ -4420,7 +4494,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Now try single character with arguments. */
|
/* Now try single character with arguments. */
|
||||||
if (strchr("mCLNPSst=pReqW", cp[0]) == NULL)
|
if (strchr("ImCLNPSst=pReqW", cp[0]) == NULL)
|
||||||
break;
|
break;
|
||||||
c = cp[0];
|
c = cp[0];
|
||||||
|
|
||||||
@@ -4440,7 +4514,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
argv = xcalloc(1, sizeof *argv);
|
argv = xcalloc(1, sizeof *argv);
|
||||||
value = xstrndup(cp + 1, end - (cp + 1));
|
value = format_unescape(es, cp + 1, end - (cp + 1));
|
||||||
argv[0] = format_expand1(es, value);
|
argv[0] = format_expand1(es, value);
|
||||||
free(value);
|
free(value);
|
||||||
argc = 1;
|
argc = 1;
|
||||||
@@ -4464,7 +4538,7 @@ format_build_modifiers(struct format_expand_state *es, const char **s,
|
|||||||
cp++;
|
cp++;
|
||||||
|
|
||||||
argv = xreallocarray(argv, argc + 1, sizeof *argv);
|
argv = xreallocarray(argv, argc + 1, sizeof *argv);
|
||||||
value = xstrndup(cp, end - cp);
|
value = format_unescape(es, cp, end - cp);
|
||||||
argv[argc++] = format_expand1(es, value);
|
argv[argc++] = format_expand1(es, value);
|
||||||
free(value);
|
free(value);
|
||||||
|
|
||||||
@@ -4627,17 +4701,19 @@ format_loop_sessions(struct format_expand_state *es, const char *fmt)
|
|||||||
struct format_tree *nft;
|
struct format_tree *nft;
|
||||||
struct format_expand_state next;
|
struct format_expand_state next;
|
||||||
char *all, *active, *use, *expanded, *value;
|
char *all, *active, *use, *expanded, *value;
|
||||||
size_t valuelen;
|
struct evbuffer *buffer;
|
||||||
|
size_t size;
|
||||||
struct session *s, **l;
|
struct session *s, **l;
|
||||||
int i, n, last = 0;
|
int i, n;
|
||||||
|
|
||||||
if (format_choose(es, fmt, &all, &active, 0) != 0) {
|
if (format_choose(es, fmt, &all, &active, 0) != 0) {
|
||||||
all = xstrdup(fmt);
|
all = xstrdup(fmt);
|
||||||
active = NULL;
|
active = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
value = xcalloc(1, 1);
|
buffer = evbuffer_new();
|
||||||
valuelen = 1;
|
if (buffer == NULL)
|
||||||
|
fatalx("out of memory");
|
||||||
|
|
||||||
l = sort_get_sessions(&n, sc);
|
l = sort_get_sessions(&n, sc);
|
||||||
for (i = 0; i < n; i++) {
|
for (i = 0; i < n; i++) {
|
||||||
@@ -4649,25 +4725,27 @@ format_loop_sessions(struct format_expand_state *es, const char *fmt)
|
|||||||
use = active;
|
use = active;
|
||||||
else
|
else
|
||||||
use = all;
|
use = all;
|
||||||
if (i == n - 1)
|
nft = format_create(c, item, FORMAT_NONE, ft->flags);
|
||||||
last = FORMAT_LAST;
|
format_add(nft, "loop_index", "%d", i);
|
||||||
nft = format_create(c, item, FORMAT_NONE, ft->flags|last);
|
format_add(nft, "loop_last_flag", "%d", i == n - 1);
|
||||||
format_defaults(nft, ft->c, s, NULL, NULL);
|
format_defaults(nft, ft->c, s, NULL, NULL);
|
||||||
format_copy_state(&next, es, 0);
|
format_copy_state(&next, es, 0);
|
||||||
next.ft = nft;
|
next.ft = nft;
|
||||||
expanded = format_expand1(&next, use);
|
expanded = format_expand1(&next, use);
|
||||||
format_free(next.ft);
|
format_free(next.ft);
|
||||||
|
|
||||||
valuelen += strlen(expanded);
|
evbuffer_add(buffer, expanded, strlen(expanded));
|
||||||
value = xrealloc(value, valuelen);
|
|
||||||
|
|
||||||
strlcat(value, expanded, valuelen);
|
|
||||||
free(expanded);
|
free(expanded);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(active);
|
free(active);
|
||||||
free(all);
|
free(all);
|
||||||
|
|
||||||
|
if ((size = EVBUFFER_LENGTH(buffer)) != 0)
|
||||||
|
value = xmemdup(EVBUFFER_DATA(buffer), size);
|
||||||
|
else
|
||||||
|
value = xstrdup("");
|
||||||
|
evbuffer_free(buffer);
|
||||||
return (value);
|
return (value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4737,10 +4815,11 @@ format_loop_windows(struct format_expand_state *es, const char *fmt)
|
|||||||
struct format_tree *nft;
|
struct format_tree *nft;
|
||||||
struct format_expand_state next;
|
struct format_expand_state next;
|
||||||
char *all, *active, *use, *expanded, *value;
|
char *all, *active, *use, *expanded, *value;
|
||||||
size_t valuelen;
|
struct evbuffer *buffer;
|
||||||
|
size_t size;
|
||||||
struct winlink *wl, **l;
|
struct winlink *wl, **l;
|
||||||
struct window *w;
|
struct window *w;
|
||||||
int i, n, last = 0;
|
int i, n;
|
||||||
|
|
||||||
if (ft->s == NULL) {
|
if (ft->s == NULL) {
|
||||||
format_log(es, "window loop but no session");
|
format_log(es, "window loop but no session");
|
||||||
@@ -4752,8 +4831,9 @@ format_loop_windows(struct format_expand_state *es, const char *fmt)
|
|||||||
active = NULL;
|
active = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
value = xcalloc(1, 1);
|
buffer = evbuffer_new();
|
||||||
valuelen = 1;
|
if (buffer == NULL)
|
||||||
|
fatalx("out of memory");
|
||||||
|
|
||||||
l = sort_get_winlinks_session(ft->s, &n, sc);
|
l = sort_get_winlinks_session(ft->s, &n, sc);
|
||||||
for (i = 0; i < n; i++) {
|
for (i = 0; i < n; i++) {
|
||||||
@@ -4764,10 +4844,10 @@ format_loop_windows(struct format_expand_state *es, const char *fmt)
|
|||||||
use = active;
|
use = active;
|
||||||
else
|
else
|
||||||
use = all;
|
use = all;
|
||||||
if (i == n - 1)
|
|
||||||
last = FORMAT_LAST;
|
|
||||||
nft = format_create(c, item, FORMAT_WINDOW|w->id,
|
nft = format_create(c, item, FORMAT_WINDOW|w->id,
|
||||||
ft->flags|last);
|
ft->flags);
|
||||||
|
format_add(nft, "loop_index", "%d", i);
|
||||||
|
format_add(nft, "loop_last_flag", "%d", i == n - 1);
|
||||||
format_defaults(nft, ft->c, ft->s, wl, NULL);
|
format_defaults(nft, ft->c, ft->s, wl, NULL);
|
||||||
|
|
||||||
/* Add neighbor window data to the format tree. */
|
/* Add neighbor window data to the format tree. */
|
||||||
@@ -4785,16 +4865,18 @@ format_loop_windows(struct format_expand_state *es, const char *fmt)
|
|||||||
expanded = format_expand1(&next, use);
|
expanded = format_expand1(&next, use);
|
||||||
format_free(nft);
|
format_free(nft);
|
||||||
|
|
||||||
valuelen += strlen(expanded);
|
evbuffer_add(buffer, expanded, strlen(expanded));
|
||||||
value = xrealloc(value, valuelen);
|
|
||||||
|
|
||||||
strlcat(value, expanded, valuelen);
|
|
||||||
free(expanded);
|
free(expanded);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(active);
|
free(active);
|
||||||
free(all);
|
free(all);
|
||||||
|
|
||||||
|
if ((size = EVBUFFER_LENGTH(buffer)) != 0)
|
||||||
|
value = xmemdup(EVBUFFER_DATA(buffer), size);
|
||||||
|
else
|
||||||
|
value = xstrdup("");
|
||||||
|
evbuffer_free(buffer);
|
||||||
return (value);
|
return (value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4809,9 +4891,10 @@ format_loop_panes(struct format_expand_state *es, const char *fmt)
|
|||||||
struct format_tree *nft;
|
struct format_tree *nft;
|
||||||
struct format_expand_state next;
|
struct format_expand_state next;
|
||||||
char *all, *active, *use, *expanded, *value;
|
char *all, *active, *use, *expanded, *value;
|
||||||
size_t valuelen;
|
struct evbuffer *buffer;
|
||||||
|
size_t size;
|
||||||
struct window_pane *wp, **l;
|
struct window_pane *wp, **l;
|
||||||
int i, n, last = 0;
|
int i, n;
|
||||||
|
|
||||||
if (ft->w == NULL) {
|
if (ft->w == NULL) {
|
||||||
format_log(es, "pane loop but no window");
|
format_log(es, "pane loop but no window");
|
||||||
@@ -4823,8 +4906,9 @@ format_loop_panes(struct format_expand_state *es, const char *fmt)
|
|||||||
active = NULL;
|
active = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
value = xcalloc(1, 1);
|
buffer = evbuffer_new();
|
||||||
valuelen = 1;
|
if (buffer == NULL)
|
||||||
|
fatalx("out of memory");
|
||||||
|
|
||||||
l = sort_get_panes_window(ft->w, &n, sc);
|
l = sort_get_panes_window(ft->w, &n, sc);
|
||||||
for (i = 0; i < n; i++) {
|
for (i = 0; i < n; i++) {
|
||||||
@@ -4834,26 +4918,28 @@ format_loop_panes(struct format_expand_state *es, const char *fmt)
|
|||||||
use = active;
|
use = active;
|
||||||
else
|
else
|
||||||
use = all;
|
use = all;
|
||||||
if (i == n - 1)
|
|
||||||
last = FORMAT_LAST;
|
|
||||||
nft = format_create(c, item, FORMAT_PANE|wp->id,
|
nft = format_create(c, item, FORMAT_PANE|wp->id,
|
||||||
ft->flags|last);
|
ft->flags);
|
||||||
|
format_add(nft, "loop_index", "%d", i);
|
||||||
|
format_add(nft, "loop_last_flag", "%d", i == n - 1);
|
||||||
format_defaults(nft, ft->c, ft->s, ft->wl, wp);
|
format_defaults(nft, ft->c, ft->s, ft->wl, wp);
|
||||||
format_copy_state(&next, es, 0);
|
format_copy_state(&next, es, 0);
|
||||||
next.ft = nft;
|
next.ft = nft;
|
||||||
expanded = format_expand1(&next, use);
|
expanded = format_expand1(&next, use);
|
||||||
format_free(nft);
|
format_free(nft);
|
||||||
|
|
||||||
valuelen += strlen(expanded);
|
evbuffer_add(buffer, expanded, strlen(expanded));
|
||||||
value = xrealloc(value, valuelen);
|
|
||||||
|
|
||||||
strlcat(value, expanded, valuelen);
|
|
||||||
free(expanded);
|
free(expanded);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(active);
|
free(active);
|
||||||
free(all);
|
free(all);
|
||||||
|
|
||||||
|
if ((size = EVBUFFER_LENGTH(buffer)) != 0)
|
||||||
|
value = xmemdup(EVBUFFER_DATA(buffer), size);
|
||||||
|
else
|
||||||
|
value = xstrdup("");
|
||||||
|
evbuffer_free(buffer);
|
||||||
return (value);
|
return (value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4868,32 +4954,36 @@ format_loop_clients(struct format_expand_state *es, const char *fmt)
|
|||||||
struct format_tree *nft;
|
struct format_tree *nft;
|
||||||
struct format_expand_state next;
|
struct format_expand_state next;
|
||||||
char *expanded, *value;
|
char *expanded, *value;
|
||||||
size_t valuelen;
|
struct evbuffer *buffer;
|
||||||
int i, n, last = 0;
|
size_t size;
|
||||||
|
int i, n;
|
||||||
|
|
||||||
value = xcalloc(1, 1);
|
buffer = evbuffer_new();
|
||||||
valuelen = 1;
|
if (buffer == NULL)
|
||||||
|
fatalx("out of memory");
|
||||||
|
|
||||||
l = sort_get_clients(&n, sc);
|
l = sort_get_clients(&n, sc);
|
||||||
for (i = 0; i < n; i++) {
|
for (i = 0; i < n; i++) {
|
||||||
c = l[i];
|
c = l[i];
|
||||||
format_log(es, "client loop: %s", c->name);
|
format_log(es, "client loop: %s", c->name);
|
||||||
if (i == n - 1)
|
nft = format_create(c, item, 0, ft->flags);
|
||||||
last = FORMAT_LAST;
|
format_add(nft, "loop_index", "%d", i);
|
||||||
nft = format_create(c, item, 0, ft->flags|last);
|
format_add(nft, "loop_last_flag", "%d", i == n - 1);
|
||||||
format_defaults(nft, c, ft->s, ft->wl, ft->wp);
|
format_defaults(nft, c, ft->s, ft->wl, ft->wp);
|
||||||
format_copy_state(&next, es, 0);
|
format_copy_state(&next, es, 0);
|
||||||
next.ft = nft;
|
next.ft = nft;
|
||||||
expanded = format_expand1(&next, fmt);
|
expanded = format_expand1(&next, fmt);
|
||||||
format_free(nft);
|
format_free(nft);
|
||||||
|
|
||||||
valuelen += strlen(expanded);
|
evbuffer_add(buffer, expanded, strlen(expanded));
|
||||||
value = xrealloc(value, valuelen);
|
|
||||||
|
|
||||||
strlcat(value, expanded, valuelen);
|
|
||||||
free(expanded);
|
free(expanded);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((size = EVBUFFER_LENGTH(buffer)) != 0)
|
||||||
|
value = xmemdup(EVBUFFER_DATA(buffer), size);
|
||||||
|
else
|
||||||
|
value = xstrdup("");
|
||||||
|
evbuffer_free(buffer);
|
||||||
return (value);
|
return (value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5059,8 +5149,9 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
|
|||||||
struct format_modifier *list, *cmp = NULL, *search = NULL;
|
struct format_modifier *list, *cmp = NULL, *search = NULL;
|
||||||
struct format_modifier **sub = NULL, *mexp = NULL, *fm;
|
struct format_modifier **sub = NULL, *mexp = NULL, *fm;
|
||||||
struct format_modifier *bool_op_n = NULL;
|
struct format_modifier *bool_op_n = NULL;
|
||||||
u_int i, count, nsub = 0, nrep;
|
u_int i, count, nsub = 0, nrep, check = 0;
|
||||||
struct format_expand_state next;
|
struct format_expand_state next;
|
||||||
|
struct environ_entry *envent;
|
||||||
|
|
||||||
/* Set sorting defaults. */
|
/* Set sorting defaults. */
|
||||||
sc->order = SORT_ORDER;
|
sc->order = SORT_ORDER;
|
||||||
@@ -5143,16 +5234,29 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
|
|||||||
case 'n':
|
case 'n':
|
||||||
modifiers |= FORMAT_LENGTH;
|
modifiers |= FORMAT_LENGTH;
|
||||||
break;
|
break;
|
||||||
|
case 'I':
|
||||||
|
if (fm->argc < 1)
|
||||||
|
break;
|
||||||
|
if (strchr(fm->argv[0], 'f') != NULL)
|
||||||
|
modifiers |= FORMAT_CLIENT_TERMFEAT;
|
||||||
|
if (strchr(fm->argv[0], 'c') != NULL)
|
||||||
|
modifiers |= FORMAT_CLIENT_TERMCAP;
|
||||||
|
if (strchr(fm->argv[0], 'e') != NULL)
|
||||||
|
modifiers |= FORMAT_CLIENT_ENVIRON;
|
||||||
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
modifiers |= FORMAT_TIMESTRING;
|
modifiers |= FORMAT_TIMESTRING;
|
||||||
if (fm->argc < 1)
|
if (fm->argc < 1)
|
||||||
break;
|
break;
|
||||||
if (strchr(fm->argv[0], 'p') != NULL)
|
if (strchr(fm->argv[0], 'p') != NULL)
|
||||||
modifiers |= FORMAT_PRETTY;
|
modifiers |= FORMAT_PRETTY;
|
||||||
|
else if (strchr(fm->argv[0], 'r') != NULL)
|
||||||
|
modifiers |= FORMAT_RELATIVE;
|
||||||
else if (fm->argc >= 2 &&
|
else if (fm->argc >= 2 &&
|
||||||
strchr(fm->argv[0], 'f') != NULL) {
|
strchr(fm->argv[0], 'f') != NULL) {
|
||||||
free(time_format);
|
free(time_format);
|
||||||
time_format = format_strip(es, fm->argv[1]);
|
time_format = format_strip(es,
|
||||||
|
fm->argv[1]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'q':
|
case 'q':
|
||||||
@@ -5267,10 +5371,42 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Look up client capability, feature or environment. */
|
||||||
|
if ((modifiers & FORMAT_CLIENT_TERMCAP) ||
|
||||||
|
(modifiers & FORMAT_CLIENT_TERMFEAT) ||
|
||||||
|
(modifiers & FORMAT_CLIENT_ENVIRON)) {
|
||||||
|
if (ft->c == NULL ||
|
||||||
|
ft->c->tty.term == NULL ||
|
||||||
|
ft->c->flags & CLIENT_UNATTACHEDFLAGS) {
|
||||||
|
value = xstrdup("");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (modifiers & FORMAT_CLIENT_TERMCAP) {
|
||||||
|
if (tty_term_has_name(ft->c->tty.term, copy))
|
||||||
|
value = xstrdup("1");
|
||||||
|
else
|
||||||
|
value = xstrdup("0");
|
||||||
|
}
|
||||||
|
if (modifiers & FORMAT_CLIENT_TERMFEAT) {
|
||||||
|
if (tty_feature_present(ft->c->tty.term, copy))
|
||||||
|
value = xstrdup("1");
|
||||||
|
else
|
||||||
|
value = xstrdup("0");
|
||||||
|
}
|
||||||
|
if (modifiers & FORMAT_CLIENT_ENVIRON) {
|
||||||
|
envent = environ_find(ft->c->environ, copy);
|
||||||
|
if (envent != NULL && envent->value != NULL)
|
||||||
|
value = xstrdup(envent->value);
|
||||||
|
else
|
||||||
|
value = xstrdup("");
|
||||||
|
}
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
/* Is this a literal string? */
|
/* Is this a literal string? */
|
||||||
if (modifiers & FORMAT_LITERAL) {
|
if (modifiers & FORMAT_LITERAL) {
|
||||||
format_log(es, "literal string is '%s'", copy);
|
format_log(es, "literal string is '%s'", copy);
|
||||||
value = format_unescape(es, copy);
|
value = format_unescape(es, copy, strlen(copy));
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5346,7 +5482,7 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
|
|||||||
else {
|
else {
|
||||||
value = xstrdup("");
|
value = xstrdup("");
|
||||||
for (i = 0; i < nrep; i++) {
|
for (i = 0; i < nrep; i++) {
|
||||||
if (!format_check_time(es)) {
|
if (!format_check_time(es, &check)) {
|
||||||
free(right);
|
free(right);
|
||||||
free(left);
|
free(left);
|
||||||
free(value);
|
free(value);
|
||||||
@@ -5626,7 +5762,7 @@ format_expand1(struct format_expand_state *es, const char *fmt)
|
|||||||
int ch, brackets;
|
int ch, brackets;
|
||||||
char expanded[8192];
|
char expanded[8192];
|
||||||
|
|
||||||
if (fmt == NULL || *fmt == '\0' || !format_check_time(es))
|
if (fmt == NULL || *fmt == '\0' || !format_check_time(es, NULL))
|
||||||
return (xstrdup(""));
|
return (xstrdup(""));
|
||||||
|
|
||||||
if (es->loop == FORMAT_LOOP_LIMIT) {
|
if (es->loop == FORMAT_LOOP_LIMIT) {
|
||||||
|
|||||||
11
grid.c
11
grid.c
@@ -292,7 +292,7 @@ grid_free_line(struct grid *gd, u_int py)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Free several lines. */
|
/* Free several lines. */
|
||||||
static void
|
void
|
||||||
grid_free_lines(struct grid *gd, u_int py, u_int ny)
|
grid_free_lines(struct grid *gd, u_int py, u_int ny)
|
||||||
{
|
{
|
||||||
u_int yy;
|
u_int yy;
|
||||||
@@ -320,6 +320,10 @@ grid_create(u_int sx, u_int sy, u_int hlimit)
|
|||||||
gd->hsize = 0;
|
gd->hsize = 0;
|
||||||
gd->hlimit = hlimit;
|
gd->hlimit = hlimit;
|
||||||
|
|
||||||
|
gd->scroll_added = 0;
|
||||||
|
gd->scroll_collected = 0;
|
||||||
|
gd->scroll_generation = 0;
|
||||||
|
|
||||||
if (gd->sy != 0)
|
if (gd->sy != 0)
|
||||||
gd->linedata = xcalloc(gd->sy, sizeof *gd->linedata);
|
gd->linedata = xcalloc(gd->sy, sizeof *gd->linedata);
|
||||||
else
|
else
|
||||||
@@ -405,6 +409,7 @@ grid_collect_history(struct grid *gd, int all)
|
|||||||
grid_trim_history(gd, ny);
|
grid_trim_history(gd, ny);
|
||||||
|
|
||||||
gd->hsize -= ny;
|
gd->hsize -= ny;
|
||||||
|
gd->scroll_collected += ny;
|
||||||
if (gd->hscrolled > gd->hsize)
|
if (gd->hscrolled > gd->hsize)
|
||||||
gd->hscrolled = gd->hsize;
|
gd->hscrolled = gd->hsize;
|
||||||
}
|
}
|
||||||
@@ -442,6 +447,7 @@ grid_scroll_history(struct grid *gd, u_int bg)
|
|||||||
grid_compact_line(&gd->linedata[gd->hsize]);
|
grid_compact_line(&gd->linedata[gd->hsize]);
|
||||||
gd->linedata[gd->hsize].time = current_time;
|
gd->linedata[gd->hsize].time = current_time;
|
||||||
gd->hsize++;
|
gd->hsize++;
|
||||||
|
gd->scroll_added++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear the history. */
|
/* Clear the history. */
|
||||||
@@ -452,6 +458,7 @@ grid_clear_history(struct grid *gd)
|
|||||||
|
|
||||||
gd->hscrolled = 0;
|
gd->hscrolled = 0;
|
||||||
gd->hsize = 0;
|
gd->hsize = 0;
|
||||||
|
gd->scroll_generation++;
|
||||||
|
|
||||||
gd->linedata = xreallocarray(gd->linedata, gd->sy,
|
gd->linedata = xreallocarray(gd->linedata, gd->sy,
|
||||||
sizeof *gd->linedata);
|
sizeof *gd->linedata);
|
||||||
@@ -489,6 +496,7 @@ grid_scroll_history_region(struct grid *gd, u_int upper, u_int lower, u_int bg)
|
|||||||
/* Move the history offset down over the line. */
|
/* Move the history offset down over the line. */
|
||||||
gd->hscrolled++;
|
gd->hscrolled++;
|
||||||
gd->hsize++;
|
gd->hsize++;
|
||||||
|
gd->scroll_added++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Expand line to fit to cell. */
|
/* Expand line to fit to cell. */
|
||||||
@@ -1510,6 +1518,7 @@ grid_reflow(struct grid *gd, u_int sx)
|
|||||||
free(gd->linedata);
|
free(gd->linedata);
|
||||||
gd->linedata = target->linedata;
|
gd->linedata = target->linedata;
|
||||||
free(target);
|
free(target);
|
||||||
|
gd->scroll_generation++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Convert to position based on wrapped lines. */
|
/* Convert to position based on wrapped lines. */
|
||||||
|
|||||||
@@ -450,11 +450,11 @@ sixel_scale(struct sixel_image *si, u_int xpixel, u_int ypixel, u_int ox,
|
|||||||
|
|
||||||
new->set_ra = si->set_ra;
|
new->set_ra = si->set_ra;
|
||||||
/* subtract offset */
|
/* subtract offset */
|
||||||
new->ra_x = new->ra_x > pox ? new->ra_x - pox : 0;
|
new->ra_x = si->ra_x > pox ? si->ra_x - pox : 0;
|
||||||
new->ra_y = new->ra_y > poy ? new->ra_y - poy : 0;
|
new->ra_y = si->ra_y > poy ? si->ra_y - poy : 0;
|
||||||
/* clamp to size */
|
/* clamp to size */
|
||||||
new->ra_x = si->ra_x < psx ? si->ra_x : psx;
|
new->ra_x = new->ra_x < psx ? new->ra_x : psx;
|
||||||
new->ra_y = si->ra_y < psy ? si->ra_y : psy;
|
new->ra_y = new->ra_y < psy ? new->ra_y : psy;
|
||||||
/* resize */
|
/* resize */
|
||||||
new->ra_x = new->ra_x * xpixel / si->xpixel;
|
new->ra_x = new->ra_x * xpixel / si->xpixel;
|
||||||
new->ra_y = new->ra_y * ypixel / si->ypixel;
|
new->ra_y = new->ra_y * ypixel / si->ypixel;
|
||||||
|
|||||||
@@ -483,7 +483,7 @@ input_key_vt10x(struct bufferevent *bev, key_code key)
|
|||||||
{
|
{
|
||||||
struct utf8_data ud;
|
struct utf8_data ud;
|
||||||
key_code onlykey;
|
key_code onlykey;
|
||||||
char *p;
|
const char *p;
|
||||||
static const char *standard_map[2] = {
|
static const char *standard_map[2] = {
|
||||||
"1!9(0)=+;:'\",<.>/-8? 2",
|
"1!9(0)=+;:'\",<.>/-8? 2",
|
||||||
"119900=+;;'',,..\x1f\x1f\x7f\x7f\0\0",
|
"119900=+;;'',,..\x1f\x1f\x7f\x7f\0\0",
|
||||||
@@ -806,7 +806,7 @@ input_key_mouse(struct window_pane *wp, struct mouse_event *m)
|
|||||||
return;
|
return;
|
||||||
if (cmd_mouse_at(wp, m, &x, &y, 0) != 0)
|
if (cmd_mouse_at(wp, m, &x, &y, 0) != 0)
|
||||||
return;
|
return;
|
||||||
if (!window_pane_visible(wp))
|
if (!window_pane_is_visible(wp))
|
||||||
return;
|
return;
|
||||||
if (!input_key_get_mouse(s, m, x, y, &buf, &len))
|
if (!input_key_get_mouse(s, m, x, y, &buf, &len))
|
||||||
return;
|
return;
|
||||||
|
|||||||
28
input.c
28
input.c
@@ -1365,7 +1365,7 @@ input_esc_dispatch(struct input_ctx *ictx)
|
|||||||
{
|
{
|
||||||
struct screen_write_ctx *sctx = &ictx->ctx;
|
struct screen_write_ctx *sctx = &ictx->ctx;
|
||||||
struct screen *s = sctx->s;
|
struct screen *s = sctx->s;
|
||||||
struct input_table_entry *entry;
|
const struct input_table_entry *entry;
|
||||||
|
|
||||||
if (ictx->flags & INPUT_DISCARD)
|
if (ictx->flags & INPUT_DISCARD)
|
||||||
return (0);
|
return (0);
|
||||||
@@ -1439,12 +1439,12 @@ input_esc_dispatch(struct input_ctx *ictx)
|
|||||||
static int
|
static int
|
||||||
input_csi_dispatch(struct input_ctx *ictx)
|
input_csi_dispatch(struct input_ctx *ictx)
|
||||||
{
|
{
|
||||||
struct screen_write_ctx *sctx = &ictx->ctx;
|
struct screen_write_ctx *sctx = &ictx->ctx;
|
||||||
struct screen *s = sctx->s;
|
struct screen *s = sctx->s;
|
||||||
struct input_table_entry *entry;
|
const struct input_table_entry *entry;
|
||||||
struct options *oo;
|
struct options *oo;
|
||||||
int i, n, m, ek, set, p;
|
int i, n, m, ek, set, p;
|
||||||
u_int cx, bg = ictx->cell.cell.bg;
|
u_int cx, bg = ictx->cell.cell.bg;
|
||||||
|
|
||||||
if (ictx->flags & INPUT_DISCARD)
|
if (ictx->flags & INPUT_DISCARD)
|
||||||
return (0);
|
return (0);
|
||||||
@@ -2701,7 +2701,7 @@ input_exit_osc(struct input_ctx *ictx)
|
|||||||
case 2:
|
case 2:
|
||||||
if (wp != NULL &&
|
if (wp != NULL &&
|
||||||
options_get_number(wp->options, "allow-set-title") &&
|
options_get_number(wp->options, "allow-set-title") &&
|
||||||
screen_set_title(sctx->s, p)) {
|
screen_set_title(sctx->s, p, 1)) {
|
||||||
notify_pane("pane-title-changed", wp);
|
notify_pane("pane-title-changed", wp);
|
||||||
server_redraw_window_borders(wp->window);
|
server_redraw_window_borders(wp->window);
|
||||||
server_status_window(wp->window);
|
server_status_window(wp->window);
|
||||||
@@ -2711,7 +2711,7 @@ input_exit_osc(struct input_ctx *ictx)
|
|||||||
input_osc_4(ictx, p);
|
input_osc_4(ictx, p);
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
if (screen_set_path(sctx->s, p) && wp != NULL) {
|
if (wp != NULL && screen_set_path(sctx->s, p, 1)) {
|
||||||
server_redraw_window_borders(wp->window);
|
server_redraw_window_borders(wp->window);
|
||||||
server_status_window(wp->window);
|
server_status_window(wp->window);
|
||||||
}
|
}
|
||||||
@@ -2779,7 +2779,7 @@ input_exit_apc(struct input_ctx *ictx)
|
|||||||
|
|
||||||
if (wp != NULL &&
|
if (wp != NULL &&
|
||||||
options_get_number(wp->options, "allow-set-title") &&
|
options_get_number(wp->options, "allow-set-title") &&
|
||||||
screen_set_title(sctx->s, ictx->input_buf)) {
|
screen_set_title(sctx->s, ictx->input_buf, 1)) {
|
||||||
notify_pane("pane-title-changed", wp);
|
notify_pane("pane-title-changed", wp);
|
||||||
server_redraw_window_borders(wp->window);
|
server_redraw_window_borders(wp->window);
|
||||||
server_status_window(wp->window);
|
server_status_window(wp->window);
|
||||||
@@ -2822,10 +2822,10 @@ input_exit_rename(struct input_ctx *ictx)
|
|||||||
if (o != NULL)
|
if (o != NULL)
|
||||||
options_remove_or_default(o, -1, NULL);
|
options_remove_or_default(o, -1, NULL);
|
||||||
if (!options_get_number(w->options, "automatic-rename"))
|
if (!options_get_number(w->options, "automatic-rename"))
|
||||||
window_set_name(w, "");
|
window_set_name(w, "", WINDOW_NAME_FORBID_EXT);
|
||||||
} else {
|
} else {
|
||||||
options_set_number(w->options, "automatic-rename", 0);
|
options_set_number(w->options, "automatic-rename", 0);
|
||||||
window_set_name(w, ictx->input_buf);
|
window_set_name(w, ictx->input_buf, WINDOW_NAME_FORBID_EXT);
|
||||||
}
|
}
|
||||||
server_redraw_window_borders(w);
|
server_redraw_window_borders(w);
|
||||||
server_status_window(w);
|
server_status_window(w);
|
||||||
@@ -3055,7 +3055,7 @@ input_osc_10(struct input_ctx *ictx, const char *p)
|
|||||||
return;
|
return;
|
||||||
c = window_pane_get_fg_control_client(wp);
|
c = window_pane_get_fg_control_client(wp);
|
||||||
if (c == -1) {
|
if (c == -1) {
|
||||||
tty_default_colours(&defaults, wp);
|
tty_default_colours(&defaults, wp, NULL);
|
||||||
if (COLOUR_DEFAULT(defaults.fg))
|
if (COLOUR_DEFAULT(defaults.fg))
|
||||||
c = window_pane_get_fg(wp);
|
c = window_pane_get_fg(wp);
|
||||||
else
|
else
|
||||||
@@ -3225,7 +3225,7 @@ static int
|
|||||||
input_osc_52_parse(struct input_ctx *ictx, const char *p, u_char **out,
|
input_osc_52_parse(struct input_ctx *ictx, const char *p, u_char **out,
|
||||||
int *outlen, char *clip)
|
int *outlen, char *clip)
|
||||||
{
|
{
|
||||||
char *end;
|
const char *end;
|
||||||
size_t len;
|
size_t len;
|
||||||
const char *allow = "cpqs01234567";
|
const char *allow = "cpqs01234567";
|
||||||
u_int i, j = 0;
|
u_int i, j = 0;
|
||||||
|
|||||||
@@ -25,11 +25,10 @@
|
|||||||
#include "tmux.h"
|
#include "tmux.h"
|
||||||
|
|
||||||
#define DEFAULT_SESSION_MENU \
|
#define DEFAULT_SESSION_MENU \
|
||||||
" 'Next' 'n' {switch-client -n}" \
|
" #{S/t:#{?#{&&:#{<:#{loop_index},6},#{!:#{session_active}}},'Switch To #[underscore]#{session_name}' '' {switch-client -t=#{session_id}#} ,}}" \
|
||||||
" 'Previous' 'p' {switch-client -p}" \
|
|
||||||
" ''" \
|
" ''" \
|
||||||
" 'Renumber' 'N' {move-window -r}" \
|
" 'Renumber' 'N' {move-window -r}" \
|
||||||
" 'Rename' 'r' {command-prompt -I \"#S\" {rename-session -- '%%'}}" \
|
" 'Rename' 'r' {command-prompt -I '#S' {rename-session -- '%%'}}" \
|
||||||
" 'Detach' 'd' {detach-client}" \
|
" 'Detach' 'd' {detach-client}" \
|
||||||
" ''" \
|
" ''" \
|
||||||
" 'New Session' 's' {new-session}" \
|
" 'New Session' 's' {new-session}" \
|
||||||
@@ -65,7 +64,7 @@
|
|||||||
" ''" \
|
" ''" \
|
||||||
" '#{?#{&&:#{!:#{pane_floating_flag}},#{>:#{window_panes},1}},Swap Up,}' 'u' {swap-pane -U}" \
|
" '#{?#{&&:#{!:#{pane_floating_flag}},#{>:#{window_panes},1}},Swap Up,}' 'u' {swap-pane -U}" \
|
||||||
" '#{?#{&&:#{!:#{pane_floating_flag}},#{>:#{window_panes},1}},Swap Down,}' 'd' {swap-pane -D}" \
|
" '#{?#{&&:#{!:#{pane_floating_flag}},#{>:#{window_panes},1}},Swap Down,}' 'd' {swap-pane -D}" \
|
||||||
" '#{?pane_marked_set,,-}Swap Marked' 's' {swap-pane}" \
|
" '#{?#{!:#{pane_floating_flag}},#{?pane_marked_set,,-}Swap Marked,}' 's' {swap-pane}" \
|
||||||
" ''" \
|
" ''" \
|
||||||
" 'Kill' 'X' {kill-pane}" \
|
" 'Kill' 'X' {kill-pane}" \
|
||||||
" 'Respawn' 'R' {respawn-pane -k}" \
|
" 'Respawn' 'R' {respawn-pane -k}" \
|
||||||
@@ -406,8 +405,10 @@ key_bindings_init(void)
|
|||||||
"bind -N 'Choose a window from a list' w { choose-tree -Zw }",
|
"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 '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 'Zoom the active pane' z { resize-pane -Z }",
|
||||||
"bind -N 'Swap the active pane with the pane above' '{' { swap-pane -U }",
|
"bind -N 'Move pane to top-left corner' '{' { resize-pane -x50% -y50%; move-pane -P top-left }",
|
||||||
"bind -N 'Swap the active pane with the pane below' '}' { swap-pane -D }",
|
"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 'Show messages' '~' { show-messages }",
|
"bind -N 'Show messages' '~' { show-messages }",
|
||||||
"bind -N 'Enter copy mode and scroll up' PPage { copy-mode -u }",
|
"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 }",
|
"bind -N 'Select the pane above the active pane' -r Up { select-pane -U }",
|
||||||
@@ -429,13 +430,13 @@ key_bindings_init(void)
|
|||||||
"bind -N 'Move the visible part of the window left' -r S-Left { refresh-client -L 10 }",
|
"bind -N 'Move the visible part of the window left' -r S-Left { refresh-client -L 10 }",
|
||||||
"bind -N 'Move the visible part of the window right' -r S-Right { refresh-client -R 10 }",
|
"bind -N 'Move the visible part of the window right' -r S-Right { refresh-client -R 10 }",
|
||||||
"bind -N 'Reset so the visible part of the window follows the cursor' -r DC { refresh-client -c }",
|
"bind -N 'Reset so the visible part of the window follows the cursor' -r DC { refresh-client -c }",
|
||||||
"bind -N 'Resize the pane up by 5' -r M-Up { resize-pane -U 5 }",
|
"bind -N 'Resize the pane up by 5' -r M-Up if -F '#{?floating_pane_flag}' { resizep -D-5 } { resize-pane -U 5 }",
|
||||||
"bind -N 'Resize the pane down by 5' -r M-Down { resize-pane -D 5 }",
|
"bind -N 'Resize the pane down by 5' -r M-Down { resize-pane -D 5 }",
|
||||||
"bind -N 'Resize the pane left by 5' -r M-Left { resize-pane -L 5 }",
|
"bind -N 'Resize the pane left by 5' -r M-Left if -F '#{?floating_pane_flag}' { resizep -R-5 } { resize-pane -L 5 }",
|
||||||
"bind -N 'Resize the pane right by 5' -r M-Right { resize-pane -R 5 }",
|
"bind -N 'Resize the pane right by 5' -r M-Right resize-pane -R 5",
|
||||||
"bind -N 'Resize the pane up' -r C-Up { resize-pane -U }",
|
"bind -N 'Resize the pane up' -r C-Up if -F '#{?floating_pane_flag}' { resizep -D-1 } { resize-pane -U }",
|
||||||
"bind -N 'Resize the pane down' -r C-Down { resize-pane -D }",
|
"bind -N 'Resize the pane down' -r C-Down { resize-pane -D }",
|
||||||
"bind -N 'Resize the pane left' -r C-Left { resize-pane -L }",
|
"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 }",
|
"bind -N 'Resize the pane right' -r C-Right { resize-pane -R }",
|
||||||
|
|
||||||
/* Menu keys */
|
/* Menu keys */
|
||||||
@@ -448,6 +449,7 @@ key_bindings_init(void)
|
|||||||
|
|
||||||
/* Mouse button 1 drag on pane. */
|
/* Mouse button 1 drag on pane. */
|
||||||
"bind -n MouseDrag1Pane { if -F '#{||:#{pane_in_mode},#{mouse_any_flag}}' { send -M } { copy-mode -M } }",
|
"bind -n MouseDrag1Pane { if -F '#{||:#{pane_in_mode},#{mouse_any_flag}}' { send -M } { copy-mode -M } }",
|
||||||
|
"bind -n M-MouseDrag1Pane { move-pane -M }",
|
||||||
|
|
||||||
/* Mouse wheel up on pane. */
|
/* Mouse wheel up on pane. */
|
||||||
"bind -n WheelUpPane { if -F '#{||:#{alternate_on},#{pane_in_mode},#{mouse_any_flag}}' { send -M } { copy-mode -e } }",
|
"bind -n WheelUpPane { if -F '#{||:#{alternate_on},#{pane_in_mode},#{mouse_any_flag}}' { send -M } { copy-mode -e } }",
|
||||||
@@ -466,6 +468,7 @@ key_bindings_init(void)
|
|||||||
|
|
||||||
/* Mouse button 1 drag on border. */
|
/* Mouse button 1 drag on border. */
|
||||||
"bind -n MouseDrag1Border { resize-pane -M }",
|
"bind -n MouseDrag1Border { resize-pane -M }",
|
||||||
|
"bind -n M-MouseDrag1Border { move-pane -M }",
|
||||||
|
|
||||||
/* Mouse button 1 down on status line. */
|
/* Mouse button 1 down on status line. */
|
||||||
"bind -n MouseDown1Status { switch-client -t= }",
|
"bind -n MouseDown1Status { switch-client -t= }",
|
||||||
@@ -482,8 +485,8 @@ key_bindings_init(void)
|
|||||||
"bind -n WheelUpStatus { previous-window }",
|
"bind -n WheelUpStatus { previous-window }",
|
||||||
|
|
||||||
/* Mouse button 3 down on status left. */
|
/* Mouse button 3 down on status left. */
|
||||||
"bind -n MouseDown3StatusLeft { display-menu -t= -xM -yW -T '#[align=centre]#{session_name}' " DEFAULT_SESSION_MENU " }",
|
"bind -n MouseDown3StatusLeft { run -C \"display-menu -t= -xM -yW -T '#[align=centre]#{session_name}' " DEFAULT_SESSION_MENU "\" }",
|
||||||
"bind -n M-MouseDown3StatusLeft { display-menu -t= -xM -yW -T '#[align=centre]#{session_name}' " DEFAULT_SESSION_MENU " }",
|
"bind -n M-MouseDown3StatusLeft { run -C \"display-menu -t= -xM -yW -T '#[align=centre]#{session_name}' " DEFAULT_SESSION_MENU "\" }",
|
||||||
|
|
||||||
/* Mouse button 3 down on status line. */
|
/* Mouse button 3 down on status line. */
|
||||||
"bind -n MouseDown3Status { display-menu -t= -xW -yW -T '#[align=centre]#{window_index}:#{window_name}' " DEFAULT_WINDOW_MENU "}",
|
"bind -n MouseDown3Status { display-menu -t= -xW -yW -T '#[align=centre]#{window_index}:#{window_name}' " DEFAULT_WINDOW_MENU "}",
|
||||||
@@ -511,8 +514,8 @@ key_bindings_init(void)
|
|||||||
"bind -Tcopy-mode M-l { send -X cursor-centre-horizontal }",
|
"bind -Tcopy-mode M-l { send -X cursor-centre-horizontal }",
|
||||||
"bind -Tcopy-mode C-n { send -X cursor-down }",
|
"bind -Tcopy-mode C-n { send -X cursor-down }",
|
||||||
"bind -Tcopy-mode C-p { send -X cursor-up }",
|
"bind -Tcopy-mode C-p { send -X cursor-up }",
|
||||||
"bind -Tcopy-mode C-r { command-prompt -T search -ip'(search up)' -I'#{pane_search_string}' { send -X search-backward-incremental -- '%%' } }",
|
"bind -Tcopy-mode C-r { command-prompt -P -T search -ip'(search up)' -I'#{pane_search_string}' { send -X search-backward-incremental -- '%%' } }",
|
||||||
"bind -Tcopy-mode C-s { command-prompt -T search -ip'(search down)' -I'#{pane_search_string}' { send -X search-forward-incremental -- '%%' } }",
|
"bind -Tcopy-mode C-s { command-prompt -P -T search -ip'(search down)' -I'#{pane_search_string}' { send -X search-forward-incremental -- '%%' } }",
|
||||||
"bind -Tcopy-mode C-v { send -X page-down }",
|
"bind -Tcopy-mode C-v { send -X page-down }",
|
||||||
"bind -Tcopy-mode C-w { send -X copy-pipe-and-cancel }",
|
"bind -Tcopy-mode C-w { send -X copy-pipe-and-cancel }",
|
||||||
"bind -Tcopy-mode Escape { send -X cancel }",
|
"bind -Tcopy-mode Escape { send -X cancel }",
|
||||||
@@ -520,18 +523,18 @@ key_bindings_init(void)
|
|||||||
"bind -Tcopy-mode Space { send -X page-down }",
|
"bind -Tcopy-mode Space { send -X page-down }",
|
||||||
"bind -Tcopy-mode , { send -X jump-reverse }",
|
"bind -Tcopy-mode , { send -X jump-reverse }",
|
||||||
"bind -Tcopy-mode \\; { send -X jump-again }",
|
"bind -Tcopy-mode \\; { send -X jump-again }",
|
||||||
"bind -Tcopy-mode F { command-prompt -1p'(jump backward)' { send -X jump-backward -- '%%' } }",
|
"bind -Tcopy-mode F { command-prompt -P -1p'(jump backward)' { send -X jump-backward -- '%%' } }",
|
||||||
"bind -Tcopy-mode N { send -X search-reverse }",
|
"bind -Tcopy-mode N { send -X search-reverse }",
|
||||||
"bind -Tcopy-mode P { send -X toggle-position }",
|
"bind -Tcopy-mode P { send -X toggle-position }",
|
||||||
"bind -Tcopy-mode R { send -X rectangle-toggle }",
|
"bind -Tcopy-mode R { send -X rectangle-toggle }",
|
||||||
"bind -Tcopy-mode T { command-prompt -1p'(jump to backward)' { send -X jump-to-backward -- '%%' } }",
|
"bind -Tcopy-mode T { command-prompt -P -1p'(jump to backward)' { send -X jump-to-backward -- '%%' } }",
|
||||||
"bind -Tcopy-mode X { send -X set-mark }",
|
"bind -Tcopy-mode X { send -X set-mark }",
|
||||||
"bind -Tcopy-mode f { command-prompt -1p'(jump forward)' { send -X jump-forward -- '%%' } }",
|
"bind -Tcopy-mode f { command-prompt -P -1p'(jump forward)' { send -X jump-forward -- '%%' } }",
|
||||||
"bind -Tcopy-mode g { command-prompt -p'(goto line)' { send -X goto-line -- '%%' } }",
|
"bind -Tcopy-mode g { command-prompt -P -p'(goto line)' { send -X goto-line -- '%%' } }",
|
||||||
"bind -Tcopy-mode n { send -X search-again }",
|
"bind -Tcopy-mode n { send -X search-again }",
|
||||||
"bind -Tcopy-mode q { send -X cancel }",
|
"bind -Tcopy-mode q { send -X cancel }",
|
||||||
"bind -Tcopy-mode r { send -X refresh-from-pane }",
|
"bind -Tcopy-mode r { send -X refresh-toggle }",
|
||||||
"bind -Tcopy-mode t { command-prompt -1p'(jump to forward)' { send -X jump-to-forward -- '%%' } }",
|
"bind -Tcopy-mode t { command-prompt -P -1p'(jump to forward)' { send -X jump-to-forward -- '%%' } }",
|
||||||
"bind -Tcopy-mode Home { send -X start-of-line }",
|
"bind -Tcopy-mode Home { send -X start-of-line }",
|
||||||
"bind -Tcopy-mode End { send -X end-of-line }",
|
"bind -Tcopy-mode End { send -X end-of-line }",
|
||||||
"bind -Tcopy-mode MouseDown1Pane select-pane",
|
"bind -Tcopy-mode MouseDown1Pane select-pane",
|
||||||
@@ -547,15 +550,15 @@ key_bindings_init(void)
|
|||||||
"bind -Tcopy-mode Down { send -X cursor-down }",
|
"bind -Tcopy-mode Down { send -X cursor-down }",
|
||||||
"bind -Tcopy-mode Left { send -X cursor-left }",
|
"bind -Tcopy-mode Left { send -X cursor-left }",
|
||||||
"bind -Tcopy-mode Right { send -X cursor-right }",
|
"bind -Tcopy-mode Right { send -X cursor-right }",
|
||||||
"bind -Tcopy-mode M-1 { command-prompt -Np'(repeat)' -I1 { send -N '%%' } }",
|
"bind -Tcopy-mode M-1 { command-prompt -P -Np'(repeat)' -I1 { send -N '%%' } }",
|
||||||
"bind -Tcopy-mode M-2 { command-prompt -Np'(repeat)' -I2 { send -N '%%' } }",
|
"bind -Tcopy-mode M-2 { command-prompt -P -Np'(repeat)' -I2 { send -N '%%' } }",
|
||||||
"bind -Tcopy-mode M-3 { command-prompt -Np'(repeat)' -I3 { send -N '%%' } }",
|
"bind -Tcopy-mode M-3 { command-prompt -P -Np'(repeat)' -I3 { send -N '%%' } }",
|
||||||
"bind -Tcopy-mode M-4 { command-prompt -Np'(repeat)' -I4 { send -N '%%' } }",
|
"bind -Tcopy-mode M-4 { command-prompt -P -Np'(repeat)' -I4 { send -N '%%' } }",
|
||||||
"bind -Tcopy-mode M-5 { command-prompt -Np'(repeat)' -I5 { send -N '%%' } }",
|
"bind -Tcopy-mode M-5 { command-prompt -P -Np'(repeat)' -I5 { send -N '%%' } }",
|
||||||
"bind -Tcopy-mode M-6 { command-prompt -Np'(repeat)' -I6 { send -N '%%' } }",
|
"bind -Tcopy-mode M-6 { command-prompt -P -Np'(repeat)' -I6 { send -N '%%' } }",
|
||||||
"bind -Tcopy-mode M-7 { command-prompt -Np'(repeat)' -I7 { send -N '%%' } }",
|
"bind -Tcopy-mode M-7 { command-prompt -P -Np'(repeat)' -I7 { send -N '%%' } }",
|
||||||
"bind -Tcopy-mode M-8 { command-prompt -Np'(repeat)' -I8 { send -N '%%' } }",
|
"bind -Tcopy-mode M-8 { command-prompt -P -Np'(repeat)' -I8 { send -N '%%' } }",
|
||||||
"bind -Tcopy-mode M-9 { command-prompt -Np'(repeat)' -I9 { send -N '%%' } }",
|
"bind -Tcopy-mode M-9 { command-prompt -P -Np'(repeat)' -I9 { send -N '%%' } }",
|
||||||
"bind -Tcopy-mode M-< { send -X history-top }",
|
"bind -Tcopy-mode M-< { send -X history-top }",
|
||||||
"bind -Tcopy-mode M-> { send -X history-bottom }",
|
"bind -Tcopy-mode M-> { send -X history-bottom }",
|
||||||
"bind -Tcopy-mode M-R { send -X top-line }",
|
"bind -Tcopy-mode M-R { send -X top-line }",
|
||||||
@@ -574,6 +577,8 @@ key_bindings_init(void)
|
|||||||
"bind -Tcopy-mode M-Down { send -X halfpage-down }",
|
"bind -Tcopy-mode M-Down { send -X halfpage-down }",
|
||||||
"bind -Tcopy-mode C-Up { send -X scroll-up }",
|
"bind -Tcopy-mode C-Up { send -X scroll-up }",
|
||||||
"bind -Tcopy-mode C-Down { send -X scroll-down }",
|
"bind -Tcopy-mode C-Down { send -X scroll-down }",
|
||||||
|
"bind -Tcopy-mode M-C-Up { send -X previous-prompt }",
|
||||||
|
"bind -Tcopy-mode M-C-Down { send -X next-prompt }",
|
||||||
|
|
||||||
/* Copy mode (vi) keys. */
|
/* Copy mode (vi) keys. */
|
||||||
"bind -Tcopy-mode-vi '#' { send -FX search-backward -- '#{copy_cursor_word}' }",
|
"bind -Tcopy-mode-vi '#' { send -FX search-backward -- '#{copy_cursor_word}' }",
|
||||||
@@ -594,25 +599,25 @@ key_bindings_init(void)
|
|||||||
"bind -Tcopy-mode-vi Space { send -X begin-selection }",
|
"bind -Tcopy-mode-vi Space { send -X begin-selection }",
|
||||||
"bind -Tcopy-mode-vi '$' { send -X end-of-line }",
|
"bind -Tcopy-mode-vi '$' { send -X end-of-line }",
|
||||||
"bind -Tcopy-mode-vi , { send -X jump-reverse }",
|
"bind -Tcopy-mode-vi , { send -X jump-reverse }",
|
||||||
"bind -Tcopy-mode-vi / { command-prompt -T search -p'(search down)' { send -X search-forward -- '%%' } }",
|
"bind -Tcopy-mode-vi / { command-prompt -P -T search -p'(search down)' { send -X search-forward -- '%%' } }",
|
||||||
"bind -Tcopy-mode-vi 0 { send -X start-of-line }",
|
"bind -Tcopy-mode-vi 0 { send -X start-of-line }",
|
||||||
"bind -Tcopy-mode-vi 1 { command-prompt -Np'(repeat)' -I1 { send -N '%%' } }",
|
"bind -Tcopy-mode-vi 1 { command-prompt -P -Np'(repeat)' -I1 { send -N '%%' } }",
|
||||||
"bind -Tcopy-mode-vi 2 { command-prompt -Np'(repeat)' -I2 { send -N '%%' } }",
|
"bind -Tcopy-mode-vi 2 { command-prompt -P -Np'(repeat)' -I2 { send -N '%%' } }",
|
||||||
"bind -Tcopy-mode-vi 3 { command-prompt -Np'(repeat)' -I3 { send -N '%%' } }",
|
"bind -Tcopy-mode-vi 3 { command-prompt -P -Np'(repeat)' -I3 { send -N '%%' } }",
|
||||||
"bind -Tcopy-mode-vi 4 { command-prompt -Np'(repeat)' -I4 { send -N '%%' } }",
|
"bind -Tcopy-mode-vi 4 { command-prompt -P -Np'(repeat)' -I4 { send -N '%%' } }",
|
||||||
"bind -Tcopy-mode-vi 5 { command-prompt -Np'(repeat)' -I5 { send -N '%%' } }",
|
"bind -Tcopy-mode-vi 5 { command-prompt -P -Np'(repeat)' -I5 { send -N '%%' } }",
|
||||||
"bind -Tcopy-mode-vi 6 { command-prompt -Np'(repeat)' -I6 { send -N '%%' } }",
|
"bind -Tcopy-mode-vi 6 { command-prompt -P -Np'(repeat)' -I6 { send -N '%%' } }",
|
||||||
"bind -Tcopy-mode-vi 7 { command-prompt -Np'(repeat)' -I7 { send -N '%%' } }",
|
"bind -Tcopy-mode-vi 7 { command-prompt -P -Np'(repeat)' -I7 { send -N '%%' } }",
|
||||||
"bind -Tcopy-mode-vi 8 { command-prompt -Np'(repeat)' -I8 { send -N '%%' } }",
|
"bind -Tcopy-mode-vi 8 { command-prompt -P -Np'(repeat)' -I8 { send -N '%%' } }",
|
||||||
"bind -Tcopy-mode-vi 9 { command-prompt -Np'(repeat)' -I9 { send -N '%%' } }",
|
"bind -Tcopy-mode-vi 9 { command-prompt -P -Np'(repeat)' -I9 { send -N '%%' } }",
|
||||||
"bind -Tcopy-mode-vi : { command-prompt -p'(goto line)' { send -X goto-line -- '%%' } }",
|
"bind -Tcopy-mode-vi : { command-prompt -P -p'(goto line)' { send -X goto-line -- '%%' } }",
|
||||||
"bind -Tcopy-mode-vi \\; { send -X jump-again }",
|
"bind -Tcopy-mode-vi \\; { send -X jump-again }",
|
||||||
"bind -Tcopy-mode-vi ? { command-prompt -T search -p'(search up)' { send -X search-backward -- '%%' } }",
|
"bind -Tcopy-mode-vi ? { command-prompt -P -T search -p'(search up)' { send -X search-backward -- '%%' } }",
|
||||||
"bind -Tcopy-mode-vi A { send -X append-selection-and-cancel }",
|
"bind -Tcopy-mode-vi A { send -X append-selection-and-cancel }",
|
||||||
"bind -Tcopy-mode-vi B { send -X previous-space }",
|
"bind -Tcopy-mode-vi B { send -X previous-space }",
|
||||||
"bind -Tcopy-mode-vi D { send -X copy-pipe-end-of-line-and-cancel }",
|
"bind -Tcopy-mode-vi D { send -X copy-pipe-end-of-line-and-cancel }",
|
||||||
"bind -Tcopy-mode-vi E { send -X next-space-end }",
|
"bind -Tcopy-mode-vi E { send -X next-space-end }",
|
||||||
"bind -Tcopy-mode-vi F { command-prompt -1p'(jump backward)' { send -X jump-backward -- '%%' } }",
|
"bind -Tcopy-mode-vi F { command-prompt -P -1p'(jump backward)' { send -X jump-backward -- '%%' } }",
|
||||||
"bind -Tcopy-mode-vi G { send -X history-bottom }",
|
"bind -Tcopy-mode-vi G { send -X history-bottom }",
|
||||||
"bind -Tcopy-mode-vi H { send -X top-line }",
|
"bind -Tcopy-mode-vi H { send -X top-line }",
|
||||||
"bind -Tcopy-mode-vi J { send -X scroll-down }",
|
"bind -Tcopy-mode-vi J { send -X scroll-down }",
|
||||||
@@ -621,14 +626,14 @@ key_bindings_init(void)
|
|||||||
"bind -Tcopy-mode-vi M { send -X middle-line }",
|
"bind -Tcopy-mode-vi M { send -X middle-line }",
|
||||||
"bind -Tcopy-mode-vi N { send -X search-reverse }",
|
"bind -Tcopy-mode-vi N { send -X search-reverse }",
|
||||||
"bind -Tcopy-mode-vi P { send -X toggle-position }",
|
"bind -Tcopy-mode-vi P { send -X toggle-position }",
|
||||||
"bind -Tcopy-mode-vi T { command-prompt -1p'(jump to backward)' { send -X jump-to-backward -- '%%' } }",
|
"bind -Tcopy-mode-vi T { command-prompt -P -1p'(jump to backward)' { send -X jump-to-backward -- '%%' } }",
|
||||||
"bind -Tcopy-mode-vi V { send -X select-line }",
|
"bind -Tcopy-mode-vi V { send -X select-line }",
|
||||||
"bind -Tcopy-mode-vi W { send -X next-space }",
|
"bind -Tcopy-mode-vi W { send -X next-space }",
|
||||||
"bind -Tcopy-mode-vi X { send -X set-mark }",
|
"bind -Tcopy-mode-vi X { send -X set-mark }",
|
||||||
"bind -Tcopy-mode-vi ^ { send -X back-to-indentation }",
|
"bind -Tcopy-mode-vi ^ { send -X back-to-indentation }",
|
||||||
"bind -Tcopy-mode-vi b { send -X previous-word }",
|
"bind -Tcopy-mode-vi b { send -X previous-word }",
|
||||||
"bind -Tcopy-mode-vi e { send -X next-word-end }",
|
"bind -Tcopy-mode-vi e { send -X next-word-end }",
|
||||||
"bind -Tcopy-mode-vi f { command-prompt -1p'(jump forward)' { send -X jump-forward -- '%%' } }",
|
"bind -Tcopy-mode-vi f { command-prompt -P -1p'(jump forward)' { send -X jump-forward -- '%%' } }",
|
||||||
"bind -Tcopy-mode-vi g { send -X history-top }",
|
"bind -Tcopy-mode-vi g { send -X history-top }",
|
||||||
"bind -Tcopy-mode-vi h { send -X cursor-left }",
|
"bind -Tcopy-mode-vi h { send -X cursor-left }",
|
||||||
"bind -Tcopy-mode-vi j { send -X cursor-down }",
|
"bind -Tcopy-mode-vi j { send -X cursor-down }",
|
||||||
@@ -638,8 +643,8 @@ key_bindings_init(void)
|
|||||||
"bind -Tcopy-mode-vi n { send -X search-again }",
|
"bind -Tcopy-mode-vi n { send -X search-again }",
|
||||||
"bind -Tcopy-mode-vi o { send -X other-end }",
|
"bind -Tcopy-mode-vi o { send -X other-end }",
|
||||||
"bind -Tcopy-mode-vi q { send -X cancel }",
|
"bind -Tcopy-mode-vi q { send -X cancel }",
|
||||||
"bind -Tcopy-mode-vi r { send -X refresh-from-pane }",
|
"bind -Tcopy-mode-vi r { send -X refresh-toggle }",
|
||||||
"bind -Tcopy-mode-vi t { command-prompt -1p'(jump to forward)' { send -X jump-to-forward -- '%%' } }",
|
"bind -Tcopy-mode-vi t { command-prompt -P -1p'(jump to forward)' { send -X jump-to-forward -- '%%' } }",
|
||||||
"bind -Tcopy-mode-vi v { send -X rectangle-toggle }",
|
"bind -Tcopy-mode-vi v { send -X rectangle-toggle }",
|
||||||
"bind -Tcopy-mode-vi w { send -X next-word }",
|
"bind -Tcopy-mode-vi w { send -X next-word }",
|
||||||
"bind -Tcopy-mode-vi '{' { send -X previous-paragraph }",
|
"bind -Tcopy-mode-vi '{' { send -X previous-paragraph }",
|
||||||
|
|||||||
@@ -379,6 +379,8 @@ layout_construct(struct layout_cell *lcparent, const char **layout,
|
|||||||
struct layout_cell *lcchild;
|
struct layout_cell *lcchild;
|
||||||
|
|
||||||
*lc = layout_construct_cell(lcparent, layout);
|
*lc = layout_construct_cell(lcparent, layout);
|
||||||
|
if (*lc == NULL)
|
||||||
|
return (-1);
|
||||||
|
|
||||||
switch (**layout) {
|
switch (**layout) {
|
||||||
case ',':
|
case ',':
|
||||||
|
|||||||
409
layout.c
409
layout.c
@@ -20,17 +20,25 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "tmux.h"
|
#include "tmux.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The window layout is a tree of cells each of which can be one of: a
|
* The window layout is a tree of cells each of which can be one of: a
|
||||||
* left-right container for a list of cells, a top-bottom container for a list
|
* left-right container for a list of cells, a top-bottom container for a list
|
||||||
* of cells, or a container for a window pane.
|
* of cells, or a container for a window pane. 'Node' will be used to refer to
|
||||||
|
* a cell which contains a list of cells, and 'leaf' to refer to a cell that
|
||||||
|
* contains a window pane. A leaf is considered to be 'tiled' if it is to be
|
||||||
|
* drawn as a part of the tiled layout. A 'neighbour' is a sibling that is also
|
||||||
|
* tiled. A cell's 'split' size refers to the side that is shortened when
|
||||||
|
* splitting it, determined by the parent's type.
|
||||||
*
|
*
|
||||||
* Each window has a pointer to the root of its layout tree (containing its
|
* Each window has a pointer to the root of its layout tree (containing its
|
||||||
* panes), every pane has a pointer back to the cell containing it, and each
|
* panes), every pane has a pointer back to the cell containing it, and each
|
||||||
* cell a pointer to its parent cell.
|
* cell a pointer to its parent cell. Every cell has a position in the root
|
||||||
|
* layout tree. This position is retained through cell state changes such as
|
||||||
|
* floating or hiding.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static u_int layout_resize_check(struct window *, struct layout_cell *,
|
static u_int layout_resize_check(struct window *, struct layout_cell *,
|
||||||
@@ -240,6 +248,49 @@ layout_fix_zindexes(struct window *w, struct layout_cell *lc)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
layout_cell_is_tiled(struct layout_cell *lc)
|
||||||
|
{
|
||||||
|
int is_leaf = lc->type == LAYOUT_WINDOWPANE;
|
||||||
|
int is_floating = lc->flags & LAYOUT_CELL_FLOATING;
|
||||||
|
|
||||||
|
return is_leaf && !is_floating;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
layout_cell_has_tiled_child(struct layout_cell *lc)
|
||||||
|
{
|
||||||
|
struct layout_cell *lcchild;
|
||||||
|
|
||||||
|
if (lc->type == LAYOUT_WINDOWPANE)
|
||||||
|
return (0);
|
||||||
|
|
||||||
|
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
||||||
|
if (layout_cell_is_tiled(lcchild) ||
|
||||||
|
layout_cell_has_tiled_child(lcchild))
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
layout_cell_is_first_tiled(struct layout_cell *lc)
|
||||||
|
{
|
||||||
|
struct layout_cell *lcchild, *lcparent = lc->parent;
|
||||||
|
|
||||||
|
if (lcparent == NULL)
|
||||||
|
return (layout_cell_is_tiled(lc));
|
||||||
|
|
||||||
|
TAILQ_FOREACH(lcchild, &lcparent->cells, entry) {
|
||||||
|
if (layout_cell_is_tiled(lcchild) ||
|
||||||
|
layout_cell_has_tiled_child(lcchild))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (lcchild == lc);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Fix cell offsets for a child cell. */
|
/* Fix cell offsets for a child cell. */
|
||||||
static void
|
static void
|
||||||
layout_fix_offsets1(struct layout_cell *lc)
|
layout_fix_offsets1(struct layout_cell *lc)
|
||||||
@@ -250,7 +301,8 @@ layout_fix_offsets1(struct layout_cell *lc)
|
|||||||
if (lc->type == LAYOUT_LEFTRIGHT) {
|
if (lc->type == LAYOUT_LEFTRIGHT) {
|
||||||
xoff = lc->xoff;
|
xoff = lc->xoff;
|
||||||
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
||||||
if (lcchild->flags & LAYOUT_CELL_FLOATING)
|
if (!layout_cell_is_tiled(lcchild) &&
|
||||||
|
!layout_cell_has_tiled_child(lcchild))
|
||||||
continue;
|
continue;
|
||||||
lcchild->xoff = xoff;
|
lcchild->xoff = xoff;
|
||||||
lcchild->yoff = lc->yoff;
|
lcchild->yoff = lc->yoff;
|
||||||
@@ -261,7 +313,8 @@ layout_fix_offsets1(struct layout_cell *lc)
|
|||||||
} else {
|
} else {
|
||||||
yoff = lc->yoff;
|
yoff = lc->yoff;
|
||||||
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
||||||
if (lcchild->flags & LAYOUT_CELL_FLOATING)
|
if (!layout_cell_is_tiled(lcchild) &&
|
||||||
|
!layout_cell_has_tiled_child(lcchild))
|
||||||
continue;
|
continue;
|
||||||
lcchild->xoff = lc->xoff;
|
lcchild->xoff = lc->xoff;
|
||||||
lcchild->yoff = yoff;
|
lcchild->yoff = yoff;
|
||||||
@@ -299,7 +352,7 @@ layout_cell_is_top(struct window *w, struct layout_cell *lc)
|
|||||||
if (next == NULL)
|
if (next == NULL)
|
||||||
return (0);
|
return (0);
|
||||||
if (next->type == LAYOUT_TOPBOTTOM &&
|
if (next->type == LAYOUT_TOPBOTTOM &&
|
||||||
lc != TAILQ_FIRST(&next->cells))
|
!layout_cell_is_first_tiled(lc))
|
||||||
return (0);
|
return (0);
|
||||||
lc = next;
|
lc = next;
|
||||||
}
|
}
|
||||||
@@ -310,15 +363,22 @@ layout_cell_is_top(struct window *w, struct layout_cell *lc)
|
|||||||
static int
|
static int
|
||||||
layout_cell_is_bottom(struct window *w, struct layout_cell *lc)
|
layout_cell_is_bottom(struct window *w, struct layout_cell *lc)
|
||||||
{
|
{
|
||||||
struct layout_cell *next;
|
struct layout_cell *next, *edge;
|
||||||
|
|
||||||
while (lc != w->layout_root) {
|
while (lc != w->layout_root) {
|
||||||
next = lc->parent;
|
next = lc->parent;
|
||||||
if (next == NULL)
|
if (next == NULL)
|
||||||
return (0);
|
return (0);
|
||||||
if (next->type == LAYOUT_TOPBOTTOM &&
|
if (next->type == LAYOUT_TOPBOTTOM) {
|
||||||
lc != TAILQ_LAST(&next->cells, layout_cells))
|
edge = TAILQ_LAST(&next->cells, layout_cells);
|
||||||
return (0);
|
while (edge != NULL) {
|
||||||
|
if (~edge->flags & LAYOUT_CELL_FLOATING)
|
||||||
|
break;
|
||||||
|
edge = TAILQ_PREV(edge, layout_cells, entry);
|
||||||
|
}
|
||||||
|
if (lc != edge)
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
lc = next;
|
lc = next;
|
||||||
}
|
}
|
||||||
return (1);
|
return (1);
|
||||||
@@ -346,9 +406,10 @@ layout_fix_panes(struct window *w, struct window_pane *skip)
|
|||||||
struct window_pane *wp;
|
struct window_pane *wp;
|
||||||
struct layout_cell *lc;
|
struct layout_cell *lc;
|
||||||
int status, scrollbars, sb_pos, sb_w, sb_pad;
|
int status, scrollbars, sb_pos, sb_w, sb_pad;
|
||||||
u_int sx, sy;
|
int old_xoff, old_yoff, changed = 0;
|
||||||
|
u_int sx, sy, old_sx, old_sy;
|
||||||
|
|
||||||
status = options_get_number(w->options, "pane-border-status");
|
status = window_get_pane_status(w);
|
||||||
scrollbars = options_get_number(w->options, "pane-scrollbars");
|
scrollbars = options_get_number(w->options, "pane-scrollbars");
|
||||||
sb_pos = options_get_number(w->options, "pane-scrollbars-position");
|
sb_pos = options_get_number(w->options, "pane-scrollbars-position");
|
||||||
|
|
||||||
@@ -356,6 +417,11 @@ layout_fix_panes(struct window *w, struct window_pane *skip)
|
|||||||
if ((lc = wp->layout_cell) == NULL || wp == skip)
|
if ((lc = wp->layout_cell) == NULL || wp == skip)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
old_xoff = wp->xoff;
|
||||||
|
old_yoff = wp->yoff;
|
||||||
|
old_sx = wp->sx;
|
||||||
|
old_sy = wp->sy;
|
||||||
|
|
||||||
wp->xoff = lc->xoff;
|
wp->xoff = lc->xoff;
|
||||||
wp->yoff = lc->yoff;
|
wp->yoff = lc->yoff;
|
||||||
sx = lc->sx;
|
sx = lc->sx;
|
||||||
@@ -376,7 +442,7 @@ layout_fix_panes(struct window *w, struct window_pane *skip)
|
|||||||
if (sb_pad < 0)
|
if (sb_pad < 0)
|
||||||
sb_pad = 0;
|
sb_pad = 0;
|
||||||
if (sb_pos == PANE_SCROLLBARS_LEFT) {
|
if (sb_pos == PANE_SCROLLBARS_LEFT) {
|
||||||
if ((int)sx - sb_w < PANE_MINIMUM) {
|
if ((int)sx - sb_w - sb_pad < PANE_MINIMUM) {
|
||||||
wp->xoff = wp->xoff +
|
wp->xoff = wp->xoff +
|
||||||
(int)sx - PANE_MINIMUM;
|
(int)sx - PANE_MINIMUM;
|
||||||
sx = PANE_MINIMUM;
|
sx = PANE_MINIMUM;
|
||||||
@@ -393,7 +459,15 @@ layout_fix_panes(struct window *w, struct window_pane *skip)
|
|||||||
}
|
}
|
||||||
|
|
||||||
window_pane_resize(wp, sx, sy);
|
window_pane_resize(wp, sx, sy);
|
||||||
|
|
||||||
|
if (wp->xoff != old_xoff ||
|
||||||
|
wp->yoff != old_yoff ||
|
||||||
|
wp->sx != old_sx ||
|
||||||
|
wp->sy != old_sy)
|
||||||
|
changed = 1;
|
||||||
}
|
}
|
||||||
|
if (changed)
|
||||||
|
redraw_invalidate_scene(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Count the number of available cells in a layout. */
|
/* Count the number of available cells in a layout. */
|
||||||
@@ -426,7 +500,7 @@ layout_resize_check(struct window *w, struct layout_cell *lc,
|
|||||||
u_int available, minimum;
|
u_int available, minimum;
|
||||||
int status, scrollbars;
|
int status, scrollbars;
|
||||||
|
|
||||||
status = options_get_number(w->options, "pane-border-status");
|
status = window_get_pane_status(w);
|
||||||
scrollbars = options_get_number(w->options, "pane-scrollbars");
|
scrollbars = options_get_number(w->options, "pane-scrollbars");
|
||||||
|
|
||||||
if (lc->type == LAYOUT_WINDOWPANE) {
|
if (lc->type == LAYOUT_WINDOWPANE) {
|
||||||
@@ -491,13 +565,20 @@ layout_resize_adjust(struct window *w, struct layout_cell *lc,
|
|||||||
/* Child cell runs in a different direction. */
|
/* Child cell runs in a different direction. */
|
||||||
if (lc->type != type) {
|
if (lc->type != type) {
|
||||||
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
||||||
if (lcchild->flags & LAYOUT_CELL_FLOATING)
|
if (!layout_cell_is_tiled(lcchild) &&
|
||||||
|
!layout_cell_has_tiled_child(lcchild))
|
||||||
continue;
|
continue;
|
||||||
layout_resize_adjust(w, lcchild, type, change);
|
layout_resize_adjust(w, lcchild, type, change);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If a node doesn't contain any tiled cells, there is nothing to do.
|
||||||
|
*/
|
||||||
|
if (!layout_cell_has_tiled_child(lc))
|
||||||
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Child cell runs in the same direction. Adjust each child equally
|
* Child cell runs in the same direction. Adjust each child equally
|
||||||
* until no further change is possible.
|
* until no further change is possible.
|
||||||
@@ -506,7 +587,8 @@ layout_resize_adjust(struct window *w, struct layout_cell *lc,
|
|||||||
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
||||||
if (change == 0)
|
if (change == 0)
|
||||||
break;
|
break;
|
||||||
if (lcchild->flags & LAYOUT_CELL_FLOATING)
|
if (!layout_cell_is_tiled(lcchild) &&
|
||||||
|
!layout_cell_has_tiled_child(lcchild))
|
||||||
continue;
|
continue;
|
||||||
if (change > 0) {
|
if (change > 0) {
|
||||||
layout_resize_adjust(w, lcchild, type, 1);
|
layout_resize_adjust(w, lcchild, type, 1);
|
||||||
@@ -521,12 +603,57 @@ layout_resize_adjust(struct window *w, struct layout_cell *lc,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Find and return the nearest neighbour to a cell in a specific direction. */
|
||||||
|
static struct layout_cell *
|
||||||
|
layout_cell_get_neighbour_direction(struct layout_cell *lc, int direction)
|
||||||
|
{
|
||||||
|
struct layout_cell *lcn = lc;
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
if (direction)
|
||||||
|
lcn = TAILQ_NEXT(lcn, entry);
|
||||||
|
else
|
||||||
|
lcn = TAILQ_PREV(lcn, layout_cells, entry);
|
||||||
|
|
||||||
|
if (lcn == NULL ||
|
||||||
|
layout_cell_is_tiled(lcn) ||
|
||||||
|
layout_cell_has_tiled_child(lcn))
|
||||||
|
return (lcn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find and return the nearest neighbour. Prefers cells "after" the specified
|
||||||
|
* cell. This behavior defines how cell dimensions are redistributed when a cell
|
||||||
|
* is hidden/shown and floated/tiled.
|
||||||
|
*/
|
||||||
|
struct layout_cell *
|
||||||
|
layout_cell_get_neighbour(struct layout_cell *lc)
|
||||||
|
{
|
||||||
|
struct layout_cell *lcother, *lcparent = lc->parent;
|
||||||
|
int direction = 1;
|
||||||
|
|
||||||
|
if (lcparent == NULL)
|
||||||
|
return (NULL);
|
||||||
|
|
||||||
|
if (lc == TAILQ_LAST(&lcparent->cells, layout_cells))
|
||||||
|
direction = !direction;
|
||||||
|
|
||||||
|
lcother = layout_cell_get_neighbour_direction(lc, direction);
|
||||||
|
if (lcother == NULL)
|
||||||
|
lcother = layout_cell_get_neighbour_direction(lc, !direction);
|
||||||
|
|
||||||
|
return (lcother);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Destroy a cell and redistribute the space. */
|
/* Destroy a cell and redistribute the space. */
|
||||||
void
|
void
|
||||||
layout_destroy_cell(struct window *w, struct layout_cell *lc,
|
layout_destroy_cell(struct window *w, struct layout_cell *lc,
|
||||||
struct layout_cell **lcroot)
|
struct layout_cell **lcroot)
|
||||||
{
|
{
|
||||||
struct layout_cell *lcother = NULL, *lcparent;
|
struct layout_cell *lcother = NULL, *lcparent;
|
||||||
|
int change;
|
||||||
|
|
||||||
/* If no parent, this is the last pane in a window. */
|
/* If no parent, this is the last pane in a window. */
|
||||||
lcparent = lc->parent;
|
lcparent = lc->parent;
|
||||||
@@ -537,27 +664,27 @@ layout_destroy_cell(struct window *w, struct layout_cell *lc,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (~lc->flags & LAYOUT_CELL_FLOATING) {
|
if (!layout_cell_is_tiled(lc)) {
|
||||||
/* Merge the space into the previous or next cell. */
|
TAILQ_REMOVE(&lcparent->cells, lc, entry);
|
||||||
if (lc == TAILQ_FIRST(&lcparent->cells))
|
layout_free_cell(lc);
|
||||||
lcother = TAILQ_NEXT(lc, entry);
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
lcother = layout_cell_get_neighbour(lc);
|
||||||
|
if (lcother != NULL) {
|
||||||
|
if (lcparent->type == LAYOUT_LEFTRIGHT)
|
||||||
|
change = lc->sx + 1;
|
||||||
else
|
else
|
||||||
lcother = TAILQ_PREV(lc, layout_cells, entry);
|
change = lc->sy + 1;
|
||||||
}
|
layout_resize_adjust(w, lcother, lcparent->type, change);
|
||||||
if (lcother != NULL && (~lcother->flags & LAYOUT_CELL_FLOATING)) {
|
} else
|
||||||
if (lcparent->type == LAYOUT_LEFTRIGHT) {
|
layout_remove_tile(w, lcparent);
|
||||||
layout_resize_adjust(w, lcother, lcparent->type,
|
|
||||||
lc->sx + 1);
|
|
||||||
} else {
|
|
||||||
layout_resize_adjust(w, lcother, lcparent->type,
|
|
||||||
lc->sy + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Remove this from the parent's list. */
|
/* Remove this from the parent's list. */
|
||||||
TAILQ_REMOVE(&lcparent->cells, lc, entry);
|
TAILQ_REMOVE(&lcparent->cells, lc, entry);
|
||||||
layout_free_cell(lc);
|
layout_free_cell(lc);
|
||||||
|
|
||||||
|
out:
|
||||||
/*
|
/*
|
||||||
* If the parent now has one cell, remove the parent from the tree and
|
* If the parent now has one cell, remove the parent from the tree and
|
||||||
* replace it by that cell.
|
* replace it by that cell.
|
||||||
@@ -568,7 +695,7 @@ layout_destroy_cell(struct window *w, struct layout_cell *lc,
|
|||||||
|
|
||||||
lc->parent = lcparent->parent;
|
lc->parent = lcparent->parent;
|
||||||
if (lc->parent == NULL) {
|
if (lc->parent == NULL) {
|
||||||
if (~lc->flags & LAYOUT_CELL_FLOATING) {
|
if (layout_cell_is_tiled(lc)) {
|
||||||
lc->xoff = 0;
|
lc->xoff = 0;
|
||||||
lc->yoff = 0;
|
lc->yoff = 0;
|
||||||
}
|
}
|
||||||
@@ -686,6 +813,76 @@ layout_resize_pane_to(struct window_pane *wp, enum layout_type type,
|
|||||||
layout_resize_pane(wp, type, change, 1);
|
layout_resize_pane(wp, type, change, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Resize a floating pane to an absolute size. */
|
||||||
|
void
|
||||||
|
layout_resize_floating_pane_to(struct window_pane *wp, enum layout_type type,
|
||||||
|
u_int size, char **cause)
|
||||||
|
{
|
||||||
|
struct layout_cell *lc = wp->layout_cell;
|
||||||
|
|
||||||
|
if (~lc->flags & LAYOUT_CELL_FLOATING) {
|
||||||
|
*cause = xstrdup("pane is not floating");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window_pane_get_pane_lines(wp) != PANE_LINES_NONE &&
|
||||||
|
size >= PANE_MINIMUM + 2)
|
||||||
|
size -= 2;
|
||||||
|
if (size < PANE_MINIMUM || size > PANE_MAXIMUM) {
|
||||||
|
*cause = xstrdup("size is too big or too small");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == LAYOUT_TOPBOTTOM) {
|
||||||
|
if (lc->sy == size)
|
||||||
|
return;
|
||||||
|
lc->sy = size;
|
||||||
|
} else {
|
||||||
|
if (lc->sx == size)
|
||||||
|
return;
|
||||||
|
lc->sx = size;
|
||||||
|
}
|
||||||
|
redraw_invalidate_scene(wp->window);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Resize a floating pane relative to its current size. */
|
||||||
|
void
|
||||||
|
layout_resize_floating_pane(struct window_pane *wp, enum layout_type type,
|
||||||
|
int change, int opposite, char **cause)
|
||||||
|
{
|
||||||
|
struct layout_cell *lc = wp->layout_cell;
|
||||||
|
u_int size;
|
||||||
|
|
||||||
|
if (~lc->flags & LAYOUT_CELL_FLOATING) {
|
||||||
|
*cause = xstrdup("pane is not floating");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (change == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (type == LAYOUT_TOPBOTTOM) {
|
||||||
|
size = lc->sy + change;
|
||||||
|
if (size < PANE_MINIMUM || size > PANE_MAXIMUM) {
|
||||||
|
*cause = xstrdup("change is too big or too small");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lc->sy = size;
|
||||||
|
if (opposite)
|
||||||
|
lc->yoff -= change;
|
||||||
|
} else {
|
||||||
|
size = lc->sx + change;
|
||||||
|
if (size < PANE_MINIMUM || size > PANE_MAXIMUM) {
|
||||||
|
*cause = xstrdup("change is too big or too small");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lc->sx = size;
|
||||||
|
if (opposite)
|
||||||
|
lc->xoff -= change;
|
||||||
|
}
|
||||||
|
redraw_invalidate_scene(wp->window);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Resize a layout cell. */
|
||||||
void
|
void
|
||||||
layout_resize_layout(struct window *w, struct layout_cell *lc,
|
layout_resize_layout(struct window *w, struct layout_cell *lc,
|
||||||
enum layout_type type, int change, int opposite)
|
enum layout_type type, int change, int opposite)
|
||||||
@@ -719,9 +916,7 @@ void
|
|||||||
layout_resize_pane(struct window_pane *wp, enum layout_type type, int change,
|
layout_resize_pane(struct window_pane *wp, enum layout_type type, int change,
|
||||||
int opposite)
|
int opposite)
|
||||||
{
|
{
|
||||||
struct layout_cell *lc, *lcparent;
|
struct layout_cell *lc = wp->layout_cell, *lcparent;
|
||||||
|
|
||||||
lc = wp->layout_cell;
|
|
||||||
|
|
||||||
/* Find next parent of the same type. */
|
/* Find next parent of the same type. */
|
||||||
lcparent = lc->parent;
|
lcparent = lc->parent;
|
||||||
@@ -733,8 +928,11 @@ layout_resize_pane(struct window_pane *wp, enum layout_type type, int change,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
/* If this is the last cell, move back one. */
|
/* If this is the last cell, move back one. */
|
||||||
if (lc == TAILQ_LAST(&lcparent->cells, layout_cells))
|
if (lc == TAILQ_LAST(&lcparent->cells, layout_cells)) {
|
||||||
lc = TAILQ_PREV(lc, layout_cells, entry);
|
do
|
||||||
|
lc = TAILQ_PREV(lc, layout_cells, entry);
|
||||||
|
while (lc->flags & LAYOUT_CELL_FLOATING);
|
||||||
|
}
|
||||||
|
|
||||||
layout_resize_layout(wp->window, lc, type, change, opposite);
|
layout_resize_layout(wp->window, lc, type, change, opposite);
|
||||||
}
|
}
|
||||||
@@ -933,7 +1131,8 @@ layout_resize_child_cells(struct window *w, struct layout_cell *lc)
|
|||||||
count = 0;
|
count = 0;
|
||||||
previous = 0;
|
previous = 0;
|
||||||
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
||||||
if (lcchild->flags & LAYOUT_CELL_FLOATING)
|
if (!layout_cell_is_tiled(lcchild) &&
|
||||||
|
!layout_cell_has_tiled_child(lcchild))
|
||||||
continue;
|
continue;
|
||||||
count++;
|
count++;
|
||||||
if (lc->type == LAYOUT_LEFTRIGHT)
|
if (lc->type == LAYOUT_LEFTRIGHT)
|
||||||
@@ -953,7 +1152,8 @@ layout_resize_child_cells(struct window *w, struct layout_cell *lc)
|
|||||||
/* Resize children into the new size. */
|
/* Resize children into the new size. */
|
||||||
idx = 0;
|
idx = 0;
|
||||||
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
||||||
if (lcchild->flags & LAYOUT_CELL_FLOATING)
|
if (!layout_cell_is_tiled(lcchild) &&
|
||||||
|
!layout_cell_has_tiled_child(lcchild))
|
||||||
continue;
|
continue;
|
||||||
if (lc->type == LAYOUT_TOPBOTTOM) {
|
if (lc->type == LAYOUT_TOPBOTTOM) {
|
||||||
lcchild->sx = lc->sx;
|
lcchild->sx = lc->sx;
|
||||||
@@ -999,7 +1199,7 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
|
|||||||
lc = wp->window->layout_root;
|
lc = wp->window->layout_root;
|
||||||
else
|
else
|
||||||
lc = wp->layout_cell;
|
lc = wp->layout_cell;
|
||||||
status = options_get_number(wp->window->options, "pane-border-status");
|
status = window_get_pane_status(wp->window);
|
||||||
scrollbars = options_get_number(wp->window->options, "pane-scrollbars");
|
scrollbars = options_get_number(wp->window->options, "pane-scrollbars");
|
||||||
|
|
||||||
/* Copy the old cell size. */
|
/* Copy the old cell size. */
|
||||||
@@ -1160,14 +1360,21 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
|
|||||||
* layout_assign_pane before much else happens!
|
* layout_assign_pane before much else happens!
|
||||||
*/
|
*/
|
||||||
struct layout_cell *
|
struct layout_cell *
|
||||||
layout_floating_pane(struct window *w, u_int sx, u_int sy, int ox, int oy)
|
layout_floating_pane(struct window *w, struct window_pane *wp, u_int sx,
|
||||||
|
u_int sy, int ox, int oy)
|
||||||
{
|
{
|
||||||
struct layout_cell *lc = w->layout_root, *lcnew, *lcparent;
|
struct layout_cell *lc, *lcnew, *lcparent;
|
||||||
|
|
||||||
if (lc->type == LAYOUT_WINDOWPANE) {
|
if (wp == NULL)
|
||||||
|
lc = w->layout_root;
|
||||||
|
else
|
||||||
|
lc = wp->layout_cell;
|
||||||
|
lcparent = lc->parent;
|
||||||
|
|
||||||
|
if (lcparent == NULL) {
|
||||||
/*
|
/*
|
||||||
* Adding a pane to a root that doesn't have a container. Must
|
* Adding a pane to a root that isn't node. Must create and
|
||||||
* create and insert a new root.
|
* insert a new root.
|
||||||
*/
|
*/
|
||||||
lcparent = layout_create_cell(NULL);
|
lcparent = layout_create_cell(NULL);
|
||||||
layout_make_node(lcparent, LAYOUT_TOPBOTTOM);
|
layout_make_node(lcparent, LAYOUT_TOPBOTTOM);
|
||||||
@@ -1177,11 +1384,10 @@ layout_floating_pane(struct window *w, u_int sx, u_int sy, int ox, int oy)
|
|||||||
/* Insert the old cell. */
|
/* Insert the old cell. */
|
||||||
lc->parent = lcparent;
|
lc->parent = lcparent;
|
||||||
TAILQ_INSERT_HEAD(&lcparent->cells, lc, entry);
|
TAILQ_INSERT_HEAD(&lcparent->cells, lc, entry);
|
||||||
} else
|
}
|
||||||
lcparent = w->layout_root;
|
|
||||||
|
|
||||||
lcnew = layout_create_cell(lcparent);
|
lcnew = layout_create_cell(lcparent);
|
||||||
TAILQ_INSERT_TAIL(&lcparent->cells, lcnew, entry);
|
TAILQ_INSERT_AFTER(&lcparent->cells, lc, lcnew, entry);
|
||||||
lcnew->flags |= LAYOUT_CELL_FLOATING;
|
lcnew->flags |= LAYOUT_CELL_FLOATING;
|
||||||
layout_set_size(lcnew, sx, sy, ox, oy);
|
layout_set_size(lcnew, sx, sy, ox, oy);
|
||||||
|
|
||||||
@@ -1222,7 +1428,7 @@ layout_spread_cell(struct window *w, struct layout_cell *parent)
|
|||||||
number++;
|
number++;
|
||||||
if (number <= 1)
|
if (number <= 1)
|
||||||
return (0);
|
return (0);
|
||||||
status = options_get_number(w->options, "pane-border-status");
|
status = window_get_pane_status(w);
|
||||||
|
|
||||||
if (parent->type == LAYOUT_LEFTRIGHT)
|
if (parent->type == LAYOUT_LEFTRIGHT)
|
||||||
size = parent->sx;
|
size = parent->sx;
|
||||||
@@ -1302,6 +1508,7 @@ layout_get_tiled_cell(struct cmdq_item *item, struct args *args,
|
|||||||
enum layout_type type;
|
enum layout_type type;
|
||||||
u_int curval;
|
u_int curval;
|
||||||
int size = -1;
|
int size = -1;
|
||||||
|
char *error = NULL;
|
||||||
|
|
||||||
if (window_pane_is_floating(wp)) {
|
if (window_pane_is_floating(wp)) {
|
||||||
*cause = xstrdup("can't split a floating pane");
|
*cause = xstrdup("can't split a floating pane");
|
||||||
@@ -1328,15 +1535,16 @@ layout_get_tiled_cell(struct cmdq_item *item, struct args *args,
|
|||||||
|
|
||||||
if (args_has(args, 'l')) {
|
if (args_has(args, 'l')) {
|
||||||
size = args_percentage_and_expand(args, 'l', 0, INT_MAX, curval,
|
size = args_percentage_and_expand(args, 'l', 0, INT_MAX, curval,
|
||||||
item, cause);
|
item, &error);
|
||||||
} else if (args_has(args, 'p')) {
|
} else if (args_has(args, 'p')) {
|
||||||
size = args_strtonum_and_expand(args, 'p', 0, 100, item,
|
size = args_strtonum_and_expand(args, 'p', 0, 100, item,
|
||||||
cause);
|
&error);
|
||||||
if (*cause == NULL)
|
if (error == NULL)
|
||||||
size = curval * size / 100;
|
size = curval * size / 100;
|
||||||
}
|
}
|
||||||
if (*cause != NULL) {
|
if (error != NULL) {
|
||||||
*cause = xstrdup("invalid tiled geometry");
|
xasprintf(cause, "invalid tiled geometry %s", error);
|
||||||
|
free(error);
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1356,35 +1564,53 @@ layout_get_tiled_cell(struct cmdq_item *item, struct args *args,
|
|||||||
/* Get a new floating cell. */
|
/* Get a new floating cell. */
|
||||||
struct layout_cell *
|
struct layout_cell *
|
||||||
layout_get_floating_cell(struct cmdq_item *item, struct args *args,
|
layout_get_floating_cell(struct cmdq_item *item, struct args *args,
|
||||||
struct window *w, __unused struct window_pane *wp, char **cause)
|
enum pane_lines lines, struct window *w, struct window_pane *wp,
|
||||||
|
char **cause)
|
||||||
{
|
{
|
||||||
struct layout_cell *lcnew;
|
struct layout_cell *lcnew;
|
||||||
int sx = w->sx / 2, sy = w->sy / 4;
|
int sx = w->sx / 2, sy = w->sy / 4;
|
||||||
int ox = INT_MAX, oy = INT_MAX;
|
int ox = INT_MAX, oy = INT_MAX;
|
||||||
|
char *error;
|
||||||
|
|
||||||
if (args_has(args, 'x')) {
|
if (args_has(args, 'x')) {
|
||||||
sx = args_percentage_and_expand(args, 'x', 0, w->sx - 1, w->sx,
|
sx = args_percentage_and_expand(args, 'x', 0, PANE_MAXIMUM,
|
||||||
item, cause);
|
w->sx, item, &error);
|
||||||
if (*cause != NULL)
|
if (error != NULL) {
|
||||||
|
xasprintf(cause, "position %s", error);
|
||||||
|
free(error);
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
}
|
||||||
|
if (lines != PANE_LINES_NONE)
|
||||||
|
sx -= 2;
|
||||||
}
|
}
|
||||||
if (args_has(args, 'y')) {
|
if (args_has(args, 'y')) {
|
||||||
sy = args_percentage_and_expand(args, 'y', 0, w->sy - 1, w->sy,
|
sy = args_percentage_and_expand(args, 'y', 0, PANE_MAXIMUM,
|
||||||
item, cause);
|
w->sy, item, &error);
|
||||||
if (*cause != NULL)
|
if (error != NULL) {
|
||||||
|
xasprintf(cause, "position %s", error);
|
||||||
|
free(error);
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
}
|
||||||
|
if (lines != PANE_LINES_NONE)
|
||||||
|
sy -= 2;
|
||||||
}
|
}
|
||||||
if (args_has(args, 'X')) {
|
if (args_has(args, 'X')) {
|
||||||
ox = args_percentage_and_expand(args, 'X', -sx, w->sx,
|
ox = args_percentage_and_expand(args, 'X', -sx, w->sx,
|
||||||
w->sx, item, cause);
|
w->sx, item, &error);
|
||||||
if (*cause != NULL)
|
if (error != NULL) {
|
||||||
|
xasprintf(cause, "size %s", error);
|
||||||
|
free(error);
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (args_has(args, 'Y')) {
|
if (args_has(args, 'Y')) {
|
||||||
oy = args_percentage_and_expand(args, 'Y', -sy, w->sy,
|
oy = args_percentage_and_expand(args, 'Y', -sy, w->sy,
|
||||||
w->sy, item, cause);
|
w->sy, item, &error);
|
||||||
if (*cause != NULL)
|
if (error != NULL) {
|
||||||
|
xasprintf(cause, "size %s", error);
|
||||||
|
free(error);
|
||||||
return (NULL);
|
return (NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ox == INT_MAX) {
|
if (ox == INT_MAX) {
|
||||||
@@ -1396,7 +1622,9 @@ layout_get_floating_cell(struct cmdq_item *item, struct args *args,
|
|||||||
ox = 4;
|
ox = 4;
|
||||||
}
|
}
|
||||||
w->last_new_pane_x = ox;
|
w->last_new_pane_x = ox;
|
||||||
}
|
} else
|
||||||
|
if (lines != PANE_LINES_NONE)
|
||||||
|
ox += 1;
|
||||||
if (oy == INT_MAX) {
|
if (oy == INT_MAX) {
|
||||||
if (w->last_new_pane_y == 0)
|
if (w->last_new_pane_y == 0)
|
||||||
oy = 2;
|
oy = 2;
|
||||||
@@ -1406,8 +1634,55 @@ layout_get_floating_cell(struct cmdq_item *item, struct args *args,
|
|||||||
oy = 2;
|
oy = 2;
|
||||||
}
|
}
|
||||||
w->last_new_pane_y = oy;
|
w->last_new_pane_y = oy;
|
||||||
|
} else
|
||||||
|
if (lines != PANE_LINES_NONE)
|
||||||
|
oy += 1;
|
||||||
|
|
||||||
|
if (sx < PANE_MINIMUM || sx > PANE_MAXIMUM) {
|
||||||
|
*cause = xstrdup("invalid width");
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
if (sy < PANE_MINIMUM || sy > PANE_MAXIMUM) {
|
||||||
|
*cause = xstrdup("invalid height");
|
||||||
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
lcnew = layout_floating_pane(w, sx, sy, ox, oy);
|
lcnew = layout_floating_pane(w, wp, sx, sy, ox, oy);
|
||||||
return (lcnew);
|
return (lcnew);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Removes a cell from the tiled layout by giving the cell's space to the
|
||||||
|
* nearest neighbour.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
layout_remove_tile(struct window *w, struct layout_cell *lc)
|
||||||
|
{
|
||||||
|
struct layout_cell *lcneighbour, *lcparent;
|
||||||
|
enum layout_type type;
|
||||||
|
int change;
|
||||||
|
|
||||||
|
if (lc->flags & LAYOUT_CELL_FLOATING)
|
||||||
|
return (0);
|
||||||
|
|
||||||
|
lcneighbour = layout_cell_get_neighbour(lc);
|
||||||
|
if (lcneighbour == NULL) {
|
||||||
|
if (lc->parent != NULL)
|
||||||
|
layout_remove_tile(w, lc->parent);
|
||||||
|
} else if ((lcparent = lcneighbour->parent) != NULL) {
|
||||||
|
type = lcparent->type;
|
||||||
|
/*
|
||||||
|
* Adding the size of the layout cell plus its border to the
|
||||||
|
* neighbour.
|
||||||
|
*/
|
||||||
|
if (type == LAYOUT_TOPBOTTOM)
|
||||||
|
change = lc->sy + 1;
|
||||||
|
else
|
||||||
|
change = lc->sx + 1;
|
||||||
|
layout_resize_adjust(w, lcneighbour, type, change);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Zeroing out the cell geometry until the cell is retiled. */
|
||||||
|
layout_set_size(lc, 0, 0, 0, 0);
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
|||||||
19
menu.c
19
menu.c
@@ -257,8 +257,7 @@ menu_reapply_styles(struct menu_data *md, struct client *c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
menu_draw_cb(struct client *c, void *data,
|
menu_draw_cb(struct client *c, void *data)
|
||||||
__unused struct screen_redraw_ctx *rctx)
|
|
||||||
{
|
{
|
||||||
struct menu_data *md = data;
|
struct menu_data *md = data;
|
||||||
struct tty *tty = &c->tty;
|
struct tty *tty = &c->tty;
|
||||||
@@ -281,10 +280,8 @@ menu_draw_cb(struct client *c, void *data,
|
|||||||
&md->style_gc, &md->border_style_gc, &md->selected_style_gc);
|
&md->style_gc, &md->border_style_gc, &md->selected_style_gc);
|
||||||
screen_write_stop(&ctx);
|
screen_write_stop(&ctx);
|
||||||
|
|
||||||
for (i = 0; i < screen_size_y(&md->s); i++) {
|
for (i = 0; i < screen_size_y(&md->s); i++)
|
||||||
tty_draw_line(tty, s, 0, i, menu->width + 4, px, py + i,
|
tty_draw_line(tty, s, 0, i, menu->width + 4, px, py + i, NULL);
|
||||||
&grid_default_cell, NULL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -440,7 +437,7 @@ menu_key_cb(struct client *c, void *data, struct key_event *event)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (name == NULL || *name == '-') {
|
while ((name == NULL || *name == '-') && md->choice != 0) {
|
||||||
md->choice--;
|
md->choice--;
|
||||||
name = menu->items[md->choice].name;
|
name = menu->items[md->choice].name;
|
||||||
}
|
}
|
||||||
@@ -450,7 +447,7 @@ menu_key_cb(struct client *c, void *data, struct key_event *event)
|
|||||||
case KEYC_HOME:
|
case KEYC_HOME:
|
||||||
md->choice = 0;
|
md->choice = 0;
|
||||||
name = menu->items[md->choice].name;
|
name = menu->items[md->choice].name;
|
||||||
while (name == NULL || *name == '-') {
|
while ((name == NULL || *name == '-') && md->choice != count - 1) {
|
||||||
md->choice++;
|
md->choice++;
|
||||||
name = menu->items[md->choice].name;
|
name = menu->items[md->choice].name;
|
||||||
}
|
}
|
||||||
@@ -460,7 +457,7 @@ menu_key_cb(struct client *c, void *data, struct key_event *event)
|
|||||||
case KEYC_END:
|
case KEYC_END:
|
||||||
md->choice = count - 1;
|
md->choice = count - 1;
|
||||||
name = menu->items[md->choice].name;
|
name = menu->items[md->choice].name;
|
||||||
while (name == NULL || *name == '-') {
|
while ((name == NULL || *name == '-') && md->choice != 0) {
|
||||||
md->choice--;
|
md->choice--;
|
||||||
name = menu->items[md->choice].name;
|
name = menu->items[md->choice].name;
|
||||||
}
|
}
|
||||||
@@ -638,7 +635,7 @@ menu_display(struct menu *menu, int flags, int starting_choice,
|
|||||||
style, selected_style, border_style, fs, cb, data);
|
style, selected_style, border_style, fs, cb, data);
|
||||||
if (md == NULL)
|
if (md == NULL)
|
||||||
return (-1);
|
return (-1);
|
||||||
server_client_set_overlay(c, 0, NULL, menu_mode_cb, menu_draw_cb,
|
server_client_set_overlay(c, 0, menu_check_cb, menu_mode_cb,
|
||||||
menu_key_cb, menu_free_cb, menu_resize_cb, md);
|
menu_draw_cb, menu_key_cb, menu_free_cb, menu_resize_cb, md);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|||||||
451
mode-tree.c
451
mode-tree.c
@@ -37,6 +37,7 @@ enum mode_tree_preview {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct mode_tree_item;
|
struct mode_tree_item;
|
||||||
|
struct mode_tree_prompt;
|
||||||
TAILQ_HEAD(mode_tree_list, mode_tree_item);
|
TAILQ_HEAD(mode_tree_list, mode_tree_item);
|
||||||
|
|
||||||
struct mode_tree_data {
|
struct mode_tree_data {
|
||||||
@@ -49,12 +50,13 @@ struct mode_tree_data {
|
|||||||
const struct menu_item *menu;
|
const struct menu_item *menu;
|
||||||
|
|
||||||
struct sort_criteria sort_crit;
|
struct sort_criteria sort_crit;
|
||||||
|
const char *view_name;
|
||||||
|
|
||||||
mode_tree_build_cb buildcb;
|
mode_tree_build_cb buildcb;
|
||||||
mode_tree_draw_cb drawcb;
|
mode_tree_draw_cb drawcb;
|
||||||
mode_tree_search_cb searchcb;
|
mode_tree_search_cb searchcb;
|
||||||
mode_tree_menu_cb menucb;
|
mode_tree_menu_cb menucb;
|
||||||
mode_tree_height_cb heightcb;
|
mode_tree_height_cb heightcb;
|
||||||
mode_tree_key_cb keycb;
|
mode_tree_key_cb keycb;
|
||||||
mode_tree_swap_cb swapcb;
|
mode_tree_swap_cb swapcb;
|
||||||
mode_tree_sort_cb sortcb;
|
mode_tree_sort_cb sortcb;
|
||||||
@@ -76,6 +78,10 @@ struct mode_tree_data {
|
|||||||
u_int current;
|
u_int current;
|
||||||
|
|
||||||
struct screen screen;
|
struct screen screen;
|
||||||
|
struct prompt *prompt;
|
||||||
|
struct mode_tree_prompt *prompt_data;
|
||||||
|
u_int prompt_cx;
|
||||||
|
int prompt_top;
|
||||||
|
|
||||||
int preview;
|
int preview;
|
||||||
char *search;
|
char *search;
|
||||||
@@ -83,6 +89,7 @@ struct mode_tree_data {
|
|||||||
int no_matches;
|
int no_matches;
|
||||||
enum mode_tree_search_dir search_dir;
|
enum mode_tree_search_dir search_dir;
|
||||||
int search_icase;
|
int search_icase;
|
||||||
|
int help;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mode_tree_item {
|
struct mode_tree_item {
|
||||||
@@ -122,7 +129,25 @@ struct mode_tree_menu {
|
|||||||
u_int line;
|
u_int line;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void mode_tree_free_items(struct mode_tree_list *);
|
/*
|
||||||
|
* Wrapper around a prompt owned by a mode tree. The mode tree holds a reference
|
||||||
|
* while the prompt is alive; the wrapper callbacks forward to the caller's
|
||||||
|
* callbacks and drop that reference when the prompt is freed.
|
||||||
|
*/
|
||||||
|
struct mode_tree_prompt {
|
||||||
|
struct mode_tree_data *mtd;
|
||||||
|
struct client *c;
|
||||||
|
mode_tree_prompt_input_cb inputcb;
|
||||||
|
prompt_free_cb freecb;
|
||||||
|
void *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void mode_tree_free_items(struct mode_tree_list *);
|
||||||
|
static void mode_tree_draw_help(struct mode_tree_data *,
|
||||||
|
struct screen_write_ctx *);
|
||||||
|
static void mode_tree_draw_prompt(struct mode_tree_data *,
|
||||||
|
struct screen_write_ctx *);
|
||||||
|
static enum cmd_retval mode_tree_prompt_accept(struct cmdq_item *, void *);
|
||||||
|
|
||||||
static const struct menu_item mode_tree_menu_items[] = {
|
static const struct menu_item mode_tree_menu_items[] = {
|
||||||
{ "Scroll Left", '<', NULL },
|
{ "Scroll Left", '<', NULL },
|
||||||
@@ -134,31 +159,31 @@ static const struct menu_item mode_tree_menu_items[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const char* mode_tree_help_start[] = {
|
static const char* mode_tree_help_start[] = {
|
||||||
"\r\033[1m Up, k \033[0m\016x\017 \033[0mMove cursor up\n",
|
"#[bold] Up, k #[default]#[acs]x#[default] Move cursor up",
|
||||||
"\r\033[1m Down, j \033[0m\016x\017 \033[0mMove cursor down\n",
|
"#[bold] Down, j #[default]#[acs]x#[default] Move cursor down",
|
||||||
"\r\033[1m g \033[0m\016x\017 \033[0mGo to top\n",
|
"#[bold] g #[default]#[acs]x#[default] Go to top",
|
||||||
"\r\033[1m G \033[0m\016x\017 \033[0mGo to bottom\n",
|
"#[bold] G #[default]#[acs]x#[default] Go to bottom",
|
||||||
"\r\033[1m PPage, C-b \033[0m\016x\017 \033[0mPage up\n",
|
"#[bold] PPage, C-b #[default]#[acs]x#[default] Page up",
|
||||||
"\r\033[1m NPage, C-f \033[0m\016x\017 \033[0mPage down\n",
|
"#[bold] NPage, C-f #[default]#[acs]x#[default] Page down",
|
||||||
"\r\033[1m Left, h \033[0m\016x\017 \033[0mCollapse %1\n",
|
"#[bold] Left, h #[default]#[acs]x#[default] Collapse %1",
|
||||||
"\r\033[1m Right, l \033[0m\016x\017 \033[0mExpand %1\n",
|
"#[bold] Right, l #[default]#[acs]x#[default] Expand %1",
|
||||||
"\r\033[1m M-- \033[0m\016x\017 \033[0mCollapse all %1s\n",
|
"#[bold] M-- #[default]#[acs]x#[default] Collapse all %1s",
|
||||||
"\r\033[1m M-+ \033[0m\016x\017 \033[0mExpand all %1s\n",
|
"#[bold] M-+ #[default]#[acs]x#[default] Expand all %1s",
|
||||||
"\r\033[1m t \033[0m\016x\017 \033[0mToggle %1 tag\n",
|
"#[bold] t #[default]#[acs]x#[default] Toggle %1 tag",
|
||||||
"\r\033[1m T \033[0m\016x\017 \033[0mUntag all %1s\n",
|
"#[bold] T #[default]#[acs]x#[default] Untag all %1s",
|
||||||
"\r\033[1m C-t \033[0m\016x\017 \033[0mTag all %1s\n",
|
"#[bold] C-t #[default]#[acs]x#[default] Tag all %1s",
|
||||||
"\r\033[1m C-s \033[0m\016x\017 \033[0mSearch forward\n",
|
"#[bold] C-s #[default]#[acs]x#[default] Search forward",
|
||||||
"\r\033[1m C-r \033[0m\016x\017 \033[0mSearch backward\n",
|
"#[bold] C-r #[default]#[acs]x#[default] Search backward",
|
||||||
"\r\033[1m n \033[0m\016x\017 \033[0mRepeat search forward\n",
|
"#[bold] n #[default]#[acs]x#[default] Repeat search forward",
|
||||||
"\r\033[1m N \033[0m\016x\017 \033[0mRepeat search backward\n",
|
"#[bold] N #[default]#[acs]x#[default] Repeat search backward",
|
||||||
"\r\033[1m f \033[0m\016x\017 \033[0mFilter %1s\n",
|
"#[bold] f #[default]#[acs]x#[default] Filter %1s",
|
||||||
"\r\033[1m O \033[0m\016x\017 \033[0mChange sort order\n",
|
"#[bold] O #[default]#[acs]x#[default] Change sort order",
|
||||||
"\r\033[1m r \033[0m\016x\017 \033[0mReverse sort order\n",
|
"#[bold] r #[default]#[acs]x#[default] Reverse sort order",
|
||||||
"\r\033[1m v \033[0m\016x\017 \033[0mToggle preview\n",
|
"#[bold] v #[default]#[acs]x#[default] Toggle preview",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
static const char* mode_tree_help_end[] = {
|
static const char* mode_tree_help_end[] = {
|
||||||
"\r\033[1m q, Escape \033[0m\016x\017 \033[0mExit mode\033[H",
|
"#[bold] q, Escape #[default]#[acs]x#[default] Exit mode",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
#define MODE_TREE_HELP_DEFAULT_WIDTH 39
|
#define MODE_TREE_HELP_DEFAULT_WIDTH 39
|
||||||
@@ -378,6 +403,13 @@ mode_tree_get_current_name(struct mode_tree_data *mtd)
|
|||||||
return (mtd->line_list[mtd->current].item->name);
|
return (mtd->line_list[mtd->current].item->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mode_tree_select_top(struct mode_tree_data *mtd)
|
||||||
|
{
|
||||||
|
mtd->current = 0;
|
||||||
|
mtd->offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
mode_tree_expand_current(struct mode_tree_data *mtd)
|
mode_tree_expand_current(struct mode_tree_data *mtd)
|
||||||
{
|
{
|
||||||
@@ -505,7 +537,9 @@ mode_tree_start(struct window_pane *wp, struct args *args,
|
|||||||
mtd->modedata = modedata;
|
mtd->modedata = modedata;
|
||||||
mtd->menu = menu;
|
mtd->menu = menu;
|
||||||
|
|
||||||
if (args_has(args, 'N') > 1)
|
if (drawcb == NULL)
|
||||||
|
mtd->preview = MODE_TREE_PREVIEW_OFF;
|
||||||
|
else if (args_has(args, 'N') > 1)
|
||||||
mtd->preview = MODE_TREE_PREVIEW_BIG;
|
mtd->preview = MODE_TREE_PREVIEW_BIG;
|
||||||
else if (args_has(args, 'N'))
|
else if (args_has(args, 'N'))
|
||||||
mtd->preview = MODE_TREE_PREVIEW_OFF;
|
mtd->preview = MODE_TREE_PREVIEW_OFF;
|
||||||
@@ -637,6 +671,7 @@ mode_tree_free(struct mode_tree_data *mtd)
|
|||||||
if (mtd->zoomed == 0)
|
if (mtd->zoomed == 0)
|
||||||
server_unzoom_window(wp->window);
|
server_unzoom_window(wp->window);
|
||||||
|
|
||||||
|
mode_tree_clear_prompt(mtd);
|
||||||
mode_tree_free_items(&mtd->children);
|
mode_tree_free_items(&mtd->children);
|
||||||
mode_tree_clear_lines(mtd);
|
mode_tree_clear_lines(mtd);
|
||||||
screen_free(&mtd->screen);
|
screen_free(&mtd->screen);
|
||||||
@@ -700,6 +735,12 @@ mode_tree_add(struct mode_tree_data *mtd, struct mode_tree_item *parent,
|
|||||||
return (mti);
|
return (mti);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mode_tree_view_name(struct mode_tree_data *mtd, const char *name)
|
||||||
|
{
|
||||||
|
mtd->view_name = name;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
mode_tree_draw_as_parent(struct mode_tree_item *mti)
|
mode_tree_draw_as_parent(struct mode_tree_item *mti)
|
||||||
{
|
{
|
||||||
@@ -884,9 +925,12 @@ mode_tree_draw(struct mode_tree_data *mtd)
|
|||||||
screen_write_box(&ctx, w, sy - h, BOX_LINES_DEFAULT, NULL, NULL);
|
screen_write_box(&ctx, w, sy - h, BOX_LINES_DEFAULT, NULL, NULL);
|
||||||
|
|
||||||
if (mtd->sort_crit.order_seq != NULL) {
|
if (mtd->sort_crit.order_seq != NULL) {
|
||||||
xasprintf(&text, " %s (sort: %s%s)", mti->name,
|
xasprintf(&text, " %s (sort: %s%s)%s%s%s", mti->name,
|
||||||
sort_order_to_string(mtd->sort_crit.order),
|
sort_order_to_string(mtd->sort_crit.order),
|
||||||
mtd->sort_crit.reversed ? ", reversed" : "");
|
mtd->sort_crit.reversed ? ", reversed" : "",
|
||||||
|
mtd->view_name == NULL ? "" : " (view: ",
|
||||||
|
mtd->view_name == NULL ? "" : mtd->view_name,
|
||||||
|
mtd->view_name == NULL ? "" : ")");
|
||||||
} else
|
} else
|
||||||
xasprintf(&text, " %s", mti->name);
|
xasprintf(&text, " %s", mti->name);
|
||||||
if (w - 2 >= strlen(text)) {
|
if (w - 2 >= strlen(text)) {
|
||||||
@@ -918,10 +962,150 @@ mode_tree_draw(struct mode_tree_data *mtd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
screen_write_cursormove(&ctx, 0, mtd->current - mtd->offset, 0);
|
if (mtd->help)
|
||||||
|
mode_tree_draw_help(mtd, &ctx);
|
||||||
|
if (mtd->prompt != NULL)
|
||||||
|
mode_tree_draw_prompt(mtd, &ctx);
|
||||||
|
else {
|
||||||
|
s->mode &= ~MODE_CURSOR;
|
||||||
|
screen_write_cursormove(&ctx, 0, mtd->current - mtd->offset, 0);
|
||||||
|
}
|
||||||
screen_write_stop(&ctx);
|
screen_write_stop(&ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mode_tree_draw_prompt(struct mode_tree_data *mtd, struct screen_write_ctx *ctx)
|
||||||
|
{
|
||||||
|
struct screen *s = &mtd->screen;
|
||||||
|
struct prompt_draw_data pdd;
|
||||||
|
u_int sx = screen_size_x(s), sy = screen_size_y(s);
|
||||||
|
u_int py;
|
||||||
|
|
||||||
|
if (sx == 0 || sy == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (mtd->prompt_top)
|
||||||
|
py = 0;
|
||||||
|
else
|
||||||
|
py = sy - 1;
|
||||||
|
|
||||||
|
pdd.ctx = ctx;
|
||||||
|
pdd.cursor_x = &mtd->prompt_cx;
|
||||||
|
pdd.area_x = 0;
|
||||||
|
pdd.area_width = sx;
|
||||||
|
pdd.prompt_line = py;
|
||||||
|
|
||||||
|
s->mode |= MODE_CURSOR;
|
||||||
|
prompt_draw(mtd->prompt, &pdd);
|
||||||
|
screen_write_cursormove(ctx, mtd->prompt_cx, py, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mode_tree_clear_prompt(struct mode_tree_data *mtd)
|
||||||
|
{
|
||||||
|
struct prompt *prompt = mtd->prompt;
|
||||||
|
|
||||||
|
if (mtd->prompt != NULL) {
|
||||||
|
mtd->prompt = NULL;
|
||||||
|
prompt_free(prompt);
|
||||||
|
mtd->screen.mode &= ~MODE_CURSOR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
mode_tree_has_prompt(struct mode_tree_data *mtd)
|
||||||
|
{
|
||||||
|
return (mtd->prompt != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum cmd_retval
|
||||||
|
mode_tree_prompt_accept(struct cmdq_item *item, void *data)
|
||||||
|
{
|
||||||
|
struct mode_tree_data *mtd = data;
|
||||||
|
struct client *c = cmdq_get_client(item);
|
||||||
|
key_code key = 'y';
|
||||||
|
|
||||||
|
if (mtd->prompt != NULL && c != NULL)
|
||||||
|
mode_tree_key(mtd, c, &key, NULL, NULL, NULL);
|
||||||
|
|
||||||
|
mode_tree_remove_ref(mtd);
|
||||||
|
return (CMD_RETURN_NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum prompt_result
|
||||||
|
mode_tree_prompt_input_callback(void *data, const char *s,
|
||||||
|
enum prompt_key_result key)
|
||||||
|
{
|
||||||
|
struct mode_tree_prompt *mtp = data;
|
||||||
|
|
||||||
|
if (mtp->inputcb != NULL)
|
||||||
|
return (mtp->inputcb(mtp->c, mtp->data, s, key));
|
||||||
|
return (PROMPT_CLOSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mode_tree_prompt_free_callback(void *data)
|
||||||
|
{
|
||||||
|
struct mode_tree_prompt *mtp = data;
|
||||||
|
|
||||||
|
if (mtp->mtd->prompt_data == mtp)
|
||||||
|
mtp->mtd->prompt_data = NULL;
|
||||||
|
if (mtp->freecb != NULL)
|
||||||
|
mtp->freecb(mtp->data);
|
||||||
|
mode_tree_remove_ref(mtp->mtd);
|
||||||
|
free(mtp);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mode_tree_set_prompt(struct mode_tree_data *mtd, struct client *c,
|
||||||
|
const char *prompt, const char *input, enum prompt_type type, int flags,
|
||||||
|
mode_tree_prompt_input_cb inputcb, prompt_free_cb freecb, void *data)
|
||||||
|
{
|
||||||
|
struct session *s;
|
||||||
|
struct options *oo;
|
||||||
|
struct prompt_create_data pd;
|
||||||
|
struct mode_tree_prompt *mtp;
|
||||||
|
|
||||||
|
if (c != NULL && c->session != NULL) {
|
||||||
|
s = c->session;
|
||||||
|
oo = s->options;
|
||||||
|
} else {
|
||||||
|
s = NULL;
|
||||||
|
oo = global_s_options;
|
||||||
|
}
|
||||||
|
|
||||||
|
mode_tree_clear_prompt(mtd);
|
||||||
|
|
||||||
|
mtp = xcalloc(1, sizeof *mtp);
|
||||||
|
mtp->mtd = mtd;
|
||||||
|
mtp->inputcb = inputcb;
|
||||||
|
mtp->freecb = freecb;
|
||||||
|
mtp->data = data;
|
||||||
|
|
||||||
|
mtd->references++;
|
||||||
|
mtd->prompt_top = options_get_number(oo, "status-position") == 0;
|
||||||
|
|
||||||
|
memset(&pd, 0, sizeof pd);
|
||||||
|
prompt_set_options(&pd, s);
|
||||||
|
pd.prompt = prompt;
|
||||||
|
pd.input = input;
|
||||||
|
pd.type = type;
|
||||||
|
pd.flags = flags|PROMPT_ISMODE;
|
||||||
|
pd.inputcb = mode_tree_prompt_input_callback;
|
||||||
|
pd.freecb = mode_tree_prompt_free_callback;
|
||||||
|
pd.data = mtp;
|
||||||
|
mtd->prompt = prompt_create(&pd);
|
||||||
|
mtd->prompt_data = mtp;
|
||||||
|
|
||||||
|
mode_tree_draw(mtd);
|
||||||
|
mtd->wp->flags |= PANE_REDRAW;
|
||||||
|
|
||||||
|
if ((flags & PROMPT_SINGLE) && (flags & PROMPT_ACCEPT) && c != NULL) {
|
||||||
|
mtd->references++;
|
||||||
|
cmdq_append(c, cmdq_get_callback(mode_tree_prompt_accept, mtd));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static struct mode_tree_item *
|
static struct mode_tree_item *
|
||||||
mode_tree_search_backward(struct mode_tree_data *mtd)
|
mode_tree_search_backward(struct mode_tree_data *mtd)
|
||||||
{
|
{
|
||||||
@@ -1042,41 +1226,37 @@ mode_tree_search_set(struct mode_tree_data *mtd)
|
|||||||
mtd->wp->flags |= PANE_REDRAW;
|
mtd->wp->flags |= PANE_REDRAW;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static enum prompt_result
|
||||||
mode_tree_search_callback(__unused struct client *c, void *data, const char *s,
|
mode_tree_search_callback(__unused struct client *c, void *data, const char *s,
|
||||||
__unused int done)
|
enum prompt_key_result key)
|
||||||
{
|
{
|
||||||
struct mode_tree_data *mtd = data;
|
struct mode_tree_data *mtd = data;
|
||||||
|
|
||||||
if (mtd->dead)
|
if (mtd->dead)
|
||||||
return (0);
|
return (PROMPT_CLOSE);
|
||||||
|
|
||||||
free(mtd->search);
|
free(mtd->search);
|
||||||
if (s == NULL || *s == '\0') {
|
if (s == NULL || *s == '\0')
|
||||||
mtd->search = NULL;
|
mtd->search = NULL;
|
||||||
return (0);
|
else {
|
||||||
|
mtd->search = xstrdup(s);
|
||||||
|
mtd->search_icase = mode_tree_is_lowercase(s);
|
||||||
|
mode_tree_search_set(mtd);
|
||||||
}
|
}
|
||||||
mtd->search = xstrdup(s);
|
|
||||||
mtd->search_icase = mode_tree_is_lowercase(s);
|
|
||||||
mode_tree_search_set(mtd);
|
|
||||||
|
|
||||||
return (0);
|
if (key == PROMPT_KEY_HANDLED)
|
||||||
|
return (PROMPT_CONTINUE);
|
||||||
|
return (PROMPT_CLOSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static enum prompt_result
|
||||||
mode_tree_search_free(void *data)
|
|
||||||
{
|
|
||||||
mode_tree_remove_ref(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
mode_tree_filter_callback(__unused struct client *c, void *data, const char *s,
|
mode_tree_filter_callback(__unused struct client *c, void *data, const char *s,
|
||||||
__unused int done)
|
enum prompt_key_result key)
|
||||||
{
|
{
|
||||||
struct mode_tree_data *mtd = data;
|
struct mode_tree_data *mtd = data;
|
||||||
|
|
||||||
if (mtd->dead)
|
if (mtd->dead)
|
||||||
return (0);
|
return (PROMPT_CLOSE);
|
||||||
|
|
||||||
if (mtd->filter != NULL)
|
if (mtd->filter != NULL)
|
||||||
free(mtd->filter);
|
free(mtd->filter);
|
||||||
@@ -1089,13 +1269,20 @@ mode_tree_filter_callback(__unused struct client *c, void *data, const char *s,
|
|||||||
mode_tree_draw(mtd);
|
mode_tree_draw(mtd);
|
||||||
mtd->wp->flags |= PANE_REDRAW;
|
mtd->wp->flags |= PANE_REDRAW;
|
||||||
|
|
||||||
return (0);
|
if (key == PROMPT_KEY_HANDLED)
|
||||||
|
return (PROMPT_CONTINUE);
|
||||||
|
return (PROMPT_CLOSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
mode_tree_filter_free(void *data)
|
mode_tree_clear_filter(struct mode_tree_data *mtd)
|
||||||
{
|
{
|
||||||
mode_tree_remove_ref(data);
|
free(mtd->filter);
|
||||||
|
mtd->filter = NULL;
|
||||||
|
|
||||||
|
mode_tree_build(mtd);
|
||||||
|
mode_tree_draw(mtd);
|
||||||
|
mtd->wp->flags |= PANE_REDRAW;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -1165,12 +1352,28 @@ mode_tree_display_menu(struct mode_tree_data *mtd, struct client *c, u_int x,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
mode_tree_display_help(__unused struct mode_tree_data *mtd, struct client *c)
|
mode_tree_draw_help_line(struct screen_write_ctx *ctx,
|
||||||
|
const struct grid_cell *gc, const char *line, const char *item, u_int x,
|
||||||
|
u_int y, u_int w)
|
||||||
{
|
{
|
||||||
struct session *s = c->session;
|
char *expanded;
|
||||||
u_int px, py, w, h = 0;
|
|
||||||
const char **line, **lines = NULL, *item = "item";
|
expanded = cmd_template_replace(line, item, 1);
|
||||||
char *new_line;
|
screen_write_cursormove(ctx, x, y, 0);
|
||||||
|
screen_write_clearcharacter(ctx, w, gc->bg);
|
||||||
|
screen_write_cursormove(ctx, x, y, 0);
|
||||||
|
format_draw(ctx, gc, w, expanded, NULL, 0);
|
||||||
|
free(expanded);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mode_tree_draw_help(struct mode_tree_data *mtd, struct screen_write_ctx *ctx)
|
||||||
|
{
|
||||||
|
struct screen *s = &mtd->screen;
|
||||||
|
struct grid_cell gc;
|
||||||
|
const char **line, **lines = NULL, *item = "item";
|
||||||
|
u_int sx = screen_size_x(s), sy = screen_size_y(s);
|
||||||
|
u_int x, y, w, h = 0, box_w, box_h;
|
||||||
|
|
||||||
if (mtd->helpcb == NULL)
|
if (mtd->helpcb == NULL)
|
||||||
w = MODE_TREE_HELP_DEFAULT_WIDTH;
|
w = MODE_TREE_HELP_DEFAULT_WIDTH;
|
||||||
@@ -1186,33 +1389,32 @@ mode_tree_display_help(__unused struct mode_tree_data *mtd, struct client *c)
|
|||||||
for (line = mode_tree_help_end; *line != NULL; line++)
|
for (line = mode_tree_help_end; *line != NULL; line++)
|
||||||
h++;
|
h++;
|
||||||
|
|
||||||
if (c->tty.sx < w || c->tty.sy < h)
|
box_w = w + 2;
|
||||||
|
box_h = h + 2;
|
||||||
|
if (sx < box_w || sy < box_h)
|
||||||
return;
|
return;
|
||||||
px = (c->tty.sx - w) / 2;
|
x = (sx - box_w) / 2;
|
||||||
py = (c->tty.sy - h) / 2;
|
y = (sy - box_h) / 2;
|
||||||
|
|
||||||
if (popup_display(POPUP_CLOSEANYKEY|POPUP_NOJOB, BOX_LINES_DEFAULT,
|
memcpy(&gc, &grid_default_cell, sizeof gc);
|
||||||
NULL, px, py, w, h, NULL, NULL, 0, NULL, NULL, NULL, c, s, NULL,
|
screen_write_cursormove(ctx, x, y, 0);
|
||||||
NULL, NULL, NULL) != 0)
|
screen_write_box(ctx, box_w, box_h, BOX_LINES_DEFAULT, &gc, NULL);
|
||||||
return;
|
|
||||||
|
|
||||||
popup_write(c, "\033[H\033[?25l\033[?7l\033)0", 17);
|
y++;
|
||||||
for (line = mode_tree_help_start; *line != NULL; line++) {
|
x++;
|
||||||
new_line = cmd_template_replace(*line, item, 1);
|
for (line = mode_tree_help_start; *line != NULL; line++, y++)
|
||||||
popup_write(c, new_line, strlen(new_line));
|
mode_tree_draw_help_line(ctx, &gc, *line, item, x, y, w);
|
||||||
free(new_line);
|
for (line = lines; line != NULL && *line != NULL; line++, y++)
|
||||||
}
|
mode_tree_draw_help_line(ctx, &gc, *line, item, x, y, w);
|
||||||
for (line = lines; line != NULL && *line != NULL; line++) {
|
for (line = mode_tree_help_end; *line != NULL; line++, y++)
|
||||||
new_line = cmd_template_replace(*line, item, 1);
|
mode_tree_draw_help_line(ctx, &gc, *line, item, x, y, w);
|
||||||
popup_write(c, new_line, strlen(new_line));
|
}
|
||||||
free(new_line);
|
|
||||||
}
|
static void
|
||||||
for (line = mode_tree_help_end; *line != NULL; line++) {
|
mode_tree_display_help(struct mode_tree_data *mtd)
|
||||||
new_line = cmd_template_replace(*line, item, 1);
|
{
|
||||||
popup_write(c, new_line, strlen(new_line));
|
mtd->help = 1;
|
||||||
free(new_line);
|
mode_tree_draw(mtd);
|
||||||
}
|
|
||||||
popup_write(c, "\033[H", 3);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -1221,14 +1423,77 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
|
|||||||
{
|
{
|
||||||
struct mode_tree_line *line;
|
struct mode_tree_line *line;
|
||||||
struct mode_tree_item *current, *parent, *mti;
|
struct mode_tree_item *current, *parent, *mti;
|
||||||
u_int i, x, y;
|
u_int i, x, y, py, sx;
|
||||||
int choice, preview;
|
int choice, preview;
|
||||||
|
enum prompt_key_result result;
|
||||||
|
int redraw;
|
||||||
|
struct prompt *prompt;
|
||||||
|
struct mode_tree_prompt *mtp;
|
||||||
|
|
||||||
if (mtd->line_size == 0) {
|
if (mtd->line_size == 0) {
|
||||||
*key = KEYC_NONE;
|
*key = KEYC_NONE;
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mtd->prompt != NULL) {
|
||||||
|
redraw = 0;
|
||||||
|
prompt = mtd->prompt;
|
||||||
|
|
||||||
|
mtp = mtd->prompt_data;
|
||||||
|
if (mtp != NULL)
|
||||||
|
mtp->c = c;
|
||||||
|
if (KEYC_IS_MOUSE(*key)) {
|
||||||
|
if (m == NULL ||
|
||||||
|
MOUSE_BUTTONS(m->b) != MOUSE_BUTTON_1 ||
|
||||||
|
MOUSE_DRAG(m->b) || MOUSE_RELEASE(m->b) ||
|
||||||
|
cmd_mouse_at(mtd->wp, m, &x, &y, 0) != 0)
|
||||||
|
result = PROMPT_KEY_NOT_HANDLED;
|
||||||
|
else {
|
||||||
|
sx = screen_size_x(&mtd->screen);
|
||||||
|
if (mtd->prompt_top)
|
||||||
|
py = 0;
|
||||||
|
else
|
||||||
|
py = screen_size_y(&mtd->screen) - 1;
|
||||||
|
if (y == py) {
|
||||||
|
result = prompt_mouse(prompt, x, 0, sx,
|
||||||
|
&redraw);
|
||||||
|
} else
|
||||||
|
result = PROMPT_KEY_NOT_HANDLED;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
result = prompt_key(prompt, *key, &redraw);
|
||||||
|
if (mtd->prompt_data == mtp && mtp != NULL)
|
||||||
|
mtp->c = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Only an explicit close or the prompt marking itself closed
|
||||||
|
* ends it; cursor movement and editing keep it open.
|
||||||
|
*/
|
||||||
|
if (mtd->prompt == prompt &&
|
||||||
|
(result == PROMPT_KEY_CLOSE || prompt_closed(prompt)))
|
||||||
|
mode_tree_clear_prompt(mtd);
|
||||||
|
|
||||||
|
if (redraw || mtd->prompt != prompt) {
|
||||||
|
mode_tree_draw(mtd);
|
||||||
|
mtd->wp->flags |= PANE_REDRAW;
|
||||||
|
}
|
||||||
|
if (result != PROMPT_KEY_NOT_HANDLED) {
|
||||||
|
*key = KEYC_NONE;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mtd->help) {
|
||||||
|
if (KEYC_IS_MOUSE(*key)) {
|
||||||
|
*key = KEYC_NONE;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
mtd->help = 0;
|
||||||
|
mode_tree_draw(mtd);
|
||||||
|
*key = KEYC_NONE;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
if (KEYC_IS_MOUSE(*key) && m != NULL) {
|
if (KEYC_IS_MOUSE(*key) && m != NULL) {
|
||||||
if (cmd_mouse_at(mtd->wp, m, &x, &y, 0) != 0) {
|
if (cmd_mouse_at(mtd->wp, m, &x, &y, 0) != 0) {
|
||||||
*key = KEYC_NONE;
|
*key = KEYC_NONE;
|
||||||
@@ -1294,7 +1559,7 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
|
|||||||
return (1);
|
return (1);
|
||||||
case KEYC_F1:
|
case KEYC_F1:
|
||||||
case 'h'|KEYC_CTRL:
|
case 'h'|KEYC_CTRL:
|
||||||
mode_tree_display_help(mtd, c);
|
mode_tree_display_help(mtd);
|
||||||
break;
|
break;
|
||||||
case KEYC_UP:
|
case KEYC_UP:
|
||||||
case 'k':
|
case 'k':
|
||||||
@@ -1424,11 +1689,10 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
|
|||||||
case '?':
|
case '?':
|
||||||
case '/':
|
case '/':
|
||||||
case 's'|KEYC_CTRL:
|
case 's'|KEYC_CTRL:
|
||||||
mtd->references++;
|
|
||||||
mtd->search_dir = MODE_TREE_SEARCH_FORWARD;
|
mtd->search_dir = MODE_TREE_SEARCH_FORWARD;
|
||||||
status_prompt_set(c, NULL, "(search) ", "",
|
mode_tree_set_prompt(mtd, c, "(search) ", "",
|
||||||
mode_tree_search_callback, mode_tree_search_free, mtd,
|
PROMPT_TYPE_SEARCH, PROMPT_NOFORMAT,
|
||||||
PROMPT_NOFORMAT, PROMPT_TYPE_SEARCH);
|
mode_tree_search_callback, NULL, mtd);
|
||||||
break;
|
break;
|
||||||
case 'n':
|
case 'n':
|
||||||
mtd->search_dir = MODE_TREE_SEARCH_FORWARD;
|
mtd->search_dir = MODE_TREE_SEARCH_FORWARD;
|
||||||
@@ -1439,10 +1703,13 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
|
|||||||
mode_tree_search_set(mtd);
|
mode_tree_search_set(mtd);
|
||||||
break;
|
break;
|
||||||
case 'f':
|
case 'f':
|
||||||
mtd->references++;
|
mode_tree_set_prompt(mtd, c, "(filter) ", mtd->filter,
|
||||||
status_prompt_set(c, NULL, "(filter) ", mtd->filter,
|
PROMPT_TYPE_SEARCH, PROMPT_NOFORMAT,
|
||||||
mode_tree_filter_callback, mode_tree_filter_free, mtd,
|
mode_tree_filter_callback, NULL, mtd);
|
||||||
PROMPT_NOFORMAT, PROMPT_TYPE_SEARCH);
|
break;
|
||||||
|
case 'c':
|
||||||
|
mode_tree_clear_prompt(mtd);
|
||||||
|
mode_tree_clear_filter(mtd);
|
||||||
break;
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
switch (mtd->preview) {
|
switch (mtd->preview) {
|
||||||
|
|||||||
4
names.c
4
names.c
@@ -95,7 +95,7 @@ check_window_name(struct window *w)
|
|||||||
name = format_window_name(w);
|
name = format_window_name(w);
|
||||||
if (strcmp(name, w->name) != 0) {
|
if (strcmp(name, w->name) != 0) {
|
||||||
log_debug("@%u new name %s (was %s)", w->id, name, w->name);
|
log_debug("@%u new name %s (was %s)", w->id, name, w->name);
|
||||||
window_set_name(w, name);
|
window_set_name(w, name, WINDOW_NAME_FORBID_EXT);
|
||||||
server_redraw_window_borders(w);
|
server_redraw_window_borders(w);
|
||||||
server_status_window(w);
|
server_status_window(w);
|
||||||
} else
|
} else
|
||||||
@@ -166,7 +166,7 @@ parse_window_name(const char *in)
|
|||||||
|
|
||||||
if (*name == '/')
|
if (*name == '/')
|
||||||
name = basename(name);
|
name = basename(name);
|
||||||
name = clean_name(name, "#");
|
name = clean_name(name, WINDOW_NAME_FORBID);
|
||||||
free(copy);
|
free(copy);
|
||||||
if (name == NULL)
|
if (name == NULL)
|
||||||
return (xstrdup(""));
|
return (xstrdup(""));
|
||||||
|
|||||||
@@ -70,13 +70,13 @@ static const char *options_table_pane_scrollbars_position_list[] = {
|
|||||||
"right", "left", NULL
|
"right", "left", NULL
|
||||||
};
|
};
|
||||||
static const char *options_table_pane_status_list[] = {
|
static const char *options_table_pane_status_list[] = {
|
||||||
"off", "top", "bottom", NULL
|
"off", "top", "bottom", "top-floating", "bottom-floating", NULL
|
||||||
};
|
};
|
||||||
static const char *options_table_pane_border_indicators_list[] = {
|
static const char *options_table_pane_border_indicators_list[] = {
|
||||||
"off", "colour", "arrows", "both", NULL
|
"off", "colour", "arrows", "both", NULL
|
||||||
};
|
};
|
||||||
static const char *options_table_pane_border_lines_list[] = {
|
static const char *options_table_pane_border_lines_list[] = {
|
||||||
"single", "double", "heavy", "simple", "number", "spaces", NULL
|
"single", "double", "heavy", "simple", "number", "spaces", "none", NULL
|
||||||
};
|
};
|
||||||
static const char *options_table_popup_border_lines_list[] = {
|
static const char *options_table_popup_border_lines_list[] = {
|
||||||
"single", "double", "heavy", "simple", "rounded", "padded", "none", NULL
|
"single", "double", "heavy", "simple", "rounded", "padded", "none", NULL
|
||||||
@@ -327,9 +327,10 @@ const struct options_table_entry options_table[] = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
{ .name = "cursor-colour",
|
{ .name = "cursor-colour",
|
||||||
.type = OPTIONS_TABLE_COLOUR,
|
.type = OPTIONS_TABLE_STRING,
|
||||||
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
|
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
|
||||||
.default_num = -1,
|
.flags = OPTIONS_TABLE_IS_COLOUR,
|
||||||
|
.default_str = "",
|
||||||
.text = "Colour of the cursor."
|
.text = "Colour of the cursor."
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -634,19 +635,29 @@ const struct options_table_entry options_table[] = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
{ .name = "display-panes-active-colour",
|
{ .name = "display-panes-active-colour",
|
||||||
.type = OPTIONS_TABLE_COLOUR,
|
.type = OPTIONS_TABLE_STRING,
|
||||||
.scope = OPTIONS_TABLE_SESSION,
|
.scope = OPTIONS_TABLE_SESSION,
|
||||||
.default_num = 1,
|
.flags = OPTIONS_TABLE_IS_COLOUR,
|
||||||
|
.default_str = "red",
|
||||||
.text = "Colour of the active pane for 'display-panes'."
|
.text = "Colour of the active pane for 'display-panes'."
|
||||||
},
|
},
|
||||||
|
|
||||||
{ .name = "display-panes-colour",
|
{ .name = "display-panes-colour",
|
||||||
.type = OPTIONS_TABLE_COLOUR,
|
.type = OPTIONS_TABLE_STRING,
|
||||||
.scope = OPTIONS_TABLE_SESSION,
|
.scope = OPTIONS_TABLE_SESSION,
|
||||||
.default_num = 4,
|
.flags = OPTIONS_TABLE_IS_COLOUR,
|
||||||
|
.default_str = "blue",
|
||||||
.text = "Colour of not active panes for 'display-panes'."
|
.text = "Colour of not active panes for 'display-panes'."
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{ .name = "display-panes-format",
|
||||||
|
.type = OPTIONS_TABLE_STRING,
|
||||||
|
.scope = OPTIONS_TABLE_SESSION,
|
||||||
|
.default_str = "#[align=right]#{pane_width}x#{pane_height}",
|
||||||
|
.text = "Format of text shown by 'display-panes', expanded for each "
|
||||||
|
"pane."
|
||||||
|
},
|
||||||
|
|
||||||
{ .name = "display-panes-time",
|
{ .name = "display-panes-time",
|
||||||
.type = OPTIONS_TABLE_NUMBER,
|
.type = OPTIONS_TABLE_NUMBER,
|
||||||
.scope = OPTIONS_TABLE_SESSION,
|
.scope = OPTIONS_TABLE_SESSION,
|
||||||
@@ -730,7 +741,7 @@ const struct options_table_entry options_table[] = {
|
|||||||
.flags = OPTIONS_TABLE_IS_STYLE,
|
.flags = OPTIONS_TABLE_IS_STYLE,
|
||||||
.separator = ",",
|
.separator = ",",
|
||||||
.text = "Style of the command prompt when in command mode, if "
|
.text = "Style of the command prompt when in command mode, if "
|
||||||
"'mode-keys' is set to 'vi'."
|
"'status-keys' is set to 'vi'."
|
||||||
},
|
},
|
||||||
|
|
||||||
{ .name = "message-format",
|
{ .name = "message-format",
|
||||||
@@ -755,7 +766,9 @@ const struct options_table_entry options_table[] = {
|
|||||||
{ .name = "message-style",
|
{ .name = "message-style",
|
||||||
.type = OPTIONS_TABLE_STRING,
|
.type = OPTIONS_TABLE_STRING,
|
||||||
.scope = OPTIONS_TABLE_SESSION,
|
.scope = OPTIONS_TABLE_SESSION,
|
||||||
.default_str = "bg=yellow,fg=black,fill=yellow",
|
.default_str = "bg=yellow,fg=black,"
|
||||||
|
"#{?#{m/r:(^|#,)IS(PANE|MODE)($|#,),#{prompt_flags}},,"
|
||||||
|
"fill=yellow}",
|
||||||
.flags = OPTIONS_TABLE_IS_STYLE,
|
.flags = OPTIONS_TABLE_IS_STYLE,
|
||||||
.separator = ",",
|
.separator = ",",
|
||||||
.text = "Style of messages and the command prompt. "
|
.text = "Style of messages and the command prompt. "
|
||||||
@@ -980,9 +993,10 @@ const struct options_table_entry options_table[] = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
{ .name = "prompt-cursor-colour",
|
{ .name = "prompt-cursor-colour",
|
||||||
.type = OPTIONS_TABLE_COLOUR,
|
.type = OPTIONS_TABLE_STRING,
|
||||||
.scope = OPTIONS_TABLE_SESSION,
|
.scope = OPTIONS_TABLE_SESSION,
|
||||||
.default_num = -1,
|
.flags = OPTIONS_TABLE_IS_COLOUR,
|
||||||
|
.default_str = "",
|
||||||
.text = "Colour of the cursor when in the command prompt."
|
.text = "Colour of the cursor when in the command prompt."
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -1134,9 +1148,10 @@ const struct options_table_entry options_table[] = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
{ .name = "clock-mode-colour",
|
{ .name = "clock-mode-colour",
|
||||||
.type = OPTIONS_TABLE_COLOUR,
|
.type = OPTIONS_TABLE_STRING,
|
||||||
.scope = OPTIONS_TABLE_WINDOW,
|
.scope = OPTIONS_TABLE_WINDOW,
|
||||||
.default_num = 4,
|
.flags = OPTIONS_TABLE_IS_COLOUR,
|
||||||
|
.default_str = "blue",
|
||||||
.text = "Colour of the clock in clock mode."
|
.text = "Colour of the clock in clock mode."
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -1356,7 +1371,7 @@ const struct options_table_entry options_table[] = {
|
|||||||
|
|
||||||
{ .name = "pane-border-lines",
|
{ .name = "pane-border-lines",
|
||||||
.type = OPTIONS_TABLE_CHOICE,
|
.type = OPTIONS_TABLE_CHOICE,
|
||||||
.scope = OPTIONS_TABLE_WINDOW,
|
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
|
||||||
.choices = options_table_pane_border_lines_list,
|
.choices = options_table_pane_border_lines_list,
|
||||||
.default_num = PANE_LINES_SINGLE,
|
.default_num = PANE_LINES_SINGLE,
|
||||||
.text = "Type of characters used to draw pane border lines. Some of "
|
.text = "Type of characters used to draw pane border lines. Some of "
|
||||||
@@ -1365,7 +1380,7 @@ const struct options_table_entry options_table[] = {
|
|||||||
|
|
||||||
{ .name = "pane-border-status",
|
{ .name = "pane-border-status",
|
||||||
.type = OPTIONS_TABLE_CHOICE,
|
.type = OPTIONS_TABLE_CHOICE,
|
||||||
.scope = OPTIONS_TABLE_WINDOW,
|
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
|
||||||
.choices = options_table_pane_status_list,
|
.choices = options_table_pane_status_list,
|
||||||
.default_num = PANE_STATUS_OFF,
|
.default_num = PANE_STATUS_OFF,
|
||||||
.text = "Position of the pane status lines."
|
.text = "Position of the pane status lines."
|
||||||
|
|||||||
55
options.c
55
options.c
@@ -662,6 +662,18 @@ options_parse_get(struct options *oo, const char *s, int *idx, int only)
|
|||||||
return (o);
|
return (o);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const struct options_table_entry *
|
||||||
|
options_search(const char *name)
|
||||||
|
{
|
||||||
|
const struct options_table_entry *oe;
|
||||||
|
|
||||||
|
for (oe = options_table; oe->name != NULL; oe++) {
|
||||||
|
if (strcmp(oe->name, name) == 0)
|
||||||
|
return (oe);
|
||||||
|
}
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
char *
|
char *
|
||||||
options_match(const char *s, int *idx, int *ambiguous)
|
options_match(const char *s, int *idx, int *ambiguous)
|
||||||
{
|
{
|
||||||
@@ -977,9 +989,12 @@ struct style *
|
|||||||
options_string_to_style(struct options *oo, const char *name,
|
options_string_to_style(struct options *oo, const char *name,
|
||||||
struct format_tree *ft)
|
struct format_tree *ft)
|
||||||
{
|
{
|
||||||
struct options_entry *o;
|
struct options_entry *o;
|
||||||
const char *s;
|
const struct options_table_entry *oe;
|
||||||
char *expanded;
|
const struct grid_cell *dgc = &grid_default_cell;
|
||||||
|
const char *s;
|
||||||
|
char *expanded;
|
||||||
|
int failed;
|
||||||
|
|
||||||
o = options_get(oo, name);
|
o = options_get(oo, name);
|
||||||
if (o == NULL || !OPTIONS_IS_STRING(o))
|
if (o == NULL || !OPTIONS_IS_STRING(o))
|
||||||
@@ -988,20 +1003,27 @@ options_string_to_style(struct options *oo, const char *name,
|
|||||||
if (o->cached)
|
if (o->cached)
|
||||||
return (&o->style);
|
return (&o->style);
|
||||||
s = o->value.string;
|
s = o->value.string;
|
||||||
|
oe = o->tableentry;
|
||||||
log_debug("%s: %s is '%s'", __func__, name, s);
|
log_debug("%s: %s is '%s'", __func__, name, s);
|
||||||
|
|
||||||
style_set(&o->style, &grid_default_cell);
|
style_set(&o->style, dgc);
|
||||||
o->cached = (strstr(s, "#{") == NULL);
|
o->cached = (strstr(s, "#{") == NULL);
|
||||||
|
|
||||||
if (ft != NULL && !o->cached) {
|
if (ft != NULL && !o->cached) {
|
||||||
expanded = format_expand(ft, s);
|
expanded = format_expand(ft, s);
|
||||||
if (style_parse(&o->style, &grid_default_cell, expanded) != 0) {
|
if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_COLOUR))
|
||||||
free(expanded);
|
failed = style_parse_colour(&o->style, dgc, expanded);
|
||||||
return (NULL);
|
else
|
||||||
}
|
failed = style_parse(&o->style, dgc, expanded);
|
||||||
free(expanded);
|
free(expanded);
|
||||||
|
if (failed != 0)
|
||||||
|
return (NULL);
|
||||||
} else {
|
} else {
|
||||||
if (style_parse(&o->style, &grid_default_cell, s) != 0)
|
if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_COLOUR))
|
||||||
|
failed = style_parse_colour(&o->style, dgc, s);
|
||||||
|
else
|
||||||
|
failed = style_parse(&o->style, dgc, s);
|
||||||
|
if (failed != 0)
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
return (&o->style);
|
return (&o->style);
|
||||||
@@ -1029,6 +1051,12 @@ options_from_string_check(const struct options_table_entry *oe,
|
|||||||
xasprintf(cause, "invalid style: %s", value);
|
xasprintf(cause, "invalid style: %s", value);
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
if ((oe->flags & OPTIONS_TABLE_IS_COLOUR) &&
|
||||||
|
strstr(value, "#{") == NULL &&
|
||||||
|
style_parse_colour(&sy, &grid_default_cell, value) != 0) {
|
||||||
|
xasprintf(cause, "invalid colour: %s", value);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1219,6 +1247,15 @@ options_push_changes(const char *name)
|
|||||||
if (strcmp(name, "status") == 0 ||
|
if (strcmp(name, "status") == 0 ||
|
||||||
strcmp(name, "status-interval") == 0)
|
strcmp(name, "status-interval") == 0)
|
||||||
status_timer_start_all();
|
status_timer_start_all();
|
||||||
|
if (strcmp(name, "status") == 0 ||
|
||||||
|
strcmp(name, "status-position") == 0 ||
|
||||||
|
strcmp(name, "pane-border-indicators") == 0 ||
|
||||||
|
strcmp(name, "pane-border-lines") == 0 ||
|
||||||
|
strcmp(name, "pane-border-status") == 0 ||
|
||||||
|
strcmp(name, "pane-scrollbars") == 0 ||
|
||||||
|
strcmp(name, "pane-scrollbars-position") == 0 ||
|
||||||
|
strcmp(name, "pane-scrollbars-style") == 0)
|
||||||
|
redraw_invalidate_all_scenes();
|
||||||
if (strcmp(name, "monitor-silence") == 0)
|
if (strcmp(name, "monitor-silence") == 0)
|
||||||
alerts_reset_all();
|
alerts_reset_all();
|
||||||
if (strcmp(name, "window-style") == 0 ||
|
if (strcmp(name, "window-style") == 0 ||
|
||||||
|
|||||||
2
paste.c
2
paste.c
@@ -176,7 +176,6 @@ paste_add(const char *prefix, char *data, size_t size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
pb = xmalloc(sizeof *pb);
|
pb = xmalloc(sizeof *pb);
|
||||||
|
|
||||||
pb->name = NULL;
|
pb->name = NULL;
|
||||||
do {
|
do {
|
||||||
free(pb->name);
|
free(pb->name);
|
||||||
@@ -296,7 +295,6 @@ paste_set(char *data, size_t size, const char *name, char **cause)
|
|||||||
}
|
}
|
||||||
|
|
||||||
pb = xmalloc(sizeof *pb);
|
pb = xmalloc(sizeof *pb);
|
||||||
|
|
||||||
pb->name = newname;
|
pb->name = newname;
|
||||||
|
|
||||||
pb->data = data;
|
pb->data = data;
|
||||||
|
|||||||
171
popup.c
171
popup.c
@@ -75,12 +75,6 @@ struct popup_data {
|
|||||||
u_int lb;
|
u_int lb;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct popup_editor {
|
|
||||||
char *path;
|
|
||||||
popup_finish_edit_cb cb;
|
|
||||||
void *arg;
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct menu_item popup_menu_items[] = {
|
static const struct menu_item popup_menu_items[] = {
|
||||||
{ "Close", 'q', NULL },
|
{ "Close", 'q', NULL },
|
||||||
{ "#{?buffer_name,Paste #[underscore]#{buffer_name},}", 'p', NULL },
|
{ "#{?buffer_name,Paste #[underscore]#{buffer_name},}", 'p', NULL },
|
||||||
@@ -94,15 +88,6 @@ static const struct menu_item popup_menu_items[] = {
|
|||||||
{ NULL, KEYC_NONE, NULL }
|
{ NULL, KEYC_NONE, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct menu_item popup_internal_menu_items[] = {
|
|
||||||
{ "Close", 'q', NULL },
|
|
||||||
{ "", KEYC_NONE, NULL },
|
|
||||||
{ "Fill Space", 'F', NULL },
|
|
||||||
{ "Centre", 'C', NULL },
|
|
||||||
|
|
||||||
{ NULL, KEYC_NONE, NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
popup_free(struct popup_data *pd)
|
popup_free(struct popup_data *pd)
|
||||||
{
|
{
|
||||||
@@ -208,7 +193,8 @@ popup_init_ctx_cb(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx)
|
|||||||
|
|
||||||
memcpy(&ttyctx->defaults, &pd->defaults, sizeof ttyctx->defaults);
|
memcpy(&ttyctx->defaults, &pd->defaults, sizeof ttyctx->defaults);
|
||||||
ttyctx->flags &= ~TTY_CTX_WINDOW_BIGGER;
|
ttyctx->flags &= ~TTY_CTX_WINDOW_BIGGER;
|
||||||
ttyctx->palette = &pd->palette;
|
ttyctx->style_ctx.defaults = &ttyctx->defaults;
|
||||||
|
ttyctx->style_ctx.palette = &pd->palette;
|
||||||
ttyctx->redraw_cb = popup_redraw_cb;
|
ttyctx->redraw_cb = popup_redraw_cb;
|
||||||
ttyctx->set_client_cb = popup_set_client_cb;
|
ttyctx->set_client_cb = popup_set_client_cb;
|
||||||
ttyctx->arg = pd;
|
ttyctx->arg = pd;
|
||||||
@@ -287,15 +273,15 @@ popup_check_cb(struct client* c, void *data, u_int px, u_int py, u_int nx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
popup_draw_cb(struct client *c, void *data, struct screen_redraw_ctx *rctx)
|
popup_draw_cb(struct client *c, void *data)
|
||||||
{
|
{
|
||||||
struct popup_data *pd = data;
|
struct popup_data *pd = data;
|
||||||
struct tty *tty = &c->tty;
|
struct tty *tty = &c->tty;
|
||||||
struct screen s;
|
struct screen s;
|
||||||
struct screen_write_ctx ctx;
|
struct screen_write_ctx ctx;
|
||||||
u_int i, px = pd->px, py = pd->py;
|
u_int i, px = pd->px, py = pd->py;
|
||||||
struct colour_palette *palette = &pd->palette;
|
|
||||||
struct grid_cell defaults;
|
struct grid_cell defaults;
|
||||||
|
struct tty_style_ctx style_ctx;
|
||||||
|
|
||||||
popup_reapply_styles(pd);
|
popup_reapply_styles(pd);
|
||||||
|
|
||||||
@@ -321,9 +307,13 @@ popup_draw_cb(struct client *c, void *data, struct screen_redraw_ctx *rctx)
|
|||||||
|
|
||||||
memcpy(&defaults, &pd->defaults, sizeof defaults);
|
memcpy(&defaults, &pd->defaults, sizeof defaults);
|
||||||
if (defaults.fg == 8)
|
if (defaults.fg == 8)
|
||||||
defaults.fg = palette->fg;
|
defaults.fg = pd->palette.fg;
|
||||||
if (defaults.bg == 8)
|
if (defaults.bg == 8)
|
||||||
defaults.bg = palette->bg;
|
defaults.bg = pd->palette.bg;
|
||||||
|
style_ctx.defaults = &defaults;
|
||||||
|
style_ctx.palette = &pd->palette;
|
||||||
|
style_ctx.dim = 0;
|
||||||
|
style_ctx.hyperlinks = s.hyperlinks;
|
||||||
|
|
||||||
if (pd->md != NULL) {
|
if (pd->md != NULL) {
|
||||||
c->overlay_check = menu_check_cb;
|
c->overlay_check = menu_check_cb;
|
||||||
@@ -332,15 +322,13 @@ popup_draw_cb(struct client *c, void *data, struct screen_redraw_ctx *rctx)
|
|||||||
c->overlay_check = NULL;
|
c->overlay_check = NULL;
|
||||||
c->overlay_data = NULL;
|
c->overlay_data = NULL;
|
||||||
}
|
}
|
||||||
for (i = 0; i < pd->sy; i++) {
|
for (i = 0; i < pd->sy; i++)
|
||||||
tty_draw_line(tty, &s, 0, i, pd->sx, px, py + i, &defaults,
|
tty_draw_line(tty, &s, 0, i, pd->sx, px, py + i, &style_ctx);
|
||||||
palette);
|
|
||||||
}
|
|
||||||
screen_free(&s);
|
screen_free(&s);
|
||||||
if (pd->md != NULL) {
|
if (pd->md != NULL) {
|
||||||
c->overlay_check = NULL;
|
c->overlay_check = NULL;
|
||||||
c->overlay_data = NULL;
|
c->overlay_data = NULL;
|
||||||
menu_draw_cb(c, pd->md, rctx);
|
menu_draw_cb(c, pd->md);
|
||||||
}
|
}
|
||||||
c->overlay_check = popup_check_cb;
|
c->overlay_check = popup_check_cb;
|
||||||
c->overlay_data = pd;
|
c->overlay_data = pd;
|
||||||
@@ -435,7 +423,7 @@ popup_make_pane(struct popup_data *pd, enum layout_type type)
|
|||||||
pd->job = NULL;
|
pd->job = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
screen_set_title(&pd->s, new_wp->base.title);
|
screen_set_title(&pd->s, new_wp->base.title, 0);
|
||||||
screen_free(&new_wp->base);
|
screen_free(&new_wp->base);
|
||||||
memcpy(&new_wp->base, &pd->s, sizeof wp->base);
|
memcpy(&new_wp->base, &pd->s, sizeof wp->base);
|
||||||
screen_resize(&new_wp->base, new_wp->sx, new_wp->sy, 1);
|
screen_resize(&new_wp->base, new_wp->sx, new_wp->sy, 1);
|
||||||
@@ -647,11 +635,7 @@ popup_key_cb(struct client *c, void *data, struct key_event *event)
|
|||||||
|
|
||||||
menu:
|
menu:
|
||||||
pd->menu = menu_create("");
|
pd->menu = menu_create("");
|
||||||
if (pd->flags & POPUP_INTERNAL) {
|
menu_add_items(pd->menu, popup_menu_items, NULL, c, NULL);
|
||||||
menu_add_items(pd->menu, popup_internal_menu_items, NULL, c,
|
|
||||||
NULL);
|
|
||||||
} else
|
|
||||||
menu_add_items(pd->menu, popup_menu_items, NULL, c, NULL);
|
|
||||||
if (m->x >= (pd->menu->width + 4) / 2)
|
if (m->x >= (pd->menu->width + 4) / 2)
|
||||||
x = m->x - (pd->menu->width + 4) / 2;
|
x = m->x - (pd->menu->width + 4) / 2;
|
||||||
else
|
else
|
||||||
@@ -858,127 +842,16 @@ popup_display(int flags, enum box_lines lines, struct cmdq_item *item, u_int px,
|
|||||||
pd->psx = sx;
|
pd->psx = sx;
|
||||||
pd->psy = sy;
|
pd->psy = sy;
|
||||||
|
|
||||||
if (flags & POPUP_NOJOB)
|
pd->job = job_run(shellcmd, argc, argv, env, s, cwd,
|
||||||
pd->ictx = input_init(NULL, NULL, &pd->palette, NULL);
|
popup_job_update_cb, popup_job_complete_cb, NULL, pd,
|
||||||
else {
|
JOB_NOWAIT|JOB_PTY|JOB_KEEPWRITE|JOB_DEFAULTSHELL, jx, jy);
|
||||||
pd->job = job_run(shellcmd, argc, argv, env, s, cwd,
|
if (pd->job == NULL) {
|
||||||
popup_job_update_cb, popup_job_complete_cb, NULL, pd,
|
popup_free(pd);
|
||||||
JOB_NOWAIT|JOB_PTY|JOB_KEEPWRITE|JOB_DEFAULTSHELL, jx, jy);
|
return (-1);
|
||||||
if (pd->job == NULL) {
|
|
||||||
popup_free(pd);
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
pd->ictx = input_init(NULL, job_get_event(pd->job),
|
|
||||||
&pd->palette, c);
|
|
||||||
}
|
}
|
||||||
|
pd->ictx = input_init(NULL, job_get_event(pd->job), &pd->palette, c);
|
||||||
|
|
||||||
server_client_set_overlay(c, 0, popup_check_cb, popup_mode_cb,
|
server_client_set_overlay(c, 0, popup_check_cb, popup_mode_cb,
|
||||||
popup_draw_cb, popup_key_cb, popup_free_cb, popup_resize_cb, pd);
|
popup_draw_cb, popup_key_cb, popup_free_cb, popup_resize_cb, pd);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
popup_write(struct client *c, const char *data, size_t size)
|
|
||||||
{
|
|
||||||
struct popup_data *pd = c->overlay_data;
|
|
||||||
|
|
||||||
if (!popup_present(c))
|
|
||||||
return;
|
|
||||||
c->overlay_check = NULL;
|
|
||||||
c->overlay_data = NULL;
|
|
||||||
input_parse_screen(pd->ictx, &pd->s, popup_init_ctx_cb, pd, data, size);
|
|
||||||
c->overlay_check = popup_check_cb;
|
|
||||||
c->overlay_data = pd;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
popup_editor_free(struct popup_editor *pe)
|
|
||||||
{
|
|
||||||
unlink(pe->path);
|
|
||||||
free(pe->path);
|
|
||||||
free(pe);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
popup_editor_close_cb(int status, void *arg)
|
|
||||||
{
|
|
||||||
struct popup_editor *pe = arg;
|
|
||||||
FILE *f;
|
|
||||||
char *buf = NULL;
|
|
||||||
off_t len = 0;
|
|
||||||
|
|
||||||
if (status != 0) {
|
|
||||||
pe->cb(NULL, 0, pe->arg);
|
|
||||||
popup_editor_free(pe);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
f = fopen(pe->path, "r");
|
|
||||||
if (f != NULL) {
|
|
||||||
fseeko(f, 0, SEEK_END);
|
|
||||||
len = ftello(f);
|
|
||||||
fseeko(f, 0, SEEK_SET);
|
|
||||||
|
|
||||||
if (len == 0 ||
|
|
||||||
(uintmax_t)len > (uintmax_t)SIZE_MAX ||
|
|
||||||
(buf = malloc(len)) == NULL ||
|
|
||||||
fread(buf, len, 1, f) != 1) {
|
|
||||||
free(buf);
|
|
||||||
buf = NULL;
|
|
||||||
len = 0;
|
|
||||||
}
|
|
||||||
fclose(f);
|
|
||||||
}
|
|
||||||
pe->cb(buf, len, pe->arg); /* callback now owns buffer */
|
|
||||||
popup_editor_free(pe);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
popup_editor(struct client *c, const char *buf, size_t len,
|
|
||||||
popup_finish_edit_cb cb, void *arg)
|
|
||||||
{
|
|
||||||
struct popup_editor *pe;
|
|
||||||
int fd;
|
|
||||||
FILE *f;
|
|
||||||
char *cmd;
|
|
||||||
char path[] = _PATH_TMP "tmux.XXXXXXXX";
|
|
||||||
const char *editor;
|
|
||||||
u_int px, py, sx, sy;
|
|
||||||
|
|
||||||
editor = options_get_string(global_options, "editor");
|
|
||||||
if (*editor == '\0')
|
|
||||||
return (-1);
|
|
||||||
|
|
||||||
fd = mkstemp(path);
|
|
||||||
if (fd == -1)
|
|
||||||
return (-1);
|
|
||||||
f = fdopen(fd, "w");
|
|
||||||
if (f == NULL)
|
|
||||||
return (-1);
|
|
||||||
if (fwrite(buf, len, 1, f) != 1) {
|
|
||||||
fclose(f);
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
fclose(f);
|
|
||||||
|
|
||||||
pe = xcalloc(1, sizeof *pe);
|
|
||||||
pe->path = xstrdup(path);
|
|
||||||
pe->cb = cb;
|
|
||||||
pe->arg = arg;
|
|
||||||
|
|
||||||
sx = c->tty.sx * 9 / 10;
|
|
||||||
sy = c->tty.sy * 9 / 10;
|
|
||||||
px = (c->tty.sx / 2) - (sx / 2);
|
|
||||||
py = (c->tty.sy / 2) - (sy / 2);
|
|
||||||
|
|
||||||
xasprintf(&cmd, "%s %s", editor, path);
|
|
||||||
if (popup_display(POPUP_INTERNAL|POPUP_CLOSEEXIT, BOX_LINES_DEFAULT,
|
|
||||||
NULL, px, py, sx, sy, NULL, cmd, 0, NULL, _PATH_TMP, NULL, c, NULL,
|
|
||||||
NULL, NULL, popup_editor_close_cb, pe) != 0) {
|
|
||||||
popup_editor_free(pe);
|
|
||||||
free(cmd);
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
free(cmd);
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|||||||
12
proc.c
12
proc.c
@@ -57,6 +57,7 @@ struct tmuxpeer {
|
|||||||
struct imsgbuf ibuf;
|
struct imsgbuf ibuf;
|
||||||
struct event event;
|
struct event event;
|
||||||
uid_t uid;
|
uid_t uid;
|
||||||
|
gid_t gid;
|
||||||
|
|
||||||
int flags;
|
int flags;
|
||||||
#define PEER_BAD 0x1
|
#define PEER_BAD 0x1
|
||||||
@@ -301,7 +302,6 @@ proc_add_peer(struct tmuxproc *tp, int fd,
|
|||||||
void (*dispatchcb)(struct imsg *, void *), void *arg)
|
void (*dispatchcb)(struct imsg *, void *), void *arg)
|
||||||
{
|
{
|
||||||
struct tmuxpeer *peer;
|
struct tmuxpeer *peer;
|
||||||
gid_t gid;
|
|
||||||
|
|
||||||
peer = xcalloc(1, sizeof *peer);
|
peer = xcalloc(1, sizeof *peer);
|
||||||
peer->parent = tp;
|
peer->parent = tp;
|
||||||
@@ -314,8 +314,10 @@ proc_add_peer(struct tmuxproc *tp, int fd,
|
|||||||
imsgbuf_allow_fdpass(&peer->ibuf);
|
imsgbuf_allow_fdpass(&peer->ibuf);
|
||||||
event_set(&peer->event, fd, EV_READ, proc_event_cb, peer);
|
event_set(&peer->event, fd, EV_READ, proc_event_cb, peer);
|
||||||
|
|
||||||
if (getpeereid(fd, &peer->uid, &gid) != 0)
|
if (getpeereid(fd, &peer->uid, &peer->gid) != 0) {
|
||||||
peer->uid = (uid_t)-1;
|
peer->uid = (uid_t)-1;
|
||||||
|
peer->gid = (gid_t)-1;
|
||||||
|
}
|
||||||
|
|
||||||
log_debug("add peer %p: %d (%p)", peer, fd, arg);
|
log_debug("add peer %p: %d (%p)", peer, fd, arg);
|
||||||
TAILQ_INSERT_TAIL(&tp->peers, peer, entry);
|
TAILQ_INSERT_TAIL(&tp->peers, peer, entry);
|
||||||
@@ -384,3 +386,9 @@ proc_get_peer_uid(struct tmuxpeer *peer)
|
|||||||
{
|
{
|
||||||
return (peer->uid);
|
return (peer->uid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gid_t
|
||||||
|
proc_get_peer_gid(struct tmuxpeer *peer)
|
||||||
|
{
|
||||||
|
return (peer->gid);
|
||||||
|
}
|
||||||
|
|||||||
264
prompt-history.c
Normal file
264
prompt-history.c
Normal file
@@ -0,0 +1,264 @@
|
|||||||
|
/* $OpenBSD$ */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2026 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
||||||
|
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "tmux.h"
|
||||||
|
|
||||||
|
static char *prompt_find_history_file(void);
|
||||||
|
static void prompt_add_typed_history(char *);
|
||||||
|
|
||||||
|
/* Prompt history. */
|
||||||
|
static char **prompt_hlist[PROMPT_NTYPES];
|
||||||
|
static u_int prompt_hsize[PROMPT_NTYPES];
|
||||||
|
|
||||||
|
/* Find the history file to load/save from/to. */
|
||||||
|
static char *
|
||||||
|
prompt_find_history_file(void)
|
||||||
|
{
|
||||||
|
const char *home, *history_file;
|
||||||
|
char *path;
|
||||||
|
|
||||||
|
history_file = options_get_string(global_options, "history-file");
|
||||||
|
if (*history_file == '\0')
|
||||||
|
return (NULL);
|
||||||
|
if (*history_file == '/')
|
||||||
|
return (xstrdup(history_file));
|
||||||
|
|
||||||
|
if (history_file[0] != '~' || history_file[1] != '/')
|
||||||
|
return (NULL);
|
||||||
|
if ((home = find_home()) == NULL)
|
||||||
|
return (NULL);
|
||||||
|
xasprintf(&path, "%s%s", home, history_file + 1);
|
||||||
|
return (path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add loaded history item to the appropriate list. */
|
||||||
|
static void
|
||||||
|
prompt_add_typed_history(char *line)
|
||||||
|
{
|
||||||
|
char *typestr;
|
||||||
|
enum prompt_type type = PROMPT_TYPE_INVALID;
|
||||||
|
|
||||||
|
typestr = strsep(&line, ":");
|
||||||
|
if (line != NULL)
|
||||||
|
type = prompt_type(typestr);
|
||||||
|
if (type == PROMPT_TYPE_INVALID) {
|
||||||
|
/*
|
||||||
|
* Invalid types are not expected, but this provides backward
|
||||||
|
* compatibility with old history files.
|
||||||
|
*/
|
||||||
|
if (line != NULL)
|
||||||
|
*(--line) = ':';
|
||||||
|
prompt_add_history(typestr, PROMPT_TYPE_COMMAND);
|
||||||
|
} else
|
||||||
|
prompt_add_history(line, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Load prompt history from file. */
|
||||||
|
void
|
||||||
|
prompt_load_history(void)
|
||||||
|
{
|
||||||
|
FILE *f;
|
||||||
|
char *history_file, *line, *tmp;
|
||||||
|
size_t length;
|
||||||
|
|
||||||
|
if ((history_file = prompt_find_history_file()) == NULL)
|
||||||
|
return;
|
||||||
|
log_debug("loading history from %s", history_file);
|
||||||
|
|
||||||
|
f = fopen(history_file, "r");
|
||||||
|
if (f == NULL) {
|
||||||
|
log_debug("%s: %s", history_file, strerror(errno));
|
||||||
|
free(history_file);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
free(history_file);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
if ((line = fgetln(f, &length)) == NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (length > 0) {
|
||||||
|
if (line[length - 1] == '\n') {
|
||||||
|
line[length - 1] = '\0';
|
||||||
|
prompt_add_typed_history(line);
|
||||||
|
} else {
|
||||||
|
tmp = xmalloc(length + 1);
|
||||||
|
memcpy(tmp, line, length);
|
||||||
|
tmp[length] = '\0';
|
||||||
|
prompt_add_typed_history(tmp);
|
||||||
|
free(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save prompt history to file. */
|
||||||
|
void
|
||||||
|
prompt_save_history(void)
|
||||||
|
{
|
||||||
|
FILE *f;
|
||||||
|
u_int i, type;
|
||||||
|
char *history_file;
|
||||||
|
|
||||||
|
if ((history_file = prompt_find_history_file()) == NULL)
|
||||||
|
return;
|
||||||
|
log_debug("saving history to %s", history_file);
|
||||||
|
|
||||||
|
f = fopen(history_file, "w");
|
||||||
|
if (f == NULL) {
|
||||||
|
log_debug("%s: %s", history_file, strerror(errno));
|
||||||
|
free(history_file);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
free(history_file);
|
||||||
|
|
||||||
|
for (type = 0; type < PROMPT_NTYPES; type++) {
|
||||||
|
for (i = 0; i < prompt_hsize[type]; i++) {
|
||||||
|
fputs(prompt_type_string(type), f);
|
||||||
|
fputc(':', f);
|
||||||
|
fputs(prompt_hlist[type][i], f);
|
||||||
|
fputc('\n', f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get previous line from the history. */
|
||||||
|
const char *
|
||||||
|
prompt_up_history(u_int *idx, u_int type)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* History runs from 0 to size - 1. Index is from 0 to size. Zero is
|
||||||
|
* empty.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (type >= PROMPT_NTYPES)
|
||||||
|
return (NULL);
|
||||||
|
if (prompt_hsize[type] == 0 || idx[type] == prompt_hsize[type])
|
||||||
|
return (NULL);
|
||||||
|
idx[type]++;
|
||||||
|
return (prompt_hlist[type][prompt_hsize[type] - idx[type]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get next line from the history. */
|
||||||
|
const char *
|
||||||
|
prompt_down_history(u_int *idx, u_int type)
|
||||||
|
{
|
||||||
|
if (type >= PROMPT_NTYPES)
|
||||||
|
return ("");
|
||||||
|
if (prompt_hsize[type] == 0 || idx[type] == 0)
|
||||||
|
return ("");
|
||||||
|
idx[type]--;
|
||||||
|
if (idx[type] == 0)
|
||||||
|
return ("");
|
||||||
|
return (prompt_hlist[type][prompt_hsize[type] - idx[type]]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add line to the history. */
|
||||||
|
void
|
||||||
|
prompt_add_history(const char *line, u_int type)
|
||||||
|
{
|
||||||
|
u_int i, oldsize, newsize, freecount, hlimit, new = 1;
|
||||||
|
size_t movesize;
|
||||||
|
|
||||||
|
if (type >= PROMPT_NTYPES)
|
||||||
|
return;
|
||||||
|
|
||||||
|
oldsize = prompt_hsize[type];
|
||||||
|
if (oldsize > 0 &&
|
||||||
|
strcmp(prompt_hlist[type][oldsize - 1], line) == 0)
|
||||||
|
new = 0;
|
||||||
|
|
||||||
|
hlimit = options_get_number(global_options, "prompt-history-limit");
|
||||||
|
if (hlimit > oldsize) {
|
||||||
|
if (new == 0)
|
||||||
|
return;
|
||||||
|
newsize = oldsize + new;
|
||||||
|
} else {
|
||||||
|
newsize = hlimit;
|
||||||
|
freecount = oldsize + new - newsize;
|
||||||
|
if (freecount > oldsize)
|
||||||
|
freecount = oldsize;
|
||||||
|
if (freecount == 0)
|
||||||
|
return;
|
||||||
|
for (i = 0; i < freecount; i++)
|
||||||
|
free(prompt_hlist[type][i]);
|
||||||
|
movesize = (oldsize - freecount) *
|
||||||
|
sizeof *prompt_hlist[type];
|
||||||
|
if (movesize > 0) {
|
||||||
|
memmove(&prompt_hlist[type][0],
|
||||||
|
&prompt_hlist[type][freecount], movesize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newsize == 0) {
|
||||||
|
free(prompt_hlist[type]);
|
||||||
|
prompt_hlist[type] = NULL;
|
||||||
|
} else if (newsize != oldsize) {
|
||||||
|
prompt_hlist[type] =
|
||||||
|
xreallocarray(prompt_hlist[type], newsize,
|
||||||
|
sizeof *prompt_hlist[type]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new == 1 && newsize > 0)
|
||||||
|
prompt_hlist[type][newsize - 1] = xstrdup(line);
|
||||||
|
prompt_hsize[type] = newsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get history size. */
|
||||||
|
u_int
|
||||||
|
prompt_history_size(enum prompt_type type)
|
||||||
|
{
|
||||||
|
if (type >= PROMPT_NTYPES)
|
||||||
|
return (0);
|
||||||
|
return (prompt_hsize[type]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get history entry. */
|
||||||
|
const char *
|
||||||
|
prompt_history_get(enum prompt_type type, u_int idx)
|
||||||
|
{
|
||||||
|
if (type >= PROMPT_NTYPES)
|
||||||
|
return (NULL);
|
||||||
|
if (idx >= prompt_hsize[type])
|
||||||
|
return (NULL);
|
||||||
|
return (prompt_hlist[type][idx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clear prompt history. */
|
||||||
|
void
|
||||||
|
prompt_history_clear(enum prompt_type type)
|
||||||
|
{
|
||||||
|
u_int idx;
|
||||||
|
|
||||||
|
if (type >= PROMPT_NTYPES)
|
||||||
|
return;
|
||||||
|
for (idx = 0; idx < prompt_hsize[type]; idx++)
|
||||||
|
free(prompt_hlist[type][idx]);
|
||||||
|
free(prompt_hlist[type]);
|
||||||
|
prompt_hlist[type] = NULL;
|
||||||
|
prompt_hsize[type] = 0;
|
||||||
|
}
|
||||||
140
regress/check-names.sh
Normal file
140
regress/check-names.sh
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Name validation policy.
|
||||||
|
|
||||||
|
PATH=/bin:/usr/bin
|
||||||
|
TERM=screen
|
||||||
|
|
||||||
|
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||||
|
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||||
|
$TMUX kill-server 2>/dev/null
|
||||||
|
|
||||||
|
fail()
|
||||||
|
{
|
||||||
|
echo "$*"
|
||||||
|
$TMUX kill-server 2>/dev/null
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
must_fail()
|
||||||
|
{
|
||||||
|
"$@" >/dev/null 2>&1 && fail "unexpected success: $*"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
must_equal()
|
||||||
|
{
|
||||||
|
got=$1
|
||||||
|
want=$2
|
||||||
|
|
||||||
|
[ "$got" = "$want" ] || fail "got '$got', expected '$want'"
|
||||||
|
}
|
||||||
|
|
||||||
|
$TMUX new-session -d -x 80 -y 24 || exit 1
|
||||||
|
$TMUX set-option -qg allow-set-title on || exit 1
|
||||||
|
$TMUX set-option -qg allow-rename on || exit 1
|
||||||
|
$TMUX set-option -qg automatic-rename off || exit 1
|
||||||
|
|
||||||
|
# Commands reject ':' and '.' for sessions and windows, but allow '#'.
|
||||||
|
$TMUX rename-session 'session#ok' || fail "session name with # rejected"
|
||||||
|
must_equal "$($TMUX display-message -p '#{session_name}')" 'session#ok'
|
||||||
|
must_fail $TMUX rename-session 'session:bad'
|
||||||
|
must_fail $TMUX rename-session 'session.bad'
|
||||||
|
|
||||||
|
$TMUX rename-window 'window#ok' || fail "window name with # rejected"
|
||||||
|
must_equal "$($TMUX display-message -p '#{window_name}')" 'window#ok'
|
||||||
|
must_fail $TMUX rename-window 'window:bad'
|
||||||
|
must_fail $TMUX rename-window 'window.bad'
|
||||||
|
|
||||||
|
$TMUX set-option -q @name 'format#ok' || exit 1
|
||||||
|
$TMUX rename-session '#{@name}' || fail "format in session name not expanded"
|
||||||
|
must_equal "$($TMUX display-message -p '#{session_name}')" 'format#ok'
|
||||||
|
$TMUX rename-window '#{@name}' || fail "format in window name not expanded"
|
||||||
|
must_equal "$($TMUX display-message -p '#{window_name}')" 'format#ok'
|
||||||
|
must_fail $TMUX rename-session '#{session_name}:bad'
|
||||||
|
must_fail $TMUX rename-window '#{window_name}.bad'
|
||||||
|
pid=$($TMUX display-message -p '#{pid}')
|
||||||
|
|
||||||
|
created=$($TMUX new-session -dP -F '#{session_id}:#{window_id}' \
|
||||||
|
-s 'new-session#ok' -n 'new-window#ok') || \
|
||||||
|
fail "new-session name with # rejected"
|
||||||
|
created_session=${created%:*}
|
||||||
|
created_window=${created#*:}
|
||||||
|
must_equal "$($TMUX display-message -pt "$created_session" '#{session_name}')" \
|
||||||
|
'new-session#ok'
|
||||||
|
must_equal "$($TMUX display-message -pt "$created_window" '#{window_name}')" \
|
||||||
|
'new-window#ok'
|
||||||
|
$TMUX kill-session -t "$created_session"
|
||||||
|
|
||||||
|
must_fail $TMUX new-session -d -s 'new-session:bad'
|
||||||
|
must_fail $TMUX new-session -d -s 'new-session.bad'
|
||||||
|
must_fail $TMUX new-session -d -n 'new-window:bad'
|
||||||
|
must_fail $TMUX new-session -d -n 'new-window.bad'
|
||||||
|
|
||||||
|
created_window=$($TMUX new-window -dP -F '#{window_id}' \
|
||||||
|
-n 'created-window#ok') || \
|
||||||
|
fail "new-window name with # rejected"
|
||||||
|
must_equal "$($TMUX display-message -pt "$created_window" '#{window_name}')" \
|
||||||
|
'created-window#ok'
|
||||||
|
must_fail $TMUX new-window -d -n 'created-window:bad'
|
||||||
|
must_fail $TMUX new-window -d -n 'created-window.bad'
|
||||||
|
|
||||||
|
created=$($TMUX new-session -dP -F '#{session_id}:#{window_id}' \
|
||||||
|
-s 'new-session-#{pid}' -n 'new-window-#{pid}') || \
|
||||||
|
fail "format in new-session name not expanded"
|
||||||
|
created_session=${created%:*}
|
||||||
|
created_window=${created#*:}
|
||||||
|
must_equal "$($TMUX display-message -pt "$created_session" '#{session_name}')" \
|
||||||
|
"new-session-$pid"
|
||||||
|
must_equal "$($TMUX display-message -pt "$created_window" '#{window_name}')" \
|
||||||
|
"new-window-$pid"
|
||||||
|
$TMUX kill-session -t "$created_session"
|
||||||
|
|
||||||
|
created_window=$($TMUX new-window -dP -F '#{window_id}' -n '#{@name}') || \
|
||||||
|
fail "format in new-window name not expanded"
|
||||||
|
must_equal "$($TMUX display-message -pt "$created_window" '#{window_name}')" \
|
||||||
|
'format#ok'
|
||||||
|
must_fail $TMUX new-session -d -s 'new-session-#{pid}:bad'
|
||||||
|
must_fail $TMUX new-session -d -n 'new-window-#{pid}.bad'
|
||||||
|
must_fail $TMUX new-window -d -n '#{window_name}:bad'
|
||||||
|
|
||||||
|
# Invalid UTF-8 is never allowed for command names.
|
||||||
|
invalid=$(printf '\302')
|
||||||
|
must_fail $TMUX rename-session "bad${invalid}name"
|
||||||
|
must_fail $TMUX rename-window "bad${invalid}name"
|
||||||
|
must_fail $TMUX new-session -d -s "bad${invalid}name"
|
||||||
|
must_fail $TMUX new-session -d -n "bad${invalid}name"
|
||||||
|
must_fail $TMUX new-window -d -n "bad${invalid}name"
|
||||||
|
must_fail $TMUX set-buffer -b "bad${invalid}name" data
|
||||||
|
|
||||||
|
# Titles set by commands allow '#', ':' and '.'.
|
||||||
|
$TMUX select-pane -T 'title#:.ok' || fail "command title rejected"
|
||||||
|
must_equal "$($TMUX display-message -p '#{pane_title}')" 'title#:.ok'
|
||||||
|
|
||||||
|
# Buffer names allow '#', ':' and '.'.
|
||||||
|
$TMUX set-buffer -b 'buffer#:.ok' data || fail "buffer name rejected"
|
||||||
|
must_equal "$($TMUX list-buffers -F '#{buffer_name}')" 'buffer#:.ok'
|
||||||
|
|
||||||
|
# Window names from escape sequences reject '#', ':' and '.' by cleaning them.
|
||||||
|
$TMUX send-keys "printf '\\033kescape#:.ok\\033\\\\'" Enter || exit 1
|
||||||
|
sleep 1
|
||||||
|
must_equal "$($TMUX display-message -p '#{window_name}')" 'escape___ok'
|
||||||
|
|
||||||
|
# Titles from escape sequences reject only '#'.
|
||||||
|
$TMUX send-keys "printf '\\033]2;escape#:.ok\\007'" Enter || exit 1
|
||||||
|
sleep 1
|
||||||
|
must_equal "$($TMUX display-message -p '#{pane_title}')" 'escape_:.ok'
|
||||||
|
|
||||||
|
# Invalid UTF-8 from escape sequences is ignored.
|
||||||
|
$TMUX rename-window 'before-invalid' || exit 1
|
||||||
|
$TMUX send-keys "printf '\\033kbad\\302name\\033\\\\'" Enter || exit 1
|
||||||
|
sleep 1
|
||||||
|
must_equal "$($TMUX display-message -p '#{window_name}')" 'before-invalid'
|
||||||
|
|
||||||
|
$TMUX select-pane -T 'before-invalid-title' || exit 1
|
||||||
|
$TMUX send-keys "printf '\\033]2;bad\\302title\\007'" Enter || exit 1
|
||||||
|
sleep 1
|
||||||
|
must_equal "$($TMUX display-message -p '#{pane_title}')" 'before-invalid-title'
|
||||||
|
|
||||||
|
$TMUX kill-server 2>/dev/null
|
||||||
|
exit 0
|
||||||
20
regress/command-alias.sh
Normal file
20
regress/command-alias.sh
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# command-alias expansion
|
||||||
|
|
||||||
|
PATH=/bin:/usr/bin
|
||||||
|
TERM=screen
|
||||||
|
|
||||||
|
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||||
|
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||||
|
$TMUX kill-server 2>/dev/null
|
||||||
|
|
||||||
|
$TMUX new-session -d -sfoo || exit 1
|
||||||
|
$TMUX split-window -d -tfoo:0.0 || exit 1
|
||||||
|
$TMUX set -s command-alias[100] zoom='resize-pane -Z' || exit 1
|
||||||
|
$TMUX zoom -tfoo:0.0 || exit 1
|
||||||
|
[ "$($TMUX display-message -p -tfoo:0.0 '#{window_zoomed_flag}')" = 1 ] || exit 1
|
||||||
|
|
||||||
|
$TMUX kill-server 2>/dev/null
|
||||||
|
|
||||||
|
exit 0
|
||||||
203
regress/floating-pane-geometry.sh
Normal file
203
regress/floating-pane-geometry.sh
Normal file
@@ -0,0 +1,203 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Test new-pane, resize-pane, and move-pane -x/-y/-X/-Y with floating panes.
|
||||||
|
# Verifies that size and position are correctly applied with the default border,
|
||||||
|
# with -B none, and with the pane-border-lines window option set to none. Also
|
||||||
|
# verifies that zero sizes are rejected.
|
||||||
|
#
|
||||||
|
# With a border, -x/-y/-X/-Y specify the onscreen footprint including the
|
||||||
|
# border: new-pane subtracts 2 from width/height and adds 1 to x/y-position
|
||||||
|
# so that the border lands on the specified screen coordinates. resize-pane
|
||||||
|
# -x/-y similarly subtracts 2 from the requested size. move-pane -X/-Y adds 1
|
||||||
|
# to the position. Without a border all values are used directly.
|
||||||
|
|
||||||
|
PATH=/bin:/usr/bin
|
||||||
|
TERM=screen
|
||||||
|
|
||||||
|
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||||
|
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||||
|
$TMUX kill-server 2>/dev/null
|
||||||
|
|
||||||
|
fail()
|
||||||
|
{
|
||||||
|
echo "$*" >&2
|
||||||
|
$TMUX kill-server 2>/dev/null
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
must_fail()
|
||||||
|
{
|
||||||
|
"$@" >/dev/null 2>&1 && fail "unexpected success: $*"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
must_equal()
|
||||||
|
{
|
||||||
|
got=$1
|
||||||
|
want=$2
|
||||||
|
[ "$got" = "$want" ] || fail "got '$got', expected '$want'"
|
||||||
|
}
|
||||||
|
|
||||||
|
$TMUX new-session -d -x 80 -y 24 || exit 1
|
||||||
|
|
||||||
|
# --- Default border (single-line) ---
|
||||||
|
|
||||||
|
# Explicit values: border subtracts 2 from size and adds 1 to position.
|
||||||
|
# -x 20 -> pane_width 18; -y 6 -> pane_height 4;
|
||||||
|
# -X 8 -> pane_left 9; -Y 3 -> pane_top 4.
|
||||||
|
id=$($TMUX new-pane -dPF '#{pane_id}' -x 20 -y 6 -X 8 -Y 3 'sleep 100') \
|
||||||
|
|| fail "new-pane with explicit geometry failed"
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_width}')" 18
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_height}')" 4
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_left}')" 9
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_top}')" 4
|
||||||
|
|
||||||
|
# resize-pane with border: requested size decremented by 2.
|
||||||
|
$TMUX resize-pane -t "$id" -x 30 || fail "resize-pane -x 30 failed"
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_width}')" 28
|
||||||
|
$TMUX resize-pane -t "$id" -y 10 || fail "resize-pane -y 10 failed"
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_height}')" 8
|
||||||
|
|
||||||
|
# resize-pane with percentage and border.
|
||||||
|
# 75% of 80 = 60, 60 - 2 = 58; 75% of 24 = 18, 18 - 2 = 16.
|
||||||
|
$TMUX resize-pane -t "$id" -x 75% || fail "resize-pane -x 75% failed"
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_width}')" 58
|
||||||
|
$TMUX resize-pane -t "$id" -y 75% || fail "resize-pane -y 75% failed"
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_height}')" 16
|
||||||
|
$TMUX kill-pane -t "$id" || exit 1
|
||||||
|
|
||||||
|
# Percentage width, height and position with border.
|
||||||
|
# 50% of 80 = 40, 40-2 = 38; 50% of 24 = 12, 12-2 = 10.
|
||||||
|
# 10% of 80 = 8, 8+1 = 9; 10% of 24 = 2, 2+1 = 3.
|
||||||
|
id=$($TMUX new-pane -dPF '#{pane_id}' -x 50% -y 50% -X 10% -Y 10% 'sleep 100') \
|
||||||
|
|| fail "new-pane with percentage geometry failed"
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_width}')" 38
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_height}')" 10
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_left}')" 9
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_top}')" 3
|
||||||
|
|
||||||
|
# move-pane -X/-Y with border: border lands at the given column/row, content
|
||||||
|
# is one cell inside. -X 5 -> pane_left 6; -Y 1 -> pane_top 2.
|
||||||
|
$TMUX move-pane -t "$id" -X 5 || fail "move-pane -X 5 failed"
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_left}')" 6
|
||||||
|
$TMUX move-pane -t "$id" -Y 1 || fail "move-pane -Y 1 failed"
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_top}')" 2
|
||||||
|
# 25% of 80 = 20, 20+1 = 21; 25% of 24 = 6, 6+1 = 7.
|
||||||
|
$TMUX move-pane -t "$id" -X 25% || fail "move-pane -X 25% failed"
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_left}')" 21
|
||||||
|
$TMUX move-pane -t "$id" -Y 25% || fail "move-pane -Y 25% failed"
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_top}')" 7
|
||||||
|
$TMUX kill-pane -t "$id" || exit 1
|
||||||
|
|
||||||
|
# --- -B none ---
|
||||||
|
|
||||||
|
# Without a border all values are used directly.
|
||||||
|
id=$($TMUX new-pane -dPF '#{pane_id}' -B none -x 20 -y 6 -X 8 -Y 3 'sleep 100') \
|
||||||
|
|| fail "new-pane -B none with explicit geometry failed"
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_width}')" 20
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_height}')" 6
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_left}')" 8
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_top}')" 3
|
||||||
|
|
||||||
|
# resize-pane without border: size used directly.
|
||||||
|
$TMUX resize-pane -t "$id" -x 30 || fail "resize-pane -x 30 failed"
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_width}')" 30
|
||||||
|
$TMUX resize-pane -t "$id" -y 10 || fail "resize-pane -y 10 failed"
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_height}')" 10
|
||||||
|
|
||||||
|
# resize-pane with percentage, no border: 75% of 80 = 60; 75% of 24 = 18.
|
||||||
|
$TMUX resize-pane -t "$id" -x 75% || fail "resize-pane -x 75% failed"
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_width}')" 60
|
||||||
|
$TMUX resize-pane -t "$id" -y 75% || fail "resize-pane -y 75% failed"
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_height}')" 18
|
||||||
|
$TMUX kill-pane -t "$id" || exit 1
|
||||||
|
|
||||||
|
# Percentage geometry without border: 50% of 80 = 40; 10% of 80 = 8 etc.
|
||||||
|
id=$($TMUX new-pane -dPF '#{pane_id}' -B none -x 50% -y 50% -X 10% -Y 10% 'sleep 100') \
|
||||||
|
|| fail "new-pane -B none with percentage geometry failed"
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_width}')" 40
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_height}')" 12
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_left}')" 8
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_top}')" 2
|
||||||
|
|
||||||
|
# move-pane without border: -X/-Y set the content position directly.
|
||||||
|
# -X 5 -> pane_left 5; -Y 1 -> pane_top 1.
|
||||||
|
$TMUX move-pane -t "$id" -X 5 || fail "move-pane -X 5 failed"
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_left}')" 5
|
||||||
|
$TMUX move-pane -t "$id" -Y 1 || fail "move-pane -Y 1 failed"
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_top}')" 1
|
||||||
|
# 25% of 80 = 20; 25% of 24 = 6.
|
||||||
|
$TMUX move-pane -t "$id" -X 25% || fail "move-pane -X 25% failed"
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_left}')" 20
|
||||||
|
$TMUX move-pane -t "$id" -Y 25% || fail "move-pane -Y 25% failed"
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_top}')" 6
|
||||||
|
$TMUX kill-pane -t "$id" || exit 1
|
||||||
|
|
||||||
|
# --- Window option pane-border-lines none ---
|
||||||
|
|
||||||
|
$TMUX set-option -w pane-border-lines none || exit 1
|
||||||
|
|
||||||
|
# Inherits none from window option: same behaviour as -B none.
|
||||||
|
id=$($TMUX new-pane -dPF '#{pane_id}' -x 20 -y 6 -X 8 -Y 3 'sleep 100') \
|
||||||
|
|| fail "new-pane with window pane-border-lines none failed"
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_width}')" 20
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_height}')" 6
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_left}')" 8
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_top}')" 3
|
||||||
|
|
||||||
|
$TMUX resize-pane -t "$id" -x 30 || fail "resize-pane -x 30 failed"
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_width}')" 30
|
||||||
|
$TMUX resize-pane -t "$id" -y 10 || fail "resize-pane -y 10 failed"
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_height}')" 10
|
||||||
|
|
||||||
|
$TMUX resize-pane -t "$id" -x 75% || fail "resize-pane -x 75% failed"
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_width}')" 60
|
||||||
|
$TMUX resize-pane -t "$id" -y 75% || fail "resize-pane -y 75% failed"
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_height}')" 18
|
||||||
|
$TMUX kill-pane -t "$id" || exit 1
|
||||||
|
|
||||||
|
id=$($TMUX new-pane -dPF '#{pane_id}' -x 50% -y 50% -X 10% -Y 10% 'sleep 100') \
|
||||||
|
|| fail "new-pane with window pane-border-lines none and percentages failed"
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_width}')" 40
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_height}')" 12
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_left}')" 8
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_top}')" 2
|
||||||
|
|
||||||
|
# move-pane with window pane-border-lines none: same behaviour as -B none.
|
||||||
|
$TMUX move-pane -t "$id" -X 5 || fail "move-pane -X 5 failed"
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_left}')" 5
|
||||||
|
$TMUX move-pane -t "$id" -Y 1 || fail "move-pane -Y 1 failed"
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_top}')" 1
|
||||||
|
$TMUX move-pane -t "$id" -X 25% || fail "move-pane -X 25% failed"
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_left}')" 20
|
||||||
|
$TMUX move-pane -t "$id" -Y 25% || fail "move-pane -Y 25% failed"
|
||||||
|
must_equal "$($TMUX display-message -p -t "$id" '#{pane_top}')" 6
|
||||||
|
$TMUX kill-pane -t "$id" || exit 1
|
||||||
|
|
||||||
|
# --- Invalid sizes ---
|
||||||
|
|
||||||
|
# Zero width and height must be rejected by new-pane with the default border.
|
||||||
|
$TMUX set-option -w -u pane-border-lines || exit 1
|
||||||
|
must_fail $TMUX new-pane -d -x 0 -y 6 -X 8 -Y 3 'sleep 100'
|
||||||
|
must_fail $TMUX new-pane -d -x 20 -y 0 -X 8 -Y 3 'sleep 100'
|
||||||
|
|
||||||
|
# Zero width and height must be rejected by resize-pane.
|
||||||
|
id=$($TMUX new-pane -dPF '#{pane_id}' -x 20 -y 6 -X 8 -Y 3 'sleep 100') \
|
||||||
|
|| fail "new-pane for resize-pane invalid size tests failed"
|
||||||
|
must_fail $TMUX resize-pane -t "$id" -x 0
|
||||||
|
must_fail $TMUX resize-pane -t "$id" -y 0
|
||||||
|
$TMUX kill-pane -t "$id" || exit 1
|
||||||
|
|
||||||
|
# Same rejections apply with no border.
|
||||||
|
$TMUX set-option -w pane-border-lines none || exit 1
|
||||||
|
must_fail $TMUX new-pane -d -x 0 -y 6 -X 8 -Y 3 'sleep 100'
|
||||||
|
must_fail $TMUX new-pane -d -x 20 -y 0 -X 8 -Y 3 'sleep 100'
|
||||||
|
|
||||||
|
id=$($TMUX new-pane -dPF '#{pane_id}' -x 20 -y 6 -X 8 -Y 3 'sleep 100') \
|
||||||
|
|| fail "new-pane for resize-pane invalid size tests (no border) failed"
|
||||||
|
must_fail $TMUX resize-pane -t "$id" -x 0
|
||||||
|
must_fail $TMUX resize-pane -t "$id" -y 0
|
||||||
|
$TMUX kill-pane -t "$id" || exit 1
|
||||||
|
|
||||||
|
$TMUX kill-server 2>/dev/null
|
||||||
|
exit 0
|
||||||
@@ -67,6 +67,7 @@ $TMUX set @true 1 || exit 1
|
|||||||
$TMUX set @false 0 || exit 1
|
$TMUX set @false 0 || exit 1
|
||||||
$TMUX set @warm Summer || exit 1
|
$TMUX set @warm Summer || exit 1
|
||||||
$TMUX set @cold Winter || exit 1
|
$TMUX set @cold Winter || exit 1
|
||||||
|
$TMUX set @v 'foo:bar' || exit 1
|
||||||
|
|
||||||
# Plain string without substitutions et al
|
# Plain string without substitutions et al
|
||||||
test_format "abc xyz" "abc xyz"
|
test_format "abc xyz" "abc xyz"
|
||||||
@@ -74,6 +75,8 @@ test_format "abc xyz" "abc xyz"
|
|||||||
# Test basic escapes for "#", "{", "#{" "}", "#}", ","
|
# Test basic escapes for "#", "{", "#{" "}", "#}", ","
|
||||||
test_format "##" "#"
|
test_format "##" "#"
|
||||||
test_format "#," ","
|
test_format "#," ","
|
||||||
|
test_format "#{s/#:/_/:@v}" "foo_bar"
|
||||||
|
test_format "#{s/o/#:/:@v}" "f:::bar"
|
||||||
test_format "{" "{"
|
test_format "{" "{"
|
||||||
test_format "##{" "#{"
|
test_format "##{" "#{"
|
||||||
test_format "#}" "}"
|
test_format "#}" "}"
|
||||||
|
|||||||
300
regress/prompt-keys.sh
Normal file
300
regress/prompt-keys.sh
Normal file
@@ -0,0 +1,300 @@
|
|||||||
|
#!/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="$TEST_TMUX -Ltest -f/dev/null" # outer (host for the client)
|
||||||
|
IN="$TEST_TMUX -Ltest2 -f/dev/null" # inner (under test)
|
||||||
|
|
||||||
|
$OUT kill-server 2>/dev/null
|
||||||
|
$IN kill-server 2>/dev/null
|
||||||
|
trap "$OUT kill-server 2>/dev/null; $IN kill-server 2>/dev/null" EXIT
|
||||||
|
|
||||||
|
fail() {
|
||||||
|
echo "[FAIL] $1"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Capture the outer pane: what the inner client rendered. No -e, so we match
|
||||||
|
# plain visible text, not styles or escape sequences.
|
||||||
|
capture() {
|
||||||
|
$OUT capture-pane -p
|
||||||
|
}
|
||||||
|
|
||||||
|
# The "(search) ..." prompt row of a mode prompt.
|
||||||
|
search_row() {
|
||||||
|
capture | grep '(search)' | head -1
|
||||||
|
}
|
||||||
|
|
||||||
|
# The inner status line is the last row of the outer capture (status is at the
|
||||||
|
# bottom). Used to assert a prompt is in the pane and not on the status line.
|
||||||
|
status_line() {
|
||||||
|
capture | tail -1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Inner mode must still be a tree mode (the prompt did not close or crash it).
|
||||||
|
in_tree_mode() {
|
||||||
|
[ "$($IN display-message -p '#{pane_mode}')" = "tree-mode" ]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Small settle for the key -> inner server -> inner client -> outer pane round
|
||||||
|
# trip to redraw before we capture. Matches the short waits other regress tests
|
||||||
|
# use; we do not depend on exact timing beyond the redraw completing.
|
||||||
|
settle() {
|
||||||
|
sleep 0.5
|
||||||
|
}
|
||||||
|
|
||||||
|
# Assert the mode search prompt currently shows exactly "(search) <want>".
|
||||||
|
search_is() {
|
||||||
|
want=$1; msg=$2
|
||||||
|
search_row | grep -qF "(search) $want" || \
|
||||||
|
fail "$msg (wanted '(search) $want', got '$(search_row)')"
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Inner session under test. ---------------------------------------------
|
||||||
|
#
|
||||||
|
# Two windows so the tree has content; status on so we can distinguish the pane
|
||||||
|
# from the status line; fixed size and manual sizing so the layout is stable.
|
||||||
|
# A root-table key opens a status-line command prompt whose accept action writes
|
||||||
|
# the final buffer into @r, so we can recover it exactly.
|
||||||
|
$IN new -d -x80 -y24 "sh -c 'exec sleep 1000'" || exit 1
|
||||||
|
$IN set -g status on || exit 1
|
||||||
|
$IN set -g status-position bottom || exit 1
|
||||||
|
$IN set -g status-keys emacs || exit 1
|
||||||
|
$IN set -g window-size manual || exit 1
|
||||||
|
$IN new-window -d "sh -c 'exec sleep 1000'" || exit 1
|
||||||
|
$IN bind -n M-r command-prompt -p ">" "set -g @r '%%'" || exit 1
|
||||||
|
|
||||||
|
# --- Outer session: attach the inner one inside its pane. -------------------
|
||||||
|
$OUT new -d -x80 -y24 || exit 1
|
||||||
|
$OUT set -g status off || exit 1
|
||||||
|
$OUT set -g window-size manual || exit 1
|
||||||
|
$OUT send-keys -l "$IN attach" || exit 1
|
||||||
|
$OUT send-keys Enter || exit 1
|
||||||
|
sleep 1
|
||||||
|
|
||||||
|
# ===========================================================================
|
||||||
|
# Mode prompt (choose-tree search): the thorough engine vehicle.
|
||||||
|
# ===========================================================================
|
||||||
|
|
||||||
|
$IN choose-tree || exit 1
|
||||||
|
settle
|
||||||
|
in_tree_mode || fail "choose-tree did not enter tree-mode"
|
||||||
|
|
||||||
|
# --- 1. Search prompt is drawn in the pane, not on the status line. ---
|
||||||
|
$IN send-keys C-s || exit 1
|
||||||
|
settle
|
||||||
|
search_row | grep -q '(search)' || fail "search prompt not drawn in the pane"
|
||||||
|
status_line | grep -q '(search)' && \
|
||||||
|
fail "search prompt drawn on the status line, not in the pane"
|
||||||
|
|
||||||
|
# --- 2. emacs editing: insert and delete at middle, start and end. ---
|
||||||
|
# Cursor position is checked behaviourally: move, insert a marker, read the row.
|
||||||
|
# This needs no cursor coordinates and fails if a movement/edit key is wrong.
|
||||||
|
|
||||||
|
# Middle insert: "abcd", Left Left (cursor between b and c), insert X -> abXcd.
|
||||||
|
$IN send-keys -l "abcd" || exit 1
|
||||||
|
settle
|
||||||
|
search_is "abcd" "literal input not shown in search prompt"
|
||||||
|
$IN send-keys Left Left || exit 1
|
||||||
|
$IN send-keys -l "X" || exit 1
|
||||||
|
settle
|
||||||
|
search_is "abXcd" "middle insert wrong (Left/insert)"
|
||||||
|
|
||||||
|
# Middle delete: BSpace removes X (before cursor), DC removes c (at cursor).
|
||||||
|
$IN send-keys BSpace || exit 1
|
||||||
|
$IN send-keys DC || exit 1
|
||||||
|
settle
|
||||||
|
search_is "abd" "middle delete wrong (BSpace/Delete)"
|
||||||
|
|
||||||
|
# Clear, then start/end insert with C-a and C-e.
|
||||||
|
$IN send-keys C-u || exit 1
|
||||||
|
$IN send-keys -l "mno" || exit 1
|
||||||
|
$IN send-keys C-a || exit 1
|
||||||
|
$IN send-keys -l "S" || exit 1
|
||||||
|
$IN send-keys C-e || exit 1
|
||||||
|
$IN send-keys -l "E" || exit 1
|
||||||
|
settle
|
||||||
|
search_is "SmnoE" "C-a/C-e start/end insert wrong"
|
||||||
|
|
||||||
|
# Word kill: "hello world", C-w removes the last word leaving "hello " (with the
|
||||||
|
# separating space). capture-pane trims trailing spaces, so make the space
|
||||||
|
# visible by inserting a marker after it: the buffer becomes "hello Z".
|
||||||
|
$IN send-keys C-u || exit 1
|
||||||
|
$IN send-keys -l "hello world" || exit 1
|
||||||
|
$IN send-keys C-w || exit 1
|
||||||
|
$IN send-keys -l "Z" || exit 1
|
||||||
|
settle
|
||||||
|
search_is "hello Z" "C-w did not kill a word"
|
||||||
|
|
||||||
|
# C-a then C-k kills the whole line.
|
||||||
|
$IN send-keys C-a || exit 1
|
||||||
|
$IN send-keys C-k || exit 1
|
||||||
|
settle
|
||||||
|
search_row | grep -q '(search) [^ ]' && fail "C-a C-k did not clear the line"
|
||||||
|
|
||||||
|
# --- 3. Editing kept the prompt open the whole time. ---
|
||||||
|
in_tree_mode || fail "editing keys closed the mode"
|
||||||
|
search_row | grep -q '(search)' || fail "editing keys closed the prompt"
|
||||||
|
|
||||||
|
# --- 4. Unicode wide character: insert, render, delete as one unit. ---
|
||||||
|
$IN send-keys C-u || exit 1
|
||||||
|
$IN send-keys -l "a中b" || exit 1
|
||||||
|
settle
|
||||||
|
search_is "a中b" "wide character not shown"
|
||||||
|
# Left moves over "b" (one column); BSpace deletes the wide "中" as a single
|
||||||
|
# width-2 unit, leaving "ab".
|
||||||
|
$IN send-keys Left || exit 1
|
||||||
|
$IN send-keys BSpace || exit 1
|
||||||
|
settle
|
||||||
|
search_is "ab" "wide character not deleted as one unit"
|
||||||
|
|
||||||
|
# --- 5. Control character: quote-next inserts it literally, shown as ^G. ---
|
||||||
|
$IN send-keys C-u || exit 1
|
||||||
|
$IN send-keys -l "a" || exit 1
|
||||||
|
$IN send-keys C-v || exit 1 # quote next key
|
||||||
|
$IN send-keys C-g || exit 1 # literal BEL -> displayed as ^G
|
||||||
|
$IN send-keys -l "b" || exit 1
|
||||||
|
settle
|
||||||
|
search_is "a^Gb" "control character not shown as ^G"
|
||||||
|
# Deleted as a single unit too.
|
||||||
|
$IN send-keys Left || exit 1
|
||||||
|
$IN send-keys BSpace || exit 1
|
||||||
|
settle
|
||||||
|
search_is "ab" "control character not deleted as one unit"
|
||||||
|
|
||||||
|
# --- 6. Kill and yank: C-w fills the yank buffer, C-y pastes it at the cursor. ---
|
||||||
|
# (prompt_key only fills the yank buffer from C-w; C-y then yanks that text, or
|
||||||
|
# the top paste buffer if nothing has been killed. Establish our own kill here
|
||||||
|
# so the result is deterministic.)
|
||||||
|
$IN send-keys C-u || exit 1
|
||||||
|
$IN send-keys -l "one two" || exit 1
|
||||||
|
$IN send-keys C-w || exit 1 # kill "two", buffer "one "
|
||||||
|
$IN send-keys C-y || exit 1 # yank it back -> "one two"
|
||||||
|
settle
|
||||||
|
search_is "one two" "C-y did not yank the killed text"
|
||||||
|
$IN send-keys C-y || exit 1 # yank again at cursor -> "one twotwo"
|
||||||
|
settle
|
||||||
|
search_is "one twotwo" "second C-y did not yank again"
|
||||||
|
|
||||||
|
# --- 7. History: accept a string, reopen, Up recalls it. ---
|
||||||
|
$IN send-keys C-u || exit 1
|
||||||
|
$IN send-keys -l "alpha" || exit 1
|
||||||
|
$IN send-keys Enter || exit 1
|
||||||
|
settle
|
||||||
|
$IN send-keys C-s || exit 1
|
||||||
|
settle
|
||||||
|
$IN send-keys Up || exit 1
|
||||||
|
settle
|
||||||
|
search_is "alpha" "history (Up) did not recall the previous entry"
|
||||||
|
|
||||||
|
# --- 8. Escape closes the prompt but leaves the mode open. ---
|
||||||
|
$IN send-keys Escape || exit 1
|
||||||
|
settle
|
||||||
|
search_row | grep -q '(search)' && fail "Escape left a dangling search prompt"
|
||||||
|
in_tree_mode || fail "Escape closed the mode as well as the prompt"
|
||||||
|
|
||||||
|
# Leave the mode.
|
||||||
|
$IN send-keys q || exit 1
|
||||||
|
settle
|
||||||
|
|
||||||
|
# ===========================================================================
|
||||||
|
# Status-line prompt (command-prompt): the same engine on the status line.
|
||||||
|
# Keys go through the inner client's terminal (outer send-keys); the accepted
|
||||||
|
# buffer is recovered exactly via %% -> @r.
|
||||||
|
# ===========================================================================
|
||||||
|
|
||||||
|
# --- 10. Prompt is drawn on the status line (the last row). ---
|
||||||
|
$IN set -g @r "" || exit 1
|
||||||
|
$OUT send-keys M-r || exit 1
|
||||||
|
settle
|
||||||
|
status_line | grep -q '>' || fail "status-line prompt not drawn on the status line"
|
||||||
|
|
||||||
|
# --- 11. emacs cursor-marker edit, accept recovers the exact buffer. ---
|
||||||
|
$OUT send-keys -l "abc" || exit 1
|
||||||
|
$OUT send-keys Home || exit 1
|
||||||
|
$OUT send-keys -l "X" || exit 1
|
||||||
|
settle
|
||||||
|
status_line | grep -qF "> Xabc" || \
|
||||||
|
fail "status-line edit wrong (got '$(status_line)')"
|
||||||
|
$OUT send-keys Enter || exit 1
|
||||||
|
settle
|
||||||
|
[ "$($IN show -gv @r)" = "Xabc" ] || \
|
||||||
|
fail "status-line accept recovered '$($IN show -gv @r)', wanted 'Xabc'"
|
||||||
|
|
||||||
|
# --- 12. Unicode on the status line: insert, move, delete wide char. ---
|
||||||
|
$IN set -g @r "" || exit 1
|
||||||
|
$OUT send-keys M-r || exit 1
|
||||||
|
settle
|
||||||
|
$OUT send-keys -l "a㋡b" || exit 1
|
||||||
|
settle
|
||||||
|
status_line | grep -qF "a㋡b" || \
|
||||||
|
fail "status-line wide character not shown (got '$(status_line)')"
|
||||||
|
# Home, insert Z (start); End, BSpace (delete b); BSpace (delete wide char).
|
||||||
|
$OUT send-keys Home || exit 1
|
||||||
|
$OUT send-keys -l "Z" || exit 1
|
||||||
|
$OUT send-keys End || exit 1
|
||||||
|
$OUT send-keys BSpace || exit 1
|
||||||
|
$OUT send-keys BSpace || exit 1
|
||||||
|
settle
|
||||||
|
$OUT send-keys Enter || exit 1
|
||||||
|
settle
|
||||||
|
[ "$($IN show -gv @r)" = "Za" ] || \
|
||||||
|
fail "status-line wide edit recovered '$($IN show -gv @r)', wanted 'Za'"
|
||||||
|
|
||||||
|
# --- 13. Overflow: more text than fits stays within the line and is kept. ---
|
||||||
|
big="0123456789012345678901234567890123456789012345678901234567890123456789ABCDEFGHIJ"
|
||||||
|
$IN set -g @r "" || exit 1
|
||||||
|
$OUT send-keys M-r || exit 1
|
||||||
|
settle
|
||||||
|
$OUT send-keys -l "$big" || exit 1
|
||||||
|
settle
|
||||||
|
# The drawn status line must not exceed the client width (80): no wrap, no crash.
|
||||||
|
width=$(status_line | awk '{print length($0)}')
|
||||||
|
[ "$width" -le 80 ] || fail "overflowing prompt drew $width columns, wider than 80"
|
||||||
|
$OUT send-keys Enter || exit 1
|
||||||
|
settle
|
||||||
|
# The whole buffer was kept despite only part being visible.
|
||||||
|
[ "$($IN show -gv @r)" = "$big" ] || fail "overflowing prompt lost buffer content"
|
||||||
|
|
||||||
|
# --- 14. Escape closes the status-line prompt cleanly. ---
|
||||||
|
$IN set -g @r "SENTINEL" || exit 1
|
||||||
|
$OUT send-keys M-r || exit 1
|
||||||
|
settle
|
||||||
|
$OUT send-keys -l "discard" || exit 1
|
||||||
|
$OUT send-keys Escape || exit 1
|
||||||
|
settle
|
||||||
|
status_line | grep -q '> discard' && fail "Escape left a dangling status-line prompt"
|
||||||
|
[ "$($IN show -gv @r)" = "SENTINEL" ] || fail "Escape ran the prompt's accept action"
|
||||||
|
|
||||||
|
# ===========================================================================
|
||||||
|
# Two clients attached to the same window: a mode prompt must render on both.
|
||||||
|
# ===========================================================================
|
||||||
|
|
||||||
|
$OUT new-window || exit 1
|
||||||
|
$OUT set -g status off || exit 1
|
||||||
|
$OUT send-keys -l "$IN attach" || exit 1
|
||||||
|
$OUT send-keys Enter || exit 1
|
||||||
|
sleep 1
|
||||||
|
|
||||||
|
$IN choose-tree || exit 1
|
||||||
|
settle
|
||||||
|
$IN send-keys C-s || exit 1
|
||||||
|
settle
|
||||||
|
$IN send-keys -l "dual" || exit 1
|
||||||
|
settle
|
||||||
|
for w in $($OUT list-windows -F '#{window_index}'); do
|
||||||
|
$OUT capture-pane -t ":$w" -p | grep -qF "(search) dual" || \
|
||||||
|
fail "mode prompt not shown on client in outer window $w"
|
||||||
|
done
|
||||||
|
$IN send-keys Escape || exit 1
|
||||||
|
settle
|
||||||
|
|
||||||
|
# --- Inner tmux is still alive and responsive. ---
|
||||||
|
$IN display-message -p '#{version}' >/dev/null 2>&1 || fail "inner tmux died"
|
||||||
|
|
||||||
|
exit 0
|
||||||
336
regress/prompt-mechanics.sh
Normal file
336
regress/prompt-mechanics.sh
Normal file
@@ -0,0 +1,336 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Exercise the prompt mechanics shared by all three host paths of the prompt
|
||||||
|
# engine in prompt.c:
|
||||||
|
#
|
||||||
|
# status.c status_prompt_set - the status-line command prompt.
|
||||||
|
# window.c window_pane_set_prompt - a prompt drawn over a pane (-P).
|
||||||
|
# mode-tree.c mode_tree_set_prompt - search/filter prompts in tree modes.
|
||||||
|
#
|
||||||
|
# prompt-keys.sh covers the editing keys; this test covers that each path OPENS
|
||||||
|
# and DRAWS in the right place and that the prompt flags select the right engine
|
||||||
|
# behaviour: -1 (single), -N (numeric), -i (incremental), -k (key), -e
|
||||||
|
# (backspace exit), -I (prefill), multi prompts, type-scoped history and command
|
||||||
|
# completion.
|
||||||
|
|
||||||
|
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="$TEST_TMUX -Ltest -f/dev/null" # outer (host for the client)
|
||||||
|
IN="$TEST_TMUX -Ltest2 -f/dev/null" # inner (under test)
|
||||||
|
|
||||||
|
$OUT kill-server 2>/dev/null
|
||||||
|
$IN kill-server 2>/dev/null
|
||||||
|
trap "$OUT kill-server 2>/dev/null; $IN kill-server 2>/dev/null" EXIT
|
||||||
|
|
||||||
|
fail() {
|
||||||
|
echo "[FAIL] $1"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Capture the outer pane: what the inner client rendered. Pane-area prompts
|
||||||
|
# (over a pane or in a tree mode) and the status-line prompt all end up here.
|
||||||
|
capture() {
|
||||||
|
$OUT capture-pane -p
|
||||||
|
}
|
||||||
|
|
||||||
|
# The inner status line is the last row of the outer capture.
|
||||||
|
status_line() {
|
||||||
|
capture | tail -1
|
||||||
|
}
|
||||||
|
|
||||||
|
# The recovered buffer. Every prompt below accepts into the @r option so the
|
||||||
|
# exact final string can be checked; reset it to a sentinel first so we can tell
|
||||||
|
# "accept ran" from "prompt cancelled".
|
||||||
|
got() {
|
||||||
|
$IN show -gv @r
|
||||||
|
}
|
||||||
|
reset() {
|
||||||
|
$IN set -g @r "SENTINEL" || exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Settle for the key -> inner server -> inner client -> outer pane redraw round
|
||||||
|
# trip, as in prompt-keys.sh.
|
||||||
|
settle() {
|
||||||
|
sleep 0.5
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Inner session under test. ---------------------------------------------
|
||||||
|
#
|
||||||
|
# The window is created at -y23 so that, with a one-row bottom status, the pane
|
||||||
|
# area (23) exactly fills the 24-row client: a pane prompt drawn on the pane's
|
||||||
|
# bottom row lands on visible row 23, just above the status line on row 24. A
|
||||||
|
# second, distinctively named window gives the tree something to filter.
|
||||||
|
$IN new -d -x80 -y23 -n YAK "sh -c 'exec sleep 1000'" || exit 1
|
||||||
|
$IN set -g status on || exit 1
|
||||||
|
$IN set -g status-position bottom || exit 1
|
||||||
|
$IN set -g status-keys emacs || exit 1
|
||||||
|
$IN set -g window-size manual || exit 1
|
||||||
|
$IN new-window -d -n ZEBRA "sh -c 'exec sleep 1000'" || exit 1
|
||||||
|
|
||||||
|
# One root-table key per path/flag. The accept template records the final
|
||||||
|
# buffer in @r (or both buffers, for the multi-prompt case).
|
||||||
|
$IN bind -n M-s command-prompt -p '(stat)' "set -g @r '%%'" || exit 1
|
||||||
|
$IN bind -n M-p command-prompt -P -p '(pane)' "set -g @r '%%'" || exit 1
|
||||||
|
$IN bind -n M-o command-prompt -P -1 -p '(one)' "set -g @r '%%'" || exit 1
|
||||||
|
$IN bind -n M-n command-prompt -P -N -I 5 -p '(num)' "set -g @r '%%'" || exit 1
|
||||||
|
$IN bind -n M-i command-prompt -P -i -p '(inc)' "set -g @r '%%'" || exit 1
|
||||||
|
$IN bind -n M-k command-prompt -P -k -p '(key)' "set -g @r '%%'" || exit 1
|
||||||
|
$IN bind -n M-e command-prompt -P -e -p '(bs)' "set -g @r '%%'" || exit 1
|
||||||
|
$IN bind -n M-j command-prompt -P -I hello -p '(pre)' "set -g @r '%%'" || exit 1
|
||||||
|
$IN bind -n M-m command-prompt -p 'first,second' "set -g @r '%1/%2'" || exit 1
|
||||||
|
$IN bind -n M-c command-prompt -p '(cmd)' "set -g @r '%%'" || exit 1
|
||||||
|
$IN bind -n M-h command-prompt -T search -p '(srch)' "set -g @r '%%'" || exit 1
|
||||||
|
|
||||||
|
# --- Outer session: attach the inner one inside its pane. -------------------
|
||||||
|
$OUT new -d -x80 -y24 || exit 1
|
||||||
|
$OUT set -g status off || exit 1
|
||||||
|
$OUT set -g window-size manual || exit 1
|
||||||
|
$OUT send-keys -l "$IN attach" || exit 1
|
||||||
|
$OUT send-keys Enter || exit 1
|
||||||
|
sleep 1
|
||||||
|
|
||||||
|
# ===========================================================================
|
||||||
|
# 1. Each path opens and draws in the right place.
|
||||||
|
# ===========================================================================
|
||||||
|
|
||||||
|
# --- 1a. status.c: drawn on the status line (the last row). ---
|
||||||
|
reset
|
||||||
|
$OUT send-keys M-s || exit 1
|
||||||
|
settle
|
||||||
|
status_line | grep -qF '(stat)' || \
|
||||||
|
fail "status-line prompt not on the status line (got '$(status_line)')"
|
||||||
|
$OUT send-keys -l "go" || exit 1
|
||||||
|
$OUT send-keys Enter || exit 1
|
||||||
|
settle
|
||||||
|
[ "$(got)" = "go" ] || fail "status-line accept recovered '$(got)', wanted 'go'"
|
||||||
|
|
||||||
|
# --- 1b. window.c: drawn over the pane, not on the status line. ---
|
||||||
|
reset
|
||||||
|
$OUT send-keys M-p || exit 1
|
||||||
|
settle
|
||||||
|
capture | grep -qF '(pane)' || fail "pane prompt not drawn in the pane"
|
||||||
|
status_line | grep -qF '(pane)' && \
|
||||||
|
fail "pane prompt drawn on the status line, not over the pane"
|
||||||
|
$OUT send-keys -l "deep" || exit 1
|
||||||
|
$OUT send-keys Enter || exit 1
|
||||||
|
settle
|
||||||
|
[ "$(got)" = "deep" ] || fail "pane prompt accept recovered '$(got)', wanted 'deep'"
|
||||||
|
|
||||||
|
# --- 1c. mode-tree.c: search prompt drawn in the pane. ---
|
||||||
|
$IN choose-tree || exit 1
|
||||||
|
settle
|
||||||
|
[ "$($IN display-message -p '#{pane_mode}')" = "tree-mode" ] || \
|
||||||
|
fail "choose-tree did not enter tree-mode"
|
||||||
|
$IN send-keys C-s || exit 1
|
||||||
|
settle
|
||||||
|
capture | grep -qF '(search)' || fail "mode-tree search prompt not drawn in the pane"
|
||||||
|
status_line | grep -qF '(search)' && \
|
||||||
|
fail "mode-tree search prompt drawn on the status line"
|
||||||
|
$IN send-keys Escape || exit 1
|
||||||
|
settle
|
||||||
|
|
||||||
|
# --- 1d. mode-tree.c: filter prompt opens, applies, prefills, and clears. ---
|
||||||
|
$IN send-keys f || exit 1
|
||||||
|
settle
|
||||||
|
capture | grep -qF '(filter)' || fail "mode-tree filter prompt not drawn"
|
||||||
|
$IN send-keys -l "ZEBRA" || exit 1
|
||||||
|
$IN send-keys Enter || exit 1
|
||||||
|
settle
|
||||||
|
capture | grep -q 'filter: active' || fail "accepting the filter did not apply it"
|
||||||
|
# Reopening the filter prompt prefills it with the current filter.
|
||||||
|
$IN send-keys f || exit 1
|
||||||
|
settle
|
||||||
|
capture | grep -qF '(filter) ZEBRA' || \
|
||||||
|
fail "filter prompt not prefilled with the current filter"
|
||||||
|
$IN send-keys Escape || exit 1
|
||||||
|
settle
|
||||||
|
# 'c' clears the filter.
|
||||||
|
$IN send-keys c || exit 1
|
||||||
|
settle
|
||||||
|
capture | grep -q 'filter: active' && fail "'c' did not clear the filter"
|
||||||
|
$IN send-keys q || exit 1
|
||||||
|
settle
|
||||||
|
|
||||||
|
# ===========================================================================
|
||||||
|
# 2. Flags select the right engine behaviour.
|
||||||
|
# ===========================================================================
|
||||||
|
|
||||||
|
# --- 2a. -1 (PROMPT_SINGLE): one keystroke closes and accepts that char. ---
|
||||||
|
reset
|
||||||
|
$OUT send-keys M-o || exit 1
|
||||||
|
settle
|
||||||
|
capture | grep -qF '(one)' || fail "single prompt did not open"
|
||||||
|
$OUT send-keys -l "q" || exit 1
|
||||||
|
settle
|
||||||
|
[ "$(got)" = "q" ] || fail "single prompt recovered '$(got)', wanted 'q'"
|
||||||
|
capture | grep -qF '(one)' && fail "single prompt stayed open after one key"
|
||||||
|
|
||||||
|
# --- 2b. -N (PROMPT_NUMERIC): prefilled, digits append, non-digit closes. ---
|
||||||
|
reset
|
||||||
|
$OUT send-keys M-n || exit 1
|
||||||
|
settle
|
||||||
|
capture | grep -qF '(num) 5' || fail "numeric prompt not prefilled with 5"
|
||||||
|
$OUT send-keys -l "7" || exit 1 # 57
|
||||||
|
$OUT send-keys Enter || exit 1 # Enter is a non-digit: close
|
||||||
|
settle
|
||||||
|
[ "$(got)" = "57" ] || fail "numeric accept recovered '$(got)', wanted '57'"
|
||||||
|
# A non-digit key closes the prompt with the existing buffer, dropping the key.
|
||||||
|
reset
|
||||||
|
$OUT send-keys M-n || exit 1
|
||||||
|
settle
|
||||||
|
$OUT send-keys -l "x" || exit 1
|
||||||
|
settle
|
||||||
|
[ "$(got)" = "5" ] || fail "numeric non-digit close recovered '$(got)', wanted '5'"
|
||||||
|
capture | grep -qF '(num)' && fail "numeric prompt stayed open after a non-digit"
|
||||||
|
|
||||||
|
# --- 2c. -i (PROMPT_INCREMENTAL): callback fires on every edit, stays open. ---
|
||||||
|
# The incremental code path prefixes the buffer with '=' (or +/-), so the '='
|
||||||
|
# proves the value came through the incremental callback, not a plain accept.
|
||||||
|
reset
|
||||||
|
$OUT send-keys M-i || exit 1
|
||||||
|
settle
|
||||||
|
[ "$(got)" = "=" ] || fail "incremental prompt did not fire on open (got '$(got)')"
|
||||||
|
$OUT send-keys -l "a" || exit 1
|
||||||
|
settle
|
||||||
|
[ "$(got)" = "=a" ] || fail "incremental did not fire after 'a' (got '$(got)')"
|
||||||
|
$OUT send-keys -l "b" || exit 1
|
||||||
|
settle
|
||||||
|
[ "$(got)" = "=ab" ] || fail "incremental did not fire after 'b' (got '$(got)')"
|
||||||
|
capture | grep -qF '(inc)' || fail "incremental prompt closed during editing"
|
||||||
|
$OUT send-keys Escape || exit 1
|
||||||
|
settle
|
||||||
|
capture | grep -qF '(inc)' && fail "Escape did not close the incremental prompt"
|
||||||
|
|
||||||
|
# --- 2d. -k (PROMPT_KEY): the next key closes and delivers its name. ---
|
||||||
|
reset
|
||||||
|
$OUT send-keys M-k || exit 1
|
||||||
|
settle
|
||||||
|
capture | grep -qF '(key)' || fail "key prompt did not open"
|
||||||
|
$OUT send-keys -l "z" || exit 1
|
||||||
|
settle
|
||||||
|
[ "$(got)" = "z" ] || fail "key prompt recovered '$(got)', wanted 'z'"
|
||||||
|
capture | grep -qF '(key)' && fail "key prompt stayed open after a key"
|
||||||
|
|
||||||
|
# --- 2e. -e (PROMPT_BSPACE_EXIT): backspace on empty cancels (no accept). ---
|
||||||
|
reset
|
||||||
|
$OUT send-keys M-e || exit 1
|
||||||
|
settle
|
||||||
|
$OUT send-keys BSpace || exit 1
|
||||||
|
settle
|
||||||
|
[ "$(got)" = "SENTINEL" ] || fail "backspace-exit ran the accept action (got '$(got)')"
|
||||||
|
capture | grep -qF '(bs)' && fail "backspace on empty did not close the prompt"
|
||||||
|
|
||||||
|
# --- 2f. -I (prefill): prompt opens with the given buffer. ---
|
||||||
|
reset
|
||||||
|
$OUT send-keys M-j || exit 1
|
||||||
|
settle
|
||||||
|
capture | grep -qF '(pre) hello' || fail "prefill not shown (got '$(capture | grep -F '(pre)')')"
|
||||||
|
$OUT send-keys Enter || exit 1
|
||||||
|
settle
|
||||||
|
[ "$(got)" = "hello" ] || fail "prefill accept recovered '$(got)', wanted 'hello'"
|
||||||
|
|
||||||
|
# --- 2g. Multi prompt: accept advances to the next, both are delivered. ---
|
||||||
|
reset
|
||||||
|
$OUT send-keys M-m || exit 1
|
||||||
|
settle
|
||||||
|
capture | grep -qF 'first' || fail "first of multi prompt not shown"
|
||||||
|
$OUT send-keys -l "X" || exit 1
|
||||||
|
$OUT send-keys Enter || exit 1
|
||||||
|
settle
|
||||||
|
capture | grep -qF 'second' || fail "multi prompt did not advance to the second"
|
||||||
|
$OUT send-keys -l "Y" || exit 1
|
||||||
|
$OUT send-keys Enter || exit 1
|
||||||
|
settle
|
||||||
|
[ "$(got)" = "X/Y" ] || fail "multi prompt recovered '$(got)', wanted 'X/Y'"
|
||||||
|
|
||||||
|
# ===========================================================================
|
||||||
|
# 3. Type-scoped history and command completion.
|
||||||
|
# ===========================================================================
|
||||||
|
|
||||||
|
# --- 3a. Command history is recalled with Up; search history is separate. ---
|
||||||
|
reset
|
||||||
|
$OUT send-keys M-c || exit 1
|
||||||
|
settle
|
||||||
|
$OUT send-keys -l "alpha" || exit 1
|
||||||
|
$OUT send-keys Enter || exit 1
|
||||||
|
settle
|
||||||
|
[ "$(got)" = "alpha" ] || fail "command prompt accept recovered '$(got)'"
|
||||||
|
# Reopen the command prompt: Up recalls the command-type entry.
|
||||||
|
$OUT send-keys M-c || exit 1
|
||||||
|
settle
|
||||||
|
$OUT send-keys Up || exit 1
|
||||||
|
settle
|
||||||
|
capture | grep -qF '(cmd) alpha' || fail "Up did not recall command history"
|
||||||
|
$OUT send-keys Escape || exit 1
|
||||||
|
settle
|
||||||
|
# A search-type prompt must NOT recall the command-type entry (separate rings).
|
||||||
|
$OUT send-keys M-h || exit 1
|
||||||
|
settle
|
||||||
|
$OUT send-keys Up || exit 1
|
||||||
|
settle
|
||||||
|
capture | grep -qF 'alpha' && fail "search prompt recalled command-type history"
|
||||||
|
$OUT send-keys Escape || exit 1
|
||||||
|
settle
|
||||||
|
|
||||||
|
# --- 3b. Tab completion works in a command prompt (command type only). ---
|
||||||
|
$OUT send-keys M-c || exit 1
|
||||||
|
settle
|
||||||
|
$OUT send-keys -l "new-w" || exit 1
|
||||||
|
$OUT send-keys Tab || exit 1
|
||||||
|
settle
|
||||||
|
status_line | grep -qF 'new-window' || \
|
||||||
|
fail "Tab did not complete new-w to new-window (got '$(status_line)')"
|
||||||
|
$OUT send-keys Escape || exit 1
|
||||||
|
settle
|
||||||
|
# A search-type prompt does not complete commands: Tab is literal / inert.
|
||||||
|
$OUT send-keys M-h || exit 1
|
||||||
|
settle
|
||||||
|
$OUT send-keys -l "new-w" || exit 1
|
||||||
|
$OUT send-keys Tab || exit 1
|
||||||
|
settle
|
||||||
|
status_line | grep -qF 'new-window' && fail "search prompt completed a command"
|
||||||
|
$OUT send-keys Escape || exit 1
|
||||||
|
settle
|
||||||
|
|
||||||
|
# ===========================================================================
|
||||||
|
# 4. Robustness: re-entrancy guard and Escape, then liveness.
|
||||||
|
# ===========================================================================
|
||||||
|
|
||||||
|
# --- 4a. A second prompt while one is open is refused (status path). ---
|
||||||
|
client=$($IN list-clients -F '#{client_name}' | head -1)
|
||||||
|
reset
|
||||||
|
$OUT send-keys M-s || exit 1
|
||||||
|
settle
|
||||||
|
$OUT send-keys -l "AAA" || exit 1
|
||||||
|
settle
|
||||||
|
$IN command-prompt -t"$client" -p '(re)' "set -g @r 'REENTERED'" 2>/dev/null
|
||||||
|
settle
|
||||||
|
capture | grep -qF '(re)' && fail "a second status prompt opened over the first"
|
||||||
|
status_line | grep -qF '(stat) AAA' || fail "first status prompt was disturbed"
|
||||||
|
$OUT send-keys Escape || exit 1
|
||||||
|
settle
|
||||||
|
[ "$(got)" = "SENTINEL" ] || fail "Escape ran the status prompt accept action"
|
||||||
|
|
||||||
|
# --- 4b. A second pane prompt while one is open is refused (pane path). ---
|
||||||
|
reset
|
||||||
|
$OUT send-keys M-p || exit 1
|
||||||
|
settle
|
||||||
|
$OUT send-keys -l "BBB" || exit 1
|
||||||
|
settle
|
||||||
|
$IN command-prompt -P -t"$client" -p '(re)' "set -g @r 'REENTERED'" 2>/dev/null
|
||||||
|
settle
|
||||||
|
capture | grep -qF '(re)' && fail "a second pane prompt opened over the first"
|
||||||
|
capture | grep -qF '(pane) BBB' || fail "first pane prompt was disturbed"
|
||||||
|
$OUT send-keys Escape || exit 1
|
||||||
|
settle
|
||||||
|
[ "$(got)" = "SENTINEL" ] || fail "Escape ran the pane prompt accept action"
|
||||||
|
|
||||||
|
# --- 4c. Inner tmux survived every path and flag. ---
|
||||||
|
$IN display-message -p '#{version}' >/dev/null 2>&1 || fail "inner tmux died"
|
||||||
|
|
||||||
|
exit 0
|
||||||
79
regress/screen-redraw-bidi.sh
Normal file
79
regress/screen-redraw-bidi.sh
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Exercise screen-redraw.c bidirectional-isolate handling. When the client is
|
||||||
|
# UTF-8 and its terminal has the Bidi capability, each drawn span is wrapped in
|
||||||
|
# directional isolate characters (U+2066 .. U+2069) so a bidi terminal does not
|
||||||
|
# reorder pane contents across borders (the REDRAW_ISOLATES path).
|
||||||
|
#
|
||||||
|
# The Bidi capability is added with terminal-overrides before the client
|
||||||
|
# attaches, so the attached client picks it up. The isolate characters appear in
|
||||||
|
# the captured output around each span.
|
||||||
|
#
|
||||||
|
# Run with GENERATE=1 to (re)create the golden files.
|
||||||
|
|
||||||
|
PATH=/bin:/usr/bin
|
||||||
|
TERM=screen
|
||||||
|
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"
|
||||||
|
RESULTS=screen-redraw-results
|
||||||
|
|
||||||
|
TMP=$(mktemp)
|
||||||
|
trap "rm -f $TMP; $TMUX kill-server 2>/dev/null; $TMUX2 kill-server 2>/dev/null" \
|
||||||
|
0 1 15
|
||||||
|
|
||||||
|
fail() {
|
||||||
|
echo "$*" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
compare() {
|
||||||
|
sleep 1
|
||||||
|
$TMUX capturep -p >$TMP || exit 1
|
||||||
|
if [ -n "$GENERATE" ]; then
|
||||||
|
cp $TMP "$RESULTS/$1.result" || exit 1
|
||||||
|
echo "generated $1"
|
||||||
|
else
|
||||||
|
cmp -s $TMP "$RESULTS/$1.result" || \
|
||||||
|
fail "scene $1 differs from $RESULTS/$1.result"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
new_scene() {
|
||||||
|
$TMUX2 neww -d "sh -c 'printf \"BIDI-LEFT 12345\nBIDI-RIGHT 67890\"; exec sleep 100'" || exit 1
|
||||||
|
$TMUX2 selectw -t:\$ || exit 1
|
||||||
|
$TMUX2 resizew -x40 -y12 || exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
C="sh -c 'printf \"BIDI-PANE 12345\nBIDI-PANE 67890\"; exec sleep 100'"
|
||||||
|
|
||||||
|
$TMUX kill-server 2>/dev/null
|
||||||
|
$TMUX2 kill-server 2>/dev/null
|
||||||
|
|
||||||
|
$TMUX2 new -d -x40 -y12 "sh -c 'printf \"BIDI-BASE 12345\nBIDI-BASE 67890\"; exec sleep 100'" || exit 1
|
||||||
|
$TMUX2 set -g status off || exit 1
|
||||||
|
$TMUX2 set -g window-size manual || exit 1
|
||||||
|
# Add the Bidi capability before the client attaches.
|
||||||
|
$TMUX2 set -ag terminal-overrides ",*:Bidi=\\E[8h" || exit 1
|
||||||
|
|
||||||
|
$TMUX new -d -x40 -y12 || exit 1
|
||||||
|
$TMUX set -g status off || exit 1
|
||||||
|
$TMUX set -g window-size manual || exit 1
|
||||||
|
$TMUX set -g default-terminal "tmux-256color" || exit 1
|
||||||
|
$TMUX send -l "$TMUX2 attach" || exit 1
|
||||||
|
$TMUX send Enter || exit 1
|
||||||
|
sleep 1
|
||||||
|
|
||||||
|
# Single pane: content is wrapped in isolates.
|
||||||
|
new_scene
|
||||||
|
compare bidi-single
|
||||||
|
|
||||||
|
# Two panes: borders and both panes are isolated.
|
||||||
|
new_scene
|
||||||
|
$TMUX2 splitw -h "$C" || exit 1
|
||||||
|
compare bidi-split
|
||||||
|
|
||||||
|
exit 0
|
||||||
162
regress/screen-redraw-cache.sh
Normal file
162
regress/screen-redraw-cache.sh
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Exercise the scene caching in screen-redraw.c. A scene is built once and reused
|
||||||
|
# until it is invalidated; redraw_get_scene rebuilds it when the window changes,
|
||||||
|
# the generation number is bumped (panes moved/resized/swapped), or the offset
|
||||||
|
# changes. These tests make such a change in place and capture afterwards: if the
|
||||||
|
# matching invalidation did not fire, the stale cached scene would be drawn and
|
||||||
|
# the capture would not match the golden.
|
||||||
|
#
|
||||||
|
# Each scene is rendered in an inner tmux attached inside an outer tmux pane. The
|
||||||
|
# outer pane is captured and compared with a golden in screen-redraw-results/.
|
||||||
|
#
|
||||||
|
# Run with GENERATE=1 to (re)create the golden files.
|
||||||
|
|
||||||
|
PATH=/bin:/usr/bin
|
||||||
|
TERM=screen
|
||||||
|
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"
|
||||||
|
RESULTS=screen-redraw-results
|
||||||
|
|
||||||
|
TMP=$(mktemp)
|
||||||
|
trap "rm -f $TMP; $TMUX kill-server 2>/dev/null; $TMUX2 kill-server 2>/dev/null" \
|
||||||
|
0 1 15
|
||||||
|
|
||||||
|
fail() {
|
||||||
|
echo "$*" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
compare() {
|
||||||
|
sleep 1
|
||||||
|
$TMUX capturep -p >$TMP || exit 1
|
||||||
|
if [ -n "$GENERATE" ]; then
|
||||||
|
cp $TMP "$RESULTS/$1.result" || exit 1
|
||||||
|
echo "generated $1"
|
||||||
|
else
|
||||||
|
cmp -s $TMP "$RESULTS/$1.result" || \
|
||||||
|
fail "scene $1 differs from $RESULTS/$1.result"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
new_scene() {
|
||||||
|
$TMUX2 neww -d "sh -c 'i=0; while [ \$i -lt 13 ]; do printf \"BASE%02d abcdefghij\n\" \$i; i=\$((i + 1)); done; exec sleep 100'" || exit 1
|
||||||
|
$TMUX2 selectw -t:\$ || exit 1
|
||||||
|
$TMUX2 resizew -x40 -y14 || exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
C="sh -c 'i=0; while [ \$i -lt 5 ]; do printf \"PANE%02d abcdefghij\n\" \$i; i=\$((i + 1)); done; exec sleep 100'"
|
||||||
|
|
||||||
|
$TMUX kill-server 2>/dev/null
|
||||||
|
$TMUX2 kill-server 2>/dev/null
|
||||||
|
|
||||||
|
$TMUX2 new -d -x40 -y14 "sh -c 'exec sleep 100'" || exit 1
|
||||||
|
$TMUX2 set -g status off || exit 1
|
||||||
|
$TMUX2 set -g window-size manual || exit 1
|
||||||
|
|
||||||
|
$TMUX new -d -x40 -y14 || exit 1
|
||||||
|
$TMUX set -g status off || exit 1
|
||||||
|
$TMUX set -g window-size manual || exit 1
|
||||||
|
$TMUX set -g default-terminal "tmux-256color" || exit 1
|
||||||
|
$TMUX send -l "$TMUX2 attach" || exit 1
|
||||||
|
$TMUX send Enter || exit 1
|
||||||
|
sleep 1
|
||||||
|
|
||||||
|
# --- Generation change: a pane is resized in place. ---
|
||||||
|
|
||||||
|
# Two columns; first capture pins the initial divider position. The scene is
|
||||||
|
# built here and cached.
|
||||||
|
new_scene
|
||||||
|
$TMUX2 splitw -h "$C" || exit 1
|
||||||
|
$TMUX2 selectp -t0 || exit 1
|
||||||
|
compare cache-resize-before
|
||||||
|
|
||||||
|
# Move the divider left. resize-pane bumps the generation, so the cached scene
|
||||||
|
# must be rebuilt and the divider must appear in its new position.
|
||||||
|
$TMUX2 resize-pane -t0 -L 6 || exit 1
|
||||||
|
compare cache-resize-after
|
||||||
|
|
||||||
|
# --- Generation change: panes are swapped/rotated in place. ---
|
||||||
|
|
||||||
|
# Three columns, each pane titled so the order is visible. The pane status line
|
||||||
|
# makes a swap show up in the captured scene.
|
||||||
|
new_scene
|
||||||
|
$TMUX2 setw pane-border-format " #{pane_title} " || exit 1
|
||||||
|
$TMUX2 setw pane-border-status top || exit 1
|
||||||
|
$TMUX2 splitw -h "$C" || exit 1
|
||||||
|
$TMUX2 selectp -t0 || exit 1
|
||||||
|
$TMUX2 splitw -h "$C" || exit 1
|
||||||
|
$TMUX2 selectp -t:.0 -T AAA || exit 1
|
||||||
|
$TMUX2 selectp -t:.1 -T BBB || exit 1
|
||||||
|
$TMUX2 selectp -t:.2 -T CCC || exit 1
|
||||||
|
$TMUX2 selectp -t:.0 || exit 1
|
||||||
|
compare cache-rotate-before
|
||||||
|
|
||||||
|
# Rotate the panes; the titles must move with them in the rebuilt scene.
|
||||||
|
# rotate-window keeps the cell geometry, so only its scene invalidation makes
|
||||||
|
# this differ from cache-rotate-before.
|
||||||
|
$TMUX2 rotate-window || exit 1
|
||||||
|
$TMUX2 selectp -t:.0 || exit 1
|
||||||
|
compare cache-rotate-after
|
||||||
|
|
||||||
|
# --- Generation change: two panes swapped in place. ---
|
||||||
|
|
||||||
|
# swap-pane likewise moves panes between cells without changing geometry; the
|
||||||
|
# swapped titles must appear in the rebuilt scene.
|
||||||
|
new_scene
|
||||||
|
$TMUX2 setw pane-border-format " #{pane_title} " || exit 1
|
||||||
|
$TMUX2 setw pane-border-status top || exit 1
|
||||||
|
$TMUX2 splitw -h "$C" || exit 1
|
||||||
|
$TMUX2 selectp -t:.0 -T LEFT || exit 1
|
||||||
|
$TMUX2 selectp -t:.1 -T RIGHT || exit 1
|
||||||
|
$TMUX2 selectp -t:.0 || exit 1
|
||||||
|
compare cache-swap-before
|
||||||
|
|
||||||
|
$TMUX2 swap-pane -d -s:.0 -t:.1 || exit 1
|
||||||
|
$TMUX2 selectp -t:.0 || exit 1
|
||||||
|
compare cache-swap-after
|
||||||
|
|
||||||
|
# --- Window change: the client switches between two differently laid out
|
||||||
|
# windows and back. The scene is keyed on the window, so each must show its own
|
||||||
|
# layout and switching back must not show the other window's cached scene. ---
|
||||||
|
|
||||||
|
# Window A: a single pane (no internal border).
|
||||||
|
$TMUX2 neww -d "sh -c 'i=0; while [ \$i -lt 13 ]; do printf \"WINA%02d abcdefghij\n\" \$i; i=\$((i + 1)); done; exec sleep 100'" || exit 1
|
||||||
|
$TMUX2 selectw -t:\$ || exit 1
|
||||||
|
$TMUX2 resizew -x40 -y14 || exit 1
|
||||||
|
A=$($TMUX2 display -p '#{window_id}') || exit 1
|
||||||
|
|
||||||
|
# Window B: a top/bottom split (a horizontal border).
|
||||||
|
$TMUX2 neww -d "sh -c 'i=0; while [ \$i -lt 13 ]; do printf \"WINB%02d abcdefghij\n\" \$i; i=\$((i + 1)); done; exec sleep 100'" || exit 1
|
||||||
|
$TMUX2 selectw -t:\$ || exit 1
|
||||||
|
$TMUX2 resizew -x40 -y14 || exit 1
|
||||||
|
$TMUX2 splitw -v "$C" || exit 1
|
||||||
|
B=$($TMUX2 display -p '#{window_id}') || exit 1
|
||||||
|
|
||||||
|
$TMUX2 selectw -t$A || exit 1
|
||||||
|
compare cache-window-a
|
||||||
|
$TMUX2 selectw -t$B || exit 1
|
||||||
|
compare cache-window-b
|
||||||
|
$TMUX2 selectw -t$A || exit 1
|
||||||
|
compare cache-window-a-again
|
||||||
|
|
||||||
|
# --- Size change: the client (and so the scene) is resized. ---
|
||||||
|
|
||||||
|
# With window-size latest the inner window tracks the client size, so resizing
|
||||||
|
# the outer window resizes the inner client and the scene. The cached scene must
|
||||||
|
# be rebuilt at the new size (the scene->sx/sy mismatch path in
|
||||||
|
# redraw_get_scene), not drawn at the old size.
|
||||||
|
$TMUX2 set -g window-size latest || exit 1
|
||||||
|
$TMUX2 neww -d "sh -c 'i=0; while [ \$i -lt 13 ]; do printf \"SIZE%02d abcdefghij\n\" \$i; i=\$((i + 1)); done; exec sleep 100'" || exit 1
|
||||||
|
$TMUX2 selectw -t:\$ || exit 1
|
||||||
|
$TMUX2 splitw -v "$C" || exit 1
|
||||||
|
compare cache-resizeclient-before
|
||||||
|
|
||||||
|
$TMUX resizew -x30 -y10 || exit 1
|
||||||
|
compare cache-resizeclient-after
|
||||||
|
|
||||||
|
exit 0
|
||||||
221
regress/screen-redraw-floating.sh
Normal file
221
regress/screen-redraw-floating.sh
Normal file
@@ -0,0 +1,221 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Exercise screen-redraw.c drawing of floating panes: their borders and titles,
|
||||||
|
# clipping at the window edge, and the interaction with the area outside the
|
||||||
|
# window (when the window is smaller than the attached client).
|
||||||
|
#
|
||||||
|
# Each scene is rendered in an inner tmux attached inside an outer tmux pane.
|
||||||
|
# The outer pane is captured (the full client scene drawn by screen-redraw.c)
|
||||||
|
# and compared with a golden file in screen_redraw_results/.
|
||||||
|
#
|
||||||
|
# Run with GENERATE=1 to (re)create the golden files.
|
||||||
|
|
||||||
|
PATH=/bin:/usr/bin
|
||||||
|
TERM=screen
|
||||||
|
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"
|
||||||
|
RESULTS=screen-redraw-results
|
||||||
|
|
||||||
|
TMP=$(mktemp)
|
||||||
|
trap "rm -f $TMP; $TMUX kill-server 2>/dev/null; $TMUX2 kill-server 2>/dev/null" \
|
||||||
|
0 1 15
|
||||||
|
|
||||||
|
fail() {
|
||||||
|
echo "$*" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
compare() {
|
||||||
|
sleep 1
|
||||||
|
$TMUX capturep -p $2 >$TMP || exit 1
|
||||||
|
if [ -n "$GENERATE" ]; then
|
||||||
|
cp $TMP "$RESULTS/$1.result" || exit 1
|
||||||
|
echo "generated $1"
|
||||||
|
else
|
||||||
|
cmp -s $TMP "$RESULTS/$1.result" || \
|
||||||
|
fail "scene $1 differs from $RESULTS/$1.result"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# new_scene <width> <height>: fresh inner window of the given window size.
|
||||||
|
new_scene() {
|
||||||
|
$TMUX2 neww -d "sh -c 'printf base; exec sleep 100'" || exit 1
|
||||||
|
$TMUX2 selectw -t:\$ || exit 1
|
||||||
|
$TMUX2 resizew -x$1 -y$2 || exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# tile_2x2: split the current window into a 2x2 grid of tiled panes.
|
||||||
|
tile_2x2() {
|
||||||
|
C="sh -c 'exec sleep 100'"
|
||||||
|
$TMUX2 splitw -h "$C" || exit 1
|
||||||
|
$TMUX2 splitw -v "$C" || exit 1
|
||||||
|
$TMUX2 selectp -t0 || exit 1
|
||||||
|
$TMUX2 splitw -v "$C" || exit 1
|
||||||
|
$TMUX2 select-layout tiled || exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# fill_base_pattern: make clipped floating panes visibly cover every column.
|
||||||
|
fill_base_pattern() {
|
||||||
|
$TMUX2 respawnp -k "sh -c 'i=0; while [ \$i -lt 12 ]; do printf \"%02d:abcdefghijklmnopqrstuvwxyz0123456789\n\" \$i; i=\$((i + 1)); done; exec sleep 100'" || exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# fill_all_panes: make each pane visibly nonblank.
|
||||||
|
fill_all_panes() {
|
||||||
|
for pane in $($TMUX2 list-panes -F '#{pane_id}'); do
|
||||||
|
$TMUX2 respawnp -k -t "$pane" "sh -c 'i=0; while [ \$i -lt 5 ]; do printf \"TILE%02d abcdefghij\n\" \$i; i=\$((i + 1)); done; exec sleep 100'" || exit 1
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
$TMUX kill-server 2>/dev/null
|
||||||
|
$TMUX2 kill-server 2>/dev/null
|
||||||
|
|
||||||
|
$TMUX2 new -d -x40 -y12 "sh -c 'printf base; exec sleep 100'" || exit 1
|
||||||
|
$TMUX2 set -g status off || exit 1
|
||||||
|
$TMUX2 set -g window-size manual || exit 1
|
||||||
|
$TMUX2 set -g pane-border-format " #{pane_title} " || exit 1
|
||||||
|
|
||||||
|
$TMUX new -d -x40 -y12 || exit 1
|
||||||
|
$TMUX set -g status off || exit 1
|
||||||
|
$TMUX set -g window-size manual || exit 1
|
||||||
|
$TMUX set -g default-terminal "tmux-256color" || exit 1
|
||||||
|
$TMUX send -l "$TMUX2 attach" || exit 1
|
||||||
|
$TMUX send Enter || exit 1
|
||||||
|
sleep 1
|
||||||
|
|
||||||
|
# Basic floating pane, well inside the window.
|
||||||
|
new_scene 40 12
|
||||||
|
$TMUX2 new-pane -x20 -y6 -X8 -Y3 "sh -c 'printf FLOAT; exec sleep 100'" || exit 1
|
||||||
|
compare floating-basic
|
||||||
|
|
||||||
|
# Floating pane with a title on its border. pane-border-status also draws the
|
||||||
|
# base pane's title, so set it explicitly (the default is the hostname, which is
|
||||||
|
# not stable).
|
||||||
|
new_scene 40 12
|
||||||
|
$TMUX2 setw pane-border-status top || exit 1
|
||||||
|
$TMUX2 selectp -t:.0 -T base || exit 1
|
||||||
|
$TMUX2 new-pane -x20 -y6 -X8 -Y2 -T title \
|
||||||
|
"sh -c 'printf FLOAT; exec sleep 100'" || exit 1
|
||||||
|
compare floating-title
|
||||||
|
|
||||||
|
# Larger floating pane with double border lines.
|
||||||
|
new_scene 40 12
|
||||||
|
$TMUX2 new-pane -x28 -y8 -X4 -Y1 -B double \
|
||||||
|
"sh -c 'printf FLOAT; exec sleep 100'" || exit 1
|
||||||
|
compare floating-border-double
|
||||||
|
|
||||||
|
# Floating pane with no border lines: redraw_mark_pane_borders returns early so
|
||||||
|
# the float has no border at all, only its (clipped) content over the base pane.
|
||||||
|
new_scene 40 12
|
||||||
|
$TMUX2 new-pane -x20 -y6 -X10 -Y3 -B none \
|
||||||
|
"sh -c 'printf NOBORDER; exec sleep 100'" || exit 1
|
||||||
|
compare floating-noborder
|
||||||
|
|
||||||
|
# Floating pane positioned past the right and bottom edges: must clip.
|
||||||
|
new_scene 40 12
|
||||||
|
$TMUX2 new-pane -x20 -y6 -X30 -Y8 "sh -c 'printf CLIP; exec sleep 100'" || exit 1
|
||||||
|
compare floating-clip-edge
|
||||||
|
|
||||||
|
# Window smaller than the client (outside area filled), with a floating pane
|
||||||
|
# that overlaps the boundary into the outside region.
|
||||||
|
new_scene 28 8
|
||||||
|
$TMUX2 new-pane -x16 -y5 -X18 -Y4 "sh -c 'printf OUT; exec sleep 100'" || exit 1
|
||||||
|
compare floating-outside
|
||||||
|
|
||||||
|
# Floating pane clipped at the top-left corner (negative offsets).
|
||||||
|
new_scene 40 12
|
||||||
|
$TMUX2 new-pane -x18 -y6 -X-4 -Y-2 "sh -c 'printf TL; exec sleep 100'" || exit 1
|
||||||
|
compare floating-clip-topleft
|
||||||
|
|
||||||
|
# Floating panes clipped at each edge. The patterned base pane makes sure the
|
||||||
|
# clipped edge still obscures both content and borders underneath.
|
||||||
|
new_scene 40 12
|
||||||
|
fill_base_pattern
|
||||||
|
$TMUX2 new-pane -x20 -y6 -X-10 -Y3 "sh -c 'printf LEFT; exec sleep 100'" || exit 1
|
||||||
|
compare floating-clip-left
|
||||||
|
|
||||||
|
new_scene 40 12
|
||||||
|
fill_base_pattern
|
||||||
|
$TMUX2 new-pane -x20 -y6 -X30 -Y3 "sh -c 'printf RIGHT; exec sleep 100'" || exit 1
|
||||||
|
compare floating-clip-right
|
||||||
|
|
||||||
|
new_scene 40 12
|
||||||
|
fill_base_pattern
|
||||||
|
$TMUX2 new-pane -x20 -y6 -X10 -Y-3 "sh -c 'printf TOP; exec sleep 100'" || exit 1
|
||||||
|
compare floating-clip-top
|
||||||
|
|
||||||
|
new_scene 40 12
|
||||||
|
fill_base_pattern
|
||||||
|
$TMUX2 new-pane -x20 -y6 -X10 -Y9 "sh -c 'printf BOTTOM; exec sleep 100'" || exit 1
|
||||||
|
compare floating-clip-bottom
|
||||||
|
|
||||||
|
# Floating pane over a tiled 2x2 grid: the float draws a complete box and must
|
||||||
|
# NOT merge its borders with the tiled pane borders underneath.
|
||||||
|
new_scene 40 12
|
||||||
|
tile_2x2
|
||||||
|
fill_all_panes
|
||||||
|
$TMUX2 new-pane -x16 -y6 -X11 -Y3 "sh -c 'printf FLT; exec sleep 100'" || exit 1
|
||||||
|
compare floating-over-tiled
|
||||||
|
|
||||||
|
# Same, but the float uses double border lines while the tiled panes use single:
|
||||||
|
# the two border styles must coexist without merging.
|
||||||
|
new_scene 40 12
|
||||||
|
tile_2x2
|
||||||
|
fill_all_panes
|
||||||
|
$TMUX2 new-pane -x16 -y6 -X11 -Y3 -B double \
|
||||||
|
"sh -c 'printf FLT; exec sleep 100'" || exit 1
|
||||||
|
compare floating-over-tiled-double
|
||||||
|
|
||||||
|
# Two overlapping floating panes: the later (top) float draws over the earlier.
|
||||||
|
new_scene 40 12
|
||||||
|
$TMUX2 new-pane -x16 -y6 -X4 -Y2 "sh -c 'printf AAA; exec sleep 100'" || exit 1
|
||||||
|
$TMUX2 new-pane -x16 -y6 -X14 -Y6 "sh -c 'printf BBB; exec sleep 100'" || exit 1
|
||||||
|
compare floating-overlap
|
||||||
|
|
||||||
|
# Two floating panes with different per-pane configuration: one has its status on
|
||||||
|
# top with single borders, the other has its status on the bottom with heavy
|
||||||
|
# borders (pane-border-status and pane-border-lines are per-pane options).
|
||||||
|
new_scene 40 12
|
||||||
|
$TMUX2 setw pane-border-format " #{pane_title} " || exit 1
|
||||||
|
$TMUX2 new-pane -x16 -y4 -X3 -Y1 -T one \
|
||||||
|
"sh -c 'printf ONE; exec sleep 100'" || exit 1
|
||||||
|
$TMUX2 set -p pane-border-status top || exit 1
|
||||||
|
$TMUX2 set -p pane-border-lines single || exit 1
|
||||||
|
$TMUX2 new-pane -x16 -y4 -X18 -Y6 -T two \
|
||||||
|
"sh -c 'printf TWO; exec sleep 100'" || exit 1
|
||||||
|
$TMUX2 set -p pane-border-status bottom || exit 1
|
||||||
|
$TMUX2 set -p pane-border-lines heavy || exit 1
|
||||||
|
compare floating-mixed-config
|
||||||
|
|
||||||
|
# Floating pane over a pane that has a scrollbar: the float must draw over the
|
||||||
|
# scrollbar. Captured with -e since the scrollbar is drawn with styles.
|
||||||
|
new_scene 40 12
|
||||||
|
$TMUX2 setw pane-scrollbars on || exit 1
|
||||||
|
$TMUX2 setw pane-scrollbars-style "bg=black,fg=white,width=1,pad=0" || exit 1
|
||||||
|
$TMUX2 new-pane -x16 -y6 -X22 -Y3 "sh -c 'printf OVERSB; exec sleep 100'" || exit 1
|
||||||
|
compare floating-over-scrollbar -e
|
||||||
|
|
||||||
|
# Floating pane overlapping the client status line: the status line is not part
|
||||||
|
# of the window scene, so the float is clipped at the window's bottom edge.
|
||||||
|
new_scene 40 11
|
||||||
|
$TMUX2 set status on || exit 1
|
||||||
|
$TMUX2 set status-position bottom || exit 1
|
||||||
|
$TMUX2 set status-format[0] "" || exit 1
|
||||||
|
$TMUX2 new-pane -x20 -y6 -X8 -Y7 "sh -c 'printf OVERST; exec sleep 100'" || exit 1
|
||||||
|
compare floating-over-status
|
||||||
|
|
||||||
|
# A window left with only a floating pane: killing the single tiled pane removes
|
||||||
|
# it from the layout, so the area it occupied is no longer owned by any pane and
|
||||||
|
# is drawn as EMPTY cells (middle dots) around the float. This is the only way to
|
||||||
|
# produce a REDRAW_SPAN_EMPTY span.
|
||||||
|
new_scene 40 12
|
||||||
|
$TMUX2 new-pane -x20 -y6 -X8 -Y3 "sh -c 'printf FLOAT; exec sleep 100'" || exit 1
|
||||||
|
tiled=$($TMUX2 list-panes -F '#{pane_floating_flag} #{pane_id}' | \
|
||||||
|
awk '$1==0{print $2; exit}') || exit 1
|
||||||
|
$TMUX2 kill-pane -t "$tiled" || exit 1
|
||||||
|
compare floating-empty
|
||||||
|
|
||||||
|
exit 0
|
||||||
212
regress/screen-redraw-indicators.sh
Normal file
212
regress/screen-redraw-indicators.sh
Normal file
@@ -0,0 +1,212 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Exercise screen-redraw.c pane-border-indicators: the arrow indicators that
|
||||||
|
# point at the active pane, and the two-pane border colour split.
|
||||||
|
#
|
||||||
|
# Arrows are drawn as glyphs (captured plain). The two-pane colour split is
|
||||||
|
# drawn with styles, so that scene is captured with escapes (-e) and uses
|
||||||
|
# distinct active/inactive border styles so the split is visible.
|
||||||
|
#
|
||||||
|
# Each scene is rendered in an inner tmux attached inside an outer tmux pane.
|
||||||
|
# The outer pane is captured and compared with a golden in screen-redraw-results/.
|
||||||
|
#
|
||||||
|
# Run with GENERATE=1 to (re)create the golden files.
|
||||||
|
|
||||||
|
PATH=/bin:/usr/bin
|
||||||
|
TERM=screen
|
||||||
|
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"
|
||||||
|
RESULTS=screen-redraw-results
|
||||||
|
|
||||||
|
TMP=$(mktemp)
|
||||||
|
trap "rm -f $TMP; $TMUX kill-server 2>/dev/null; $TMUX2 kill-server 2>/dev/null" \
|
||||||
|
0 1 15
|
||||||
|
|
||||||
|
fail() {
|
||||||
|
echo "$*" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# compare <name> [-e]: capture the outer pane and compare (or generate).
|
||||||
|
compare() {
|
||||||
|
sleep 1
|
||||||
|
$TMUX capturep -p $2 >$TMP || exit 1
|
||||||
|
if [ -n "$GENERATE" ]; then
|
||||||
|
cp $TMP "$RESULTS/$1.result" || exit 1
|
||||||
|
echo "generated $1"
|
||||||
|
else
|
||||||
|
cmp -s $TMP "$RESULTS/$1.result" || \
|
||||||
|
fail "scene $1 differs from $RESULTS/$1.result"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
new_scene() {
|
||||||
|
$TMUX2 neww -d "sh -c 'exec sleep 100'" || exit 1
|
||||||
|
$TMUX2 selectw -t:\$ || exit 1
|
||||||
|
$TMUX2 resizew -x40 -y12 || exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
C="sh -c 'exec sleep 100'"
|
||||||
|
|
||||||
|
$TMUX kill-server 2>/dev/null
|
||||||
|
$TMUX2 kill-server 2>/dev/null
|
||||||
|
|
||||||
|
$TMUX2 new -d -x40 -y12 "sh -c 'exec sleep 100'" || exit 1
|
||||||
|
$TMUX2 set -g status off || exit 1
|
||||||
|
$TMUX2 set -g window-size manual || exit 1
|
||||||
|
|
||||||
|
$TMUX new -d -x40 -y12 || exit 1
|
||||||
|
$TMUX set -g status off || exit 1
|
||||||
|
$TMUX set -g window-size manual || exit 1
|
||||||
|
$TMUX set -g default-terminal "tmux-256color" || exit 1
|
||||||
|
$TMUX send -l "$TMUX2 attach" || exit 1
|
||||||
|
$TMUX send Enter || exit 1
|
||||||
|
sleep 1
|
||||||
|
|
||||||
|
# --- Arrows: must appear for whichever pane is active (GitHub #4780). ---
|
||||||
|
|
||||||
|
$TMUX2 set -g pane-border-indicators arrows || exit 1
|
||||||
|
|
||||||
|
# Two panes, left active: arrow points left.
|
||||||
|
new_scene
|
||||||
|
$TMUX2 splitw -h "$C" || exit 1
|
||||||
|
$TMUX2 selectp -t0 || exit 1
|
||||||
|
compare arrows-2pane-left
|
||||||
|
|
||||||
|
# Two panes, right active: arrow points right (the case that regressed).
|
||||||
|
new_scene
|
||||||
|
$TMUX2 splitw -h "$C" || exit 1
|
||||||
|
$TMUX2 selectp -t1 || exit 1
|
||||||
|
compare arrows-2pane-right
|
||||||
|
|
||||||
|
# Three columns, middle active.
|
||||||
|
new_scene
|
||||||
|
$TMUX2 splitw -h "$C" || exit 1
|
||||||
|
$TMUX2 selectp -t0 || exit 1
|
||||||
|
$TMUX2 splitw -h "$C" || exit 1
|
||||||
|
$TMUX2 selectp -t1 || exit 1
|
||||||
|
compare arrows-3pane
|
||||||
|
|
||||||
|
# Four panes (2x2), one active.
|
||||||
|
new_scene
|
||||||
|
$TMUX2 splitw -h "$C" || exit 1
|
||||||
|
$TMUX2 splitw -v "$C" || exit 1
|
||||||
|
$TMUX2 selectp -t0 || exit 1
|
||||||
|
$TMUX2 splitw -v "$C" || exit 1
|
||||||
|
$TMUX2 select-layout tiled || exit 1
|
||||||
|
$TMUX2 selectp -t0 || exit 1
|
||||||
|
compare arrows-4pane
|
||||||
|
|
||||||
|
# --- Two-pane border colour split. ---
|
||||||
|
|
||||||
|
# Distinct active/inactive styles so the coloured halves are visible; captured
|
||||||
|
# with -e to record the SGR.
|
||||||
|
$TMUX2 set -g pane-border-indicators colour || exit 1
|
||||||
|
|
||||||
|
# Left/right split: the border is vertical and is split into a top half (active
|
||||||
|
# pane colour) and a bottom half (the LAYOUT_LEFTRIGHT case).
|
||||||
|
new_scene
|
||||||
|
$TMUX2 setw pane-active-border-style fg=red || exit 1
|
||||||
|
$TMUX2 setw pane-border-style fg=green || exit 1
|
||||||
|
$TMUX2 splitw -h "$C" || exit 1
|
||||||
|
$TMUX2 selectp -t0 || exit 1
|
||||||
|
compare two-pane-colour-vertical -e
|
||||||
|
|
||||||
|
# Top/bottom split: the border is horizontal and is split into a left half and a
|
||||||
|
# right half instead (the LAYOUT_TOPBOTTOM case).
|
||||||
|
new_scene
|
||||||
|
$TMUX2 setw pane-active-border-style fg=red || exit 1
|
||||||
|
$TMUX2 setw pane-border-style fg=green || exit 1
|
||||||
|
$TMUX2 splitw -v "$C" || exit 1
|
||||||
|
$TMUX2 selectp -t0 || exit 1
|
||||||
|
compare two-pane-colour-horizontal -e
|
||||||
|
|
||||||
|
# The colour split only applies with exactly two tiled panes. With three panes
|
||||||
|
# the split is suppressed: the whole border uses the active pane's colour and
|
||||||
|
# there is no coloured half (redraw_check_two_pane_colours returns 0).
|
||||||
|
new_scene
|
||||||
|
$TMUX2 setw pane-active-border-style fg=red || exit 1
|
||||||
|
$TMUX2 setw pane-border-style fg=green || exit 1
|
||||||
|
$TMUX2 splitw -h "$C" || exit 1
|
||||||
|
$TMUX2 selectp -t0 || exit 1
|
||||||
|
$TMUX2 splitw -h "$C" || exit 1
|
||||||
|
$TMUX2 selectp -t0 || exit 1
|
||||||
|
compare colour-three-suppressed -e
|
||||||
|
|
||||||
|
# A floating pane is ignored by the two-pane count, so two tiled panes plus a
|
||||||
|
# float still split. The float itself is never coloured by the indicator.
|
||||||
|
new_scene
|
||||||
|
$TMUX2 setw pane-active-border-style fg=red || exit 1
|
||||||
|
$TMUX2 setw pane-border-style fg=green || exit 1
|
||||||
|
$TMUX2 splitw -h "$C" || exit 1
|
||||||
|
$TMUX2 selectp -t0 || exit 1
|
||||||
|
$TMUX2 new-pane -x16 -y6 -X10 -Y2 "$C" || exit 1
|
||||||
|
$TMUX2 selectp -t0 || exit 1
|
||||||
|
compare colour-two-plus-float -e
|
||||||
|
|
||||||
|
# --- Both indicators together. ---
|
||||||
|
|
||||||
|
# pane-border-indicators both enables the arrow and the colour split at once
|
||||||
|
# (it satisfies both the arrow and the colour branches). Two panes so the colour
|
||||||
|
# split also applies.
|
||||||
|
$TMUX2 set -g pane-border-indicators both || exit 1
|
||||||
|
new_scene
|
||||||
|
$TMUX2 setw pane-active-border-style fg=red || exit 1
|
||||||
|
$TMUX2 setw pane-border-style fg=green || exit 1
|
||||||
|
$TMUX2 splitw -h "$C" || exit 1
|
||||||
|
$TMUX2 selectp -t0 || exit 1
|
||||||
|
compare indicators-both -e
|
||||||
|
|
||||||
|
# --- Marked pane. ---
|
||||||
|
|
||||||
|
# A marked pane (select-pane -m) has its border drawn reversed. Captured with -e
|
||||||
|
# to record the reverse attribute. The marked pane is made non-active so its
|
||||||
|
# reversed border is distinct from the active pane.
|
||||||
|
$TMUX2 set -g pane-border-indicators off || exit 1
|
||||||
|
|
||||||
|
# Left/right split, right pane marked.
|
||||||
|
new_scene
|
||||||
|
$TMUX2 splitw -h "$C" || exit 1
|
||||||
|
$TMUX2 selectp -t0 || exit 1
|
||||||
|
$TMUX2 selectp -t1 -m || exit 1
|
||||||
|
compare marked-pane-lr -e
|
||||||
|
|
||||||
|
# Top/bottom split, bottom pane marked.
|
||||||
|
new_scene
|
||||||
|
$TMUX2 splitw -v "$C" || exit 1
|
||||||
|
$TMUX2 selectp -t0 || exit 1
|
||||||
|
$TMUX2 selectp -t1 -m || exit 1
|
||||||
|
compare marked-pane-tb -e
|
||||||
|
|
||||||
|
# Three columns, middle pane marked (reversed border on both sides).
|
||||||
|
new_scene
|
||||||
|
$TMUX2 splitw -h "$C" || exit 1
|
||||||
|
$TMUX2 selectp -t0 || exit 1
|
||||||
|
$TMUX2 splitw -h "$C" || exit 1
|
||||||
|
$TMUX2 selectp -t0 || exit 1
|
||||||
|
$TMUX2 selectp -t1 -m || exit 1
|
||||||
|
compare marked-pane-three -e
|
||||||
|
|
||||||
|
# Floating pane marked: the whole floating box border is reversed.
|
||||||
|
new_scene
|
||||||
|
$TMUX2 new-pane -x20 -y6 -X8 -Y3 "$C" || exit 1
|
||||||
|
$TMUX2 selectp -t0 || exit 1
|
||||||
|
$TMUX2 selectp -t1 -m || exit 1
|
||||||
|
compare marked-pane-float -e
|
||||||
|
|
||||||
|
# Marked pane together with a pane status line: the title border is reversed too.
|
||||||
|
new_scene
|
||||||
|
$TMUX2 splitw -h "$C" || exit 1
|
||||||
|
$TMUX2 setw pane-border-format " #{pane_index}:#{pane_title} " || exit 1
|
||||||
|
$TMUX2 setw pane-border-status top || exit 1
|
||||||
|
$TMUX2 selectp -t:.0 -T left || exit 1
|
||||||
|
$TMUX2 selectp -t:.1 -T right || exit 1
|
||||||
|
$TMUX2 selectp -t0 || exit 1
|
||||||
|
$TMUX2 selectp -t1 -m || exit 1
|
||||||
|
compare marked-pane-status -e
|
||||||
|
|
||||||
|
exit 0
|
||||||
116
regress/screen-redraw-outside.sh
Normal file
116
regress/screen-redraw-outside.sh
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Exercise screen-redraw.c when the window is smaller than the attached client,
|
||||||
|
# so part of the client is outside the window. screen-redraw.c fills the outside
|
||||||
|
# area and draws a real border along the window's right and/or bottom edge (not
|
||||||
|
# just where panes meet). This checks redraw_get_window_offset and the OUTSIDE
|
||||||
|
# span handling, including how the window-edge border joins the pane borders.
|
||||||
|
#
|
||||||
|
# Each scene is rendered in an inner tmux attached inside an outer tmux pane.
|
||||||
|
# The outer client is 40x14; the inner window is made smaller with resizew. The
|
||||||
|
# outer pane is captured and compared with a golden in screen-redraw-results/.
|
||||||
|
#
|
||||||
|
# Run with GENERATE=1 to (re)create the golden files.
|
||||||
|
|
||||||
|
PATH=/bin:/usr/bin
|
||||||
|
TERM=screen
|
||||||
|
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"
|
||||||
|
RESULTS=screen-redraw-results
|
||||||
|
|
||||||
|
TMP=$(mktemp)
|
||||||
|
trap "rm -f $TMP; $TMUX kill-server 2>/dev/null; $TMUX2 kill-server 2>/dev/null" \
|
||||||
|
0 1 15
|
||||||
|
|
||||||
|
fail() {
|
||||||
|
echo "$*" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
compare() {
|
||||||
|
sleep 1
|
||||||
|
$TMUX capturep -p >$TMP || exit 1
|
||||||
|
if [ -n "$GENERATE" ]; then
|
||||||
|
cp $TMP "$RESULTS/$1.result" || exit 1
|
||||||
|
echo "generated $1"
|
||||||
|
else
|
||||||
|
cmp -s $TMP "$RESULTS/$1.result" || \
|
||||||
|
fail "scene $1 differs from $RESULTS/$1.result"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# new_scene <width> <height>: fresh inner window smaller than the 40x14 client.
|
||||||
|
new_scene() {
|
||||||
|
$TMUX2 neww -d "sh -c 'i=0; while [ \$i -lt $(($2 - 1)) ]; do printf \"OUT%02d abcdefghij\n\" \$i; i=\$((i + 1)); done; exec sleep 100'" || exit 1
|
||||||
|
$TMUX2 selectw -t:\$ || exit 1
|
||||||
|
$TMUX2 resizew -x$1 -y$2 || exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
C="sh -c 'i=0; while [ \$i -lt 8 ]; do printf \"PAN%02d abcdefghij\n\" \$i; i=\$((i + 1)); done; exec sleep 100'"
|
||||||
|
|
||||||
|
$TMUX kill-server 2>/dev/null
|
||||||
|
$TMUX2 kill-server 2>/dev/null
|
||||||
|
|
||||||
|
$TMUX2 new -d -x40 -y14 "sh -c 'i=0; while [ \$i -lt 13 ]; do printf \"OUT%02d abcdefghij\n\" \$i; i=\$((i + 1)); done; exec sleep 100'" || exit 1
|
||||||
|
$TMUX2 set -g status off || exit 1
|
||||||
|
$TMUX2 set -g window-size manual || exit 1
|
||||||
|
|
||||||
|
$TMUX new -d -x40 -y14 || exit 1
|
||||||
|
$TMUX set -g status off || exit 1
|
||||||
|
$TMUX set -g window-size manual || exit 1
|
||||||
|
$TMUX set -g default-terminal "tmux-256color" || exit 1
|
||||||
|
$TMUX send -l "$TMUX2 attach" || exit 1
|
||||||
|
$TMUX send Enter || exit 1
|
||||||
|
sleep 1
|
||||||
|
|
||||||
|
# Single pane, narrower than the client: a border along the right edge.
|
||||||
|
new_scene 28 14
|
||||||
|
compare outside-right-single
|
||||||
|
|
||||||
|
# Narrower than the client with a left/right split: the inter-pane border plus a
|
||||||
|
# real border on the window's right edge, then the outside area.
|
||||||
|
new_scene 28 14
|
||||||
|
$TMUX2 splitw -h "$C" || exit 1
|
||||||
|
compare outside-right-split
|
||||||
|
|
||||||
|
# Shorter than the client with a top/bottom split: a real border on the window's
|
||||||
|
# bottom edge.
|
||||||
|
new_scene 40 9
|
||||||
|
$TMUX2 splitw -v "$C" || exit 1
|
||||||
|
compare outside-bottom-split
|
||||||
|
|
||||||
|
# Smaller in both dimensions with a 2x2 grid: borders on the right and bottom
|
||||||
|
# edges meeting the internal pane borders at the corner.
|
||||||
|
new_scene 28 9
|
||||||
|
$TMUX2 splitw -h "$C" || exit 1
|
||||||
|
$TMUX2 splitw -v "$C" || exit 1
|
||||||
|
$TMUX2 selectp -t0 || exit 1
|
||||||
|
$TMUX2 splitw -v "$C" || exit 1
|
||||||
|
$TMUX2 select-layout tiled || exit 1
|
||||||
|
compare outside-both-2x2
|
||||||
|
|
||||||
|
# Window BIGGER than the client: only part of the window is viewed and the view
|
||||||
|
# can be panned (refresh-client). This exercises a non-zero scene offset.
|
||||||
|
# A 2x2 grid in a 60x20 window viewed through the 40x14 client.
|
||||||
|
new_scene 60 20
|
||||||
|
$TMUX2 splitw -h "$C" || exit 1
|
||||||
|
$TMUX2 splitw -v "$C" || exit 1
|
||||||
|
$TMUX2 selectp -t0 || exit 1
|
||||||
|
$TMUX2 splitw -v "$C" || exit 1
|
||||||
|
$TMUX2 select-layout tiled || exit 1
|
||||||
|
|
||||||
|
# Default view: the top-left of the window.
|
||||||
|
$TMUX2 refresh-client -U 100 || exit 1
|
||||||
|
$TMUX2 refresh-client -L 100 || exit 1
|
||||||
|
compare bigger-topleft
|
||||||
|
|
||||||
|
# Panned to the bottom-right of the window (down and right to the limit).
|
||||||
|
$TMUX2 refresh-client -D 100 || exit 1
|
||||||
|
$TMUX2 refresh-client -R 100 || exit 1
|
||||||
|
compare bigger-bottomright
|
||||||
|
|
||||||
|
exit 0
|
||||||
92
regress/screen-redraw-popups.sh
Normal file
92
regress/screen-redraw-popups.sh
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Exercise drawing of popups (display-popup) over the window scene. A popup is an
|
||||||
|
# overlay drawn on top of the redraw scene (the overlay_draw path in
|
||||||
|
# screen-redraw.c), so this guards against regressions in how popups appear.
|
||||||
|
#
|
||||||
|
# A popup is modal and stays open until its command exits, so each scene fully
|
||||||
|
# re-creates the servers and re-attaches; the popup is opened in the background
|
||||||
|
# (display-popup blocks the client that runs it) and the outer pane is captured
|
||||||
|
# while it is open.
|
||||||
|
#
|
||||||
|
# Run with GENERATE=1 to (re)create the golden files.
|
||||||
|
|
||||||
|
PATH=/bin:/usr/bin
|
||||||
|
TERM=screen
|
||||||
|
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"
|
||||||
|
RESULTS=screen-redraw-results
|
||||||
|
|
||||||
|
TMP=$(mktemp)
|
||||||
|
trap "rm -f $TMP; $TMUX kill-server 2>/dev/null; $TMUX2 kill-server 2>/dev/null" \
|
||||||
|
0 1 15
|
||||||
|
|
||||||
|
fail() {
|
||||||
|
echo "$*" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
compare() {
|
||||||
|
sleep 1
|
||||||
|
$TMUX capturep -p >$TMP || exit 1
|
||||||
|
if [ -n "$GENERATE" ]; then
|
||||||
|
cp $TMP "$RESULTS/$1.result" || exit 1
|
||||||
|
echo "generated $1"
|
||||||
|
else
|
||||||
|
cmp -s $TMP "$RESULTS/$1.result" || \
|
||||||
|
fail "scene $1 differs from $RESULTS/$1.result"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
C="sh -c 'i=0; while [ \$i -lt 13 ]; do printf \"POP%02d abcdefghij\n\" \$i; i=\$((i + 1)); done; exec sleep 100'"
|
||||||
|
|
||||||
|
# setup: fresh inner window attached inside a fresh outer pane, 40x14.
|
||||||
|
setup() {
|
||||||
|
$TMUX kill-server 2>/dev/null
|
||||||
|
$TMUX2 kill-server 2>/dev/null
|
||||||
|
$TMUX2 new -d -x40 -y14 "$C" || exit 1
|
||||||
|
$TMUX2 set -g status off || exit 1
|
||||||
|
$TMUX2 set -g window-size manual || exit 1
|
||||||
|
$TMUX2 resizew -x40 -y14 || exit 1
|
||||||
|
$TMUX new -d -x40 -y14 || exit 1
|
||||||
|
$TMUX set -g status off || exit 1
|
||||||
|
$TMUX set -g window-size manual || exit 1
|
||||||
|
$TMUX set -g default-terminal "tmux-256color" || exit 1
|
||||||
|
$TMUX send -l "$TMUX2 attach" || exit 1
|
||||||
|
$TMUX send Enter || exit 1
|
||||||
|
sleep 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# popup <args>: open a popup running a fixed command, in the background (it stays
|
||||||
|
# open because the command sleeps; the servers are killed at the next setup).
|
||||||
|
popup() {
|
||||||
|
$TMUX2 display-popup "$@" -E "sh -c 'printf POPUP; exec sleep 100'" &
|
||||||
|
sleep 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Basic popup over a single pane.
|
||||||
|
setup
|
||||||
|
popup -w20 -h6 -x6 -y3
|
||||||
|
compare popup-basic
|
||||||
|
|
||||||
|
# Popup over a split: drawn on top of the pane border.
|
||||||
|
setup
|
||||||
|
$TMUX2 splitw -h "$C" || exit 1
|
||||||
|
popup -w24 -h8 -x8 -y3
|
||||||
|
compare popup-over-split
|
||||||
|
|
||||||
|
# Popup with no border lines (-B).
|
||||||
|
setup
|
||||||
|
popup -B -w20 -h6 -x6 -y3
|
||||||
|
compare popup-noborder
|
||||||
|
|
||||||
|
# Popup with double border lines.
|
||||||
|
setup
|
||||||
|
popup -b double -w20 -h6 -x6 -y3
|
||||||
|
compare popup-double
|
||||||
|
|
||||||
|
exit 0
|
||||||
12
regress/screen-redraw-results/arrows-2pane-left.result
Normal file
12
regress/screen-redraw-results/arrows-2pane-left.result
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
│
|
||||||
|
←
|
||||||
|
│
|
||||||
|
│
|
||||||
|
│
|
||||||
|
│
|
||||||
|
│
|
||||||
|
│
|
||||||
|
│
|
||||||
|
│
|
||||||
|
│
|
||||||
|
│
|
||||||
12
regress/screen-redraw-results/arrows-2pane-right.result
Normal file
12
regress/screen-redraw-results/arrows-2pane-right.result
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
│
|
||||||
|
→
|
||||||
|
│
|
||||||
|
│
|
||||||
|
│
|
||||||
|
│
|
||||||
|
│
|
||||||
|
│
|
||||||
|
│
|
||||||
|
│
|
||||||
|
│
|
||||||
|
│
|
||||||
12
regress/screen-redraw-results/arrows-3pane.result
Normal file
12
regress/screen-redraw-results/arrows-3pane.result
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
│ │
|
||||||
|
→ ←
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
12
regress/screen-redraw-results/arrows-4pane.result
Normal file
12
regress/screen-redraw-results/arrows-4pane.result
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
│
|
||||||
|
←
|
||||||
|
│
|
||||||
|
│
|
||||||
|
│
|
||||||
|
─↑─────────────────┼────────────────────
|
||||||
|
│
|
||||||
|
│
|
||||||
|
│
|
||||||
|
│
|
||||||
|
│
|
||||||
|
│
|
||||||
12
regress/screen-redraw-results/bidi-single.result
Normal file
12
regress/screen-redraw-results/bidi-single.result
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
BIDI-LEFT 12345
|
||||||
|
BIDI-RIGHT 67890
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
12
regress/screen-redraw-results/bidi-split.result
Normal file
12
regress/screen-redraw-results/bidi-split.result
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
BIDI-LEFT 12345 │BIDI-PANE 12345
|
||||||
|
BIDI-RIGHT 67890 │BIDI-PANE 67890
|
||||||
|
│
|
||||||
|
│
|
||||||
|
│
|
||||||
|
│
|
||||||
|
│
|
||||||
|
│
|
||||||
|
│
|
||||||
|
│
|
||||||
|
│
|
||||||
|
│
|
||||||
14
regress/screen-redraw-results/bigger-bottomright.result
Normal file
14
regress/screen-redraw-results/bigger-bottomright.result
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
│PAN06 abcdefghij
|
||||||
|
│PAN07 abcdefghij
|
||||||
|
│
|
||||||
|
─────────┼──────────────────────────────
|
||||||
|
│PAN00 abcdefghij
|
||||||
|
│PAN01 abcdefghij
|
||||||
|
│PAN02 abcdefghij
|
||||||
|
│PAN03 abcdefghij
|
||||||
|
│PAN04 abcdefghij
|
||||||
|
│PAN05 abcdefghij
|
||||||
|
│PAN06 abcdefghij
|
||||||
|
│PAN07 abcdefghij
|
||||||
|
│
|
||||||
|
│
|
||||||
14
regress/screen-redraw-results/bigger-topleft.result
Normal file
14
regress/screen-redraw-results/bigger-topleft.result
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
OUT11 abcdefghij │PAN00 abcd
|
||||||
|
OUT12 abcdefghij │PAN01 abcd
|
||||||
|
OUT13 abcdefghij │PAN02 abcd
|
||||||
|
OUT14 abcdefghij │PAN03 abcd
|
||||||
|
OUT15 abcdefghij │PAN04 abcd
|
||||||
|
OUT16 abcdefghij │PAN05 abcd
|
||||||
|
OUT17 abcdefghij │PAN06 abcd
|
||||||
|
OUT18 abcdefghij │PAN07 abcd
|
||||||
|
│
|
||||||
|
─────────────────────────────┼──────────
|
||||||
|
PAN00 abcdefghij │PAN00 abcd
|
||||||
|
PAN01 abcdefghij │PAN01 abcd
|
||||||
|
PAN02 abcdefghij │PAN02 abcd
|
||||||
|
PAN03 abcdefghij │PAN03 abcd
|
||||||
14
regress/screen-redraw-results/cache-resize-after.result
Normal file
14
regress/screen-redraw-results/cache-resize-after.result
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
hij │PANE00 abcdefghij
|
||||||
|
BASE07 abcdefg│PANE01 abcdefghij
|
||||||
|
hij │PANE02 abcdefghij
|
||||||
|
BASE08 abcdefg│PANE03 abcdefghij
|
||||||
|
hij │PANE04 abcdefghij
|
||||||
|
BASE09 abcdefg│
|
||||||
|
hij │
|
||||||
|
BASE10 abcdefg│
|
||||||
|
hij │
|
||||||
|
BASE11 abcdefg│
|
||||||
|
hij │
|
||||||
|
BASE12 abcdefg│
|
||||||
|
hij │
|
||||||
|
│
|
||||||
14
regress/screen-redraw-results/cache-resize-before.result
Normal file
14
regress/screen-redraw-results/cache-resize-before.result
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
BASE00 abcdefghij │PANE00 abcdefghij
|
||||||
|
BASE01 abcdefghij │PANE01 abcdefghij
|
||||||
|
BASE02 abcdefghij │PANE02 abcdefghij
|
||||||
|
BASE03 abcdefghij │PANE03 abcdefghij
|
||||||
|
BASE04 abcdefghij │PANE04 abcdefghij
|
||||||
|
BASE05 abcdefghij │
|
||||||
|
BASE06 abcdefghij │
|
||||||
|
BASE07 abcdefghij │
|
||||||
|
BASE08 abcdefghij │
|
||||||
|
BASE09 abcdefghij │
|
||||||
|
BASE10 abcdefghij │
|
||||||
|
BASE11 abcdefghij │
|
||||||
|
BASE12 abcdefghij │
|
||||||
|
│
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
SIZE09 abcdefghij
|
||||||
|
SIZE10 abcdefghij
|
||||||
|
SIZE11 abcdefghij
|
||||||
|
SIZE12 abcdefghij
|
||||||
|
|
||||||
|
──────────────────────────────
|
||||||
|
PANE02 abcdefghij
|
||||||
|
PANE03 abcdefghij
|
||||||
|
PANE04 abcdefghij
|
||||||
|
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
SIZE07 abcdefghij
|
||||||
|
SIZE08 abcdefghij
|
||||||
|
SIZE09 abcdefghij
|
||||||
|
SIZE10 abcdefghij
|
||||||
|
SIZE11 abcdefghij
|
||||||
|
SIZE12 abcdefghij
|
||||||
|
|
||||||
|
────────────────────────────────────────
|
||||||
|
PANE00 abcdefghij
|
||||||
|
PANE01 abcdefghij
|
||||||
|
PANE02 abcdefghij
|
||||||
|
PANE03 abcdefghij
|
||||||
|
PANE04 abcdefghij
|
||||||
|
|
||||||
14
regress/screen-redraw-results/cache-rotate-after.result
Normal file
14
regress/screen-redraw-results/cache-rotate-after.result
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
── BBB ───┬── CCC ──┬── AAA ────────────
|
||||||
|
PANE00 abc│cdefghij │BASE01 abcdefghij
|
||||||
|
defghij │PANE03 ab│BASE02 abcdefghij
|
||||||
|
PANE01 abc│cdefghij │BASE03 abcdefghij
|
||||||
|
defghij │PANE04 ab│BASE04 abcdefghij
|
||||||
|
PANE02 abc│cdefghij │BASE05 abcdefghij
|
||||||
|
defghij │ │BASE06 abcdefghij
|
||||||
|
PANE03 abc│ │BASE07 abcdefghij
|
||||||
|
defghij │ │BASE08 abcdefghij
|
||||||
|
PANE04 abc│ │BASE09 abcdefghij
|
||||||
|
defghij │ │BASE10 abcdefghij
|
||||||
|
│ │BASE11 abcdefghij
|
||||||
|
│ │BASE12 abcdefghij
|
||||||
|
│ │
|
||||||
14
regress/screen-redraw-results/cache-rotate-before.result
Normal file
14
regress/screen-redraw-results/cache-rotate-before.result
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
── AAA ───┬── BBB ──┬── CCC ────────────
|
||||||
|
BASE07 abc│PANE00 ab│PANE00 abcdefghij
|
||||||
|
defghij │cdefghij │PANE01 abcdefghij
|
||||||
|
BASE08 abc│PANE01 ab│PANE02 abcdefghij
|
||||||
|
defghij │cdefghij │PANE03 abcdefghij
|
||||||
|
BASE09 abc│PANE02 ab│PANE04 abcdefghij
|
||||||
|
defghij │cdefghij │
|
||||||
|
BASE10 abc│PANE03 ab│
|
||||||
|
defghij │cdefghij │
|
||||||
|
BASE11 abc│PANE04 ab│
|
||||||
|
defghij │cdefghij │
|
||||||
|
BASE12 abc│ │
|
||||||
|
defghij │ │
|
||||||
|
│ │
|
||||||
14
regress/screen-redraw-results/cache-swap-after.result
Normal file
14
regress/screen-redraw-results/cache-swap-after.result
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
── RIGHT ───────────┬── LEFT ───────────
|
||||||
|
PANE00 abcdefghij │BASE01 abcdefghij
|
||||||
|
PANE01 abcdefghij │BASE02 abcdefghij
|
||||||
|
PANE02 abcdefghij │BASE03 abcdefghij
|
||||||
|
PANE03 abcdefghij │BASE04 abcdefghij
|
||||||
|
PANE04 abcdefghij │BASE05 abcdefghij
|
||||||
|
│BASE06 abcdefghij
|
||||||
|
│BASE07 abcdefghij
|
||||||
|
│BASE08 abcdefghij
|
||||||
|
│BASE09 abcdefghij
|
||||||
|
│BASE10 abcdefghij
|
||||||
|
│BASE11 abcdefghij
|
||||||
|
│BASE12 abcdefghij
|
||||||
|
│
|
||||||
14
regress/screen-redraw-results/cache-swap-before.result
Normal file
14
regress/screen-redraw-results/cache-swap-before.result
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
── LEFT ────────────┬── RIGHT ──────────
|
||||||
|
BASE01 abcdefghij │PANE00 abcdefghij
|
||||||
|
BASE02 abcdefghij │PANE01 abcdefghij
|
||||||
|
BASE03 abcdefghij │PANE02 abcdefghij
|
||||||
|
BASE04 abcdefghij │PANE03 abcdefghij
|
||||||
|
BASE05 abcdefghij │PANE04 abcdefghij
|
||||||
|
BASE06 abcdefghij │
|
||||||
|
BASE07 abcdefghij │
|
||||||
|
BASE08 abcdefghij │
|
||||||
|
BASE09 abcdefghij │
|
||||||
|
BASE10 abcdefghij │
|
||||||
|
BASE11 abcdefghij │
|
||||||
|
BASE12 abcdefghij │
|
||||||
|
│
|
||||||
14
regress/screen-redraw-results/cache-window-a-again.result
Normal file
14
regress/screen-redraw-results/cache-window-a-again.result
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
WINA00 abcdefghij
|
||||||
|
WINA01 abcdefghij
|
||||||
|
WINA02 abcdefghij
|
||||||
|
WINA03 abcdefghij
|
||||||
|
WINA04 abcdefghij
|
||||||
|
WINA05 abcdefghij
|
||||||
|
WINA06 abcdefghij
|
||||||
|
WINA07 abcdefghij
|
||||||
|
WINA08 abcdefghij
|
||||||
|
WINA09 abcdefghij
|
||||||
|
WINA10 abcdefghij
|
||||||
|
WINA11 abcdefghij
|
||||||
|
WINA12 abcdefghij
|
||||||
|
|
||||||
14
regress/screen-redraw-results/cache-window-a.result
Normal file
14
regress/screen-redraw-results/cache-window-a.result
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
WINA00 abcdefghij
|
||||||
|
WINA01 abcdefghij
|
||||||
|
WINA02 abcdefghij
|
||||||
|
WINA03 abcdefghij
|
||||||
|
WINA04 abcdefghij
|
||||||
|
WINA05 abcdefghij
|
||||||
|
WINA06 abcdefghij
|
||||||
|
WINA07 abcdefghij
|
||||||
|
WINA08 abcdefghij
|
||||||
|
WINA09 abcdefghij
|
||||||
|
WINA10 abcdefghij
|
||||||
|
WINA11 abcdefghij
|
||||||
|
WINA12 abcdefghij
|
||||||
|
|
||||||
14
regress/screen-redraw-results/cache-window-b.result
Normal file
14
regress/screen-redraw-results/cache-window-b.result
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
WINB07 abcdefghij
|
||||||
|
WINB08 abcdefghij
|
||||||
|
WINB09 abcdefghij
|
||||||
|
WINB10 abcdefghij
|
||||||
|
WINB11 abcdefghij
|
||||||
|
WINB12 abcdefghij
|
||||||
|
|
||||||
|
────────────────────────────────────────
|
||||||
|
PANE00 abcdefghij
|
||||||
|
PANE01 abcdefghij
|
||||||
|
PANE02 abcdefghij
|
||||||
|
PANE03 abcdefghij
|
||||||
|
PANE04 abcdefghij
|
||||||
|
|
||||||
12
regress/screen-redraw-results/colour-three-suppressed.result
Normal file
12
regress/screen-redraw-results/colour-three-suppressed.result
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
[31m│[39m [32m│[39m
|
||||||
|
[31m│[39m [32m│[39m
|
||||||
|
[31m│[39m [32m│[39m
|
||||||
|
[31m│[39m [32m│[39m
|
||||||
|
[31m│[39m [32m│[39m
|
||||||
|
[31m│[39m [32m│[39m
|
||||||
|
[31m│[39m [32m│[39m
|
||||||
|
[31m│[39m [32m│[39m
|
||||||
|
[31m│[39m [32m│[39m
|
||||||
|
[31m│[39m [32m│[39m
|
||||||
|
[31m│[39m [32m│[39m
|
||||||
|
[31m│[39m [32m│[39m
|
||||||
12
regress/screen-redraw-results/colour-two-plus-float.result
Normal file
12
regress/screen-redraw-results/colour-two-plus-float.result
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
[31m│[39m
|
||||||
|
[32m┌────────────────┐[39m
|
||||||
|
[32m│[39m [32m│[39m
|
||||||
|
[32m│[39m [32m│[39m
|
||||||
|
[32m│[39m [32m│[39m
|
||||||
|
[32m│[39m [32m│[39m
|
||||||
|
[32m│[39m [32m│[39m
|
||||||
|
[32m│[39m [32m│[39m
|
||||||
|
[32m└────────────────┘[39m
|
||||||
|
[32m│[39m
|
||||||
|
[32m│[39m
|
||||||
|
[32m│[39m
|
||||||
14
regress/screen-redraw-results/cross-double.result
Normal file
14
regress/screen-redraw-results/cross-double.result
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
║
|
||||||
|
║
|
||||||
|
║
|
||||||
|
║
|
||||||
|
║
|
||||||
|
║
|
||||||
|
═══════════════════╬════════════════════
|
||||||
|
║
|
||||||
|
║
|
||||||
|
║
|
||||||
|
║
|
||||||
|
║
|
||||||
|
║
|
||||||
|
║
|
||||||
14
regress/screen-redraw-results/cross-heavy.result
Normal file
14
regress/screen-redraw-results/cross-heavy.result
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
┃
|
||||||
|
┃
|
||||||
|
┃
|
||||||
|
┃
|
||||||
|
┃
|
||||||
|
┃
|
||||||
|
━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━
|
||||||
|
┃
|
||||||
|
┃
|
||||||
|
┃
|
||||||
|
┃
|
||||||
|
┃
|
||||||
|
┃
|
||||||
|
┃
|
||||||
14
regress/screen-redraw-results/cross-none.result
Normal file
14
regress/screen-redraw-results/cross-none.result
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
14
regress/screen-redraw-results/cross-number.result
Normal file
14
regress/screen-redraw-results/cross-number.result
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
1
|
||||||
|
1
|
||||||
|
1
|
||||||
|
1
|
||||||
|
1
|
||||||
|
1
|
||||||
|
0000000000000000000011111111111111111111
|
||||||
|
2
|
||||||
|
2
|
||||||
|
2
|
||||||
|
2
|
||||||
|
2
|
||||||
|
2
|
||||||
|
2
|
||||||
14
regress/screen-redraw-results/cross-simple.result
Normal file
14
regress/screen-redraw-results/cross-simple.result
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
-------------------+--------------------
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
|
|
||||||
14
regress/screen-redraw-results/cross-single.result
Normal file
14
regress/screen-redraw-results/cross-single.result
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
│
|
||||||
|
│
|
||||||
|
│
|
||||||
|
│
|
||||||
|
│
|
||||||
|
│
|
||||||
|
───────────────────┼────────────────────
|
||||||
|
│
|
||||||
|
│
|
||||||
|
│
|
||||||
|
│
|
||||||
|
│
|
||||||
|
│
|
||||||
|
│
|
||||||
14
regress/screen-redraw-results/cross-spaces.result
Normal file
14
regress/screen-redraw-results/cross-spaces.result
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
12
regress/screen-redraw-results/floating-basic.result
Normal file
12
regress/screen-redraw-results/floating-basic.result
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
base
|
||||||
|
|
||||||
|
┌────────────────────┐
|
||||||
|
│FLOAT │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
│ │
|
||||||
|
└────────────────────┘
|
||||||
|
|
||||||
|
|
||||||
12
regress/screen-redraw-results/floating-border-double.result
Normal file
12
regress/screen-redraw-results/floating-border-double.result
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
bas╔════════════════════════════╗
|
||||||
|
║FLOAT ║
|
||||||
|
║ ║
|
||||||
|
║ ║
|
||||||
|
║ ║
|
||||||
|
║ ║
|
||||||
|
║ ║
|
||||||
|
║ ║
|
||||||
|
║ ║
|
||||||
|
╚════════════════════════════╝
|
||||||
|
|
||||||
|
|
||||||
12
regress/screen-redraw-results/floating-clip-bottom.result
Normal file
12
regress/screen-redraw-results/floating-clip-bottom.result
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
01:abcdefghijklmnopqrstuvwxyz0123456789
|
||||||
|
02:abcdefghijklmnopqrstuvwxyz0123456789
|
||||||
|
03:abcdefghijklmnopqrstuvwxyz0123456789
|
||||||
|
04:abcdefghijklmnopqrstuvwxyz0123456789
|
||||||
|
05:abcdefghijklmnopqrstuvwxyz0123456789
|
||||||
|
06:abcdefghijklmnopqrstuvwxyz0123456789
|
||||||
|
07:abcdefghijklmnopqrstuvwxyz0123456789
|
||||||
|
08:abcdefghijklmnopqrstuvwxyz0123456789
|
||||||
|
09:abcdef┌────────────────────┐23456789
|
||||||
|
10:abcdef│BOTTOM │23456789
|
||||||
|
11:abcdef│ │23456789
|
||||||
|
│ │
|
||||||
12
regress/screen-redraw-results/floating-clip-edge.result
Normal file
12
regress/screen-redraw-results/floating-clip-edge.result
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
base
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
┌──────────
|
||||||
|
│CLIP
|
||||||
|
│
|
||||||
|
│
|
||||||
|
│
|
||||||
12
regress/screen-redraw-results/floating-clip-left.result
Normal file
12
regress/screen-redraw-results/floating-clip-left.result
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
01:abcdefghijklmnopqrstuvwxyz0123456789
|
||||||
|
02:abcdefghijklmnopqrstuvwxyz0123456789
|
||||||
|
──────────┐ijklmnopqrstuvwxyz0123456789
|
||||||
|
│ijklmnopqrstuvwxyz0123456789
|
||||||
|
│ijklmnopqrstuvwxyz0123456789
|
||||||
|
│ijklmnopqrstuvwxyz0123456789
|
||||||
|
│ijklmnopqrstuvwxyz0123456789
|
||||||
|
│ijklmnopqrstuvwxyz0123456789
|
||||||
|
│ijklmnopqrstuvwxyz0123456789
|
||||||
|
──────────┘ijklmnopqrstuvwxyz0123456789
|
||||||
|
11:abcdefghijklmnopqrstuvwxyz0123456789
|
||||||
|
|
||||||
12
regress/screen-redraw-results/floating-clip-right.result
Normal file
12
regress/screen-redraw-results/floating-clip-right.result
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
01:abcdefghijklmnopqrstuvwxyz0123456789
|
||||||
|
02:abcdefghijklmnopqrstuvwxyz0123456789
|
||||||
|
03:abcdefghijklmnopqrstuvwxyz┌──────────
|
||||||
|
04:abcdefghijklmnopqrstuvwxyz│RIGHT
|
||||||
|
05:abcdefghijklmnopqrstuvwxyz│
|
||||||
|
06:abcdefghijklmnopqrstuvwxyz│
|
||||||
|
07:abcdefghijklmnopqrstuvwxyz│
|
||||||
|
08:abcdefghijklmnopqrstuvwxyz│
|
||||||
|
09:abcdefghijklmnopqrstuvwxyz│
|
||||||
|
10:abcdefghijklmnopqrstuvwxyz└──────────
|
||||||
|
11:abcdefghijklmnopqrstuvwxyz0123456789
|
||||||
|
|
||||||
12
regress/screen-redraw-results/floating-clip-top.result
Normal file
12
regress/screen-redraw-results/floating-clip-top.result
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
01:abcdef│ │23456789
|
||||||
|
02:abcdef│ │23456789
|
||||||
|
03:abcdef│ │23456789
|
||||||
|
04:abcdef└────────────────────┘23456789
|
||||||
|
05:abcdefghijklmnopqrstuvwxyz0123456789
|
||||||
|
06:abcdefghijklmnopqrstuvwxyz0123456789
|
||||||
|
07:abcdefghijklmnopqrstuvwxyz0123456789
|
||||||
|
08:abcdefghijklmnopqrstuvwxyz0123456789
|
||||||
|
09:abcdefghijklmnopqrstuvwxyz0123456789
|
||||||
|
10:abcdefghijklmnopqrstuvwxyz0123456789
|
||||||
|
11:abcdefghijklmnopqrstuvwxyz0123456789
|
||||||
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user