mirror of
https://github.com/tmux/tmux.git
synced 2026-07-23 17:22:42 +00:00
Merge branch 'master' into floating_panes
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -7,6 +7,8 @@
|
||||
*~
|
||||
.deps/
|
||||
.dirstamp
|
||||
.serena/
|
||||
AGENTS.md
|
||||
Makefile
|
||||
Makefile.in
|
||||
aclocal.m4
|
||||
|
||||
@@ -163,6 +163,7 @@ dist_tmux_SOURCES = \
|
||||
file.c \
|
||||
format.c \
|
||||
format-draw.c \
|
||||
fuzzy.c \
|
||||
grid-reader.c \
|
||||
grid-view.c \
|
||||
grid.c \
|
||||
@@ -185,6 +186,8 @@ dist_tmux_SOURCES = \
|
||||
paste.c \
|
||||
popup.c \
|
||||
proc.c \
|
||||
prompt.c \
|
||||
prompt-history.c \
|
||||
regsub.c \
|
||||
resize.c \
|
||||
screen-redraw.c \
|
||||
@@ -210,11 +213,13 @@ dist_tmux_SOURCES = \
|
||||
tty.c \
|
||||
utf8-combined.c \
|
||||
utf8.c \
|
||||
window-border.c \
|
||||
window-buffer.c \
|
||||
window-client.c \
|
||||
window-clock.c \
|
||||
window-copy.c \
|
||||
window-customize.c \
|
||||
window-switch.c \
|
||||
window-tree.c \
|
||||
window-visible.c \
|
||||
window.c \
|
||||
|
||||
18
arguments.c
18
arguments.c
@@ -149,7 +149,7 @@ args_parse_flag_argument(struct args_value *values, u_int count, char **cause,
|
||||
int optional_argument)
|
||||
{
|
||||
struct args_value *argument, *new;
|
||||
const char *s;
|
||||
const char *s, *as;
|
||||
|
||||
new = xcalloc(1, sizeof *new);
|
||||
if (*string != '\0') {
|
||||
@@ -180,12 +180,24 @@ args_parse_flag_argument(struct args_value *values, u_int count, char **cause,
|
||||
xasprintf(cause, "-%c expects an argument", flag);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (optional_argument && argument->type == ARGS_STRING) {
|
||||
as = argument->string;
|
||||
if (as[0] == '-' && (as[1] == '-' || isalpha((u_char)as[1]))) {
|
||||
args_free_value(new);
|
||||
free(new);
|
||||
log_debug("%s: -%c (optional)", __func__, flag);
|
||||
args_set(args, flag, NULL, ARGS_ENTRY_OPTIONAL_VALUE);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
args_copy_value(new, argument);
|
||||
(*i)++;
|
||||
|
||||
out:
|
||||
s = args_value_as_string(new);
|
||||
log_debug("%s: -%c = %s", __func__, flag, s);
|
||||
|
||||
args_set(args, flag, new, 0);
|
||||
return (0);
|
||||
}
|
||||
@@ -998,7 +1010,7 @@ args_string_percentage(const char *value, long long minval, long long maxval,
|
||||
copy = xstrdup(value);
|
||||
copy[valuelen - 1] = '\0';
|
||||
|
||||
ll = strtonum(copy, 0, 100, &errstr);
|
||||
ll = strtonum(copy, 0, 1000, &errstr);
|
||||
free(copy);
|
||||
if (errstr != NULL) {
|
||||
*cause = xstrdup(errstr);
|
||||
@@ -1066,7 +1078,7 @@ args_string_percentage_and_expand(const char *value, long long minval,
|
||||
copy[valuelen - 1] = '\0';
|
||||
|
||||
f = format_single_from_target(item, copy);
|
||||
ll = strtonum(f, 0, 100, &errstr);
|
||||
ll = strtonum(f, 0, 1000, &errstr);
|
||||
free(f);
|
||||
free(copy);
|
||||
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)
|
||||
cmdq_continue(cfg_item);
|
||||
|
||||
status_prompt_load_history();
|
||||
prompt_load_history();
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
@@ -54,6 +54,7 @@ cmd_break_pane_float(struct cmdq_item *item, struct args *args,
|
||||
u_int sx = lc->saved_sx, sy = lc->saved_sy;
|
||||
int ox = lc->saved_xoff, oy = lc->saved_yoff;
|
||||
char *cause = NULL;
|
||||
enum pane_lines lines = window_get_pane_lines(w);
|
||||
|
||||
if (window_pane_is_floating(wp)) {
|
||||
cmdq_error(item, "pane is already floating");
|
||||
@@ -68,13 +69,13 @@ cmd_break_pane_float(struct cmdq_item *item, struct args *args,
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
layout_remove_tile(w, lc);
|
||||
layout_cell_floating_args_parse(item, args, w, &sx, &sy, &ox, &oy, &cause);
|
||||
if (cause != NULL) {
|
||||
if (layout_floating_args_parse(item, args, lines, w, &sx, &sy, &ox, &oy,
|
||||
&cause) != 0) {
|
||||
cmdq_error(item, "failed to float pane: %s", cause);
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
layout_remove_tile(w, lc);
|
||||
layout_set_size(lc, sx, sy, ox, oy);
|
||||
|
||||
lc->flags |= LAYOUT_CELL_FLOATING;
|
||||
@@ -111,7 +112,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (args_has(args, 'W'))
|
||||
return (cmd_break_pane_float(item, args, w, wp));
|
||||
|
||||
if (name != NULL && !check_name(name, WINDOW_NAME_FORBID)) {
|
||||
if (name != NULL && !check_name(name)) {
|
||||
cmdq_error(item, "invalid window name: %s", name);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
@@ -135,7 +136,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
if (name != NULL) {
|
||||
window_set_name(w, name, WINDOW_NAME_FORBID);
|
||||
window_set_name(w, name, 0);
|
||||
options_set_number(w->options, "automatic-rename", 0);
|
||||
}
|
||||
server_unlink_window(src_s, wl);
|
||||
@@ -165,7 +166,7 @@ cmd_break_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
|
||||
if (name == NULL) {
|
||||
newname = default_window_name(w);
|
||||
window_set_name(w, newname, WINDOW_NAME_FORBID);
|
||||
window_set_name(w, newname, 0);
|
||||
free(newname);
|
||||
} else {
|
||||
window_set_name(w, name, 0);
|
||||
|
||||
@@ -318,6 +318,7 @@ cmd_capture_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
grid_clear_history(wp->base.grid);
|
||||
if (args_has(args, 'H'))
|
||||
screen_reset_hyperlinks(wp->screen);
|
||||
server_redraw_window(wp->window);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
|
||||
@@ -84,6 +84,19 @@ const struct cmd_entry cmd_customize_mode_entry = {
|
||||
.exec = cmd_choose_tree_exec
|
||||
};
|
||||
|
||||
const struct cmd_entry cmd_switch_mode_entry = {
|
||||
.name = "switch-mode",
|
||||
.alias = NULL,
|
||||
|
||||
.args = { "F:kst:wZ", 0, 1, cmd_choose_tree_args_parse },
|
||||
.usage = "[-kswZ] [-F format] " CMD_TARGET_PANE_USAGE " [command]",
|
||||
|
||||
.target = { 't', CMD_FIND_PANE, 0 },
|
||||
|
||||
.flags = 0,
|
||||
.exec = cmd_choose_tree_exec
|
||||
};
|
||||
|
||||
static enum args_parse_type
|
||||
cmd_choose_tree_args_parse(__unused struct args *args, __unused u_int idx,
|
||||
__unused char **cause)
|
||||
@@ -116,6 +129,8 @@ cmd_choose_tree_exec(struct cmd *self, struct cmdq_item *item)
|
||||
mode = &window_client_mode;
|
||||
} else if (cmd_get_entry(self) == &cmd_customize_mode_entry)
|
||||
mode = &window_customize_mode;
|
||||
else if (cmd_get_entry(self) == &cmd_switch_mode_entry)
|
||||
mode = &window_switch_mode;
|
||||
else
|
||||
mode = &window_tree_mode;
|
||||
|
||||
|
||||
@@ -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 *,
|
||||
struct cmdq_item *);
|
||||
|
||||
static int cmd_command_prompt_callback(struct client *, void *,
|
||||
const char *, int);
|
||||
static enum prompt_result cmd_command_prompt_callback(struct client *, void *,
|
||||
const char *, enum prompt_key_result);
|
||||
static void cmd_command_prompt_free(void *);
|
||||
|
||||
const struct cmd_entry cmd_command_prompt_entry = {
|
||||
.name = "command-prompt",
|
||||
.alias = NULL,
|
||||
|
||||
.args = { "1CbeFiklI:Np:t:T:", 0, 1, cmd_command_prompt_args_parse },
|
||||
.usage = "[-1CbeFiklN] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE
|
||||
.args = { "1CbeFiklI:NPp:t:T:", 0, 1, cmd_command_prompt_args_parse },
|
||||
.usage = "[-1CbeFiklNP] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE
|
||||
" [-T prompt-type] [template]",
|
||||
|
||||
.flags = CMD_CLIENT_TFLAG,
|
||||
@@ -62,6 +62,8 @@ struct cmd_command_prompt_cdata {
|
||||
int flags;
|
||||
enum prompt_type prompt_type;
|
||||
|
||||
struct window_pane *wp;
|
||||
|
||||
struct cmd_command_prompt_prompt *prompts;
|
||||
u_int count;
|
||||
u_int current;
|
||||
@@ -87,10 +89,15 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
|
||||
struct cmd_command_prompt_cdata *cdata;
|
||||
char *tmp, *prompts, *prompt, *next_prompt;
|
||||
char *inputs = NULL, *next_input;
|
||||
struct window_pane *wp = target->wp;
|
||||
u_int count = args_count(args);
|
||||
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);
|
||||
if (args_has(args, 'i'))
|
||||
wait = 0;
|
||||
@@ -98,6 +105,8 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
|
||||
cdata = xcalloc(1, sizeof *cdata);
|
||||
if (wait)
|
||||
cdata->item = item;
|
||||
if (pane)
|
||||
cdata->wp = wp;
|
||||
cdata->state = args_make_commands_prepare(self, item, 0, "%1", wait,
|
||||
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) {
|
||||
cdata->prompt_type = status_prompt_type(type);
|
||||
cdata->prompt_type = prompt_type(type);
|
||||
if (cdata->prompt_type == PROMPT_TYPE_INVALID) {
|
||||
cmdq_error(item, "unknown type: %s", type);
|
||||
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;
|
||||
if (args_has(args, 'C'))
|
||||
cdata->flags |= PROMPT_NOFREEZE;
|
||||
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 (pane) {
|
||||
cdata->flags |= PROMPT_ISPANE;
|
||||
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)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
return (CMD_RETURN_WAIT);
|
||||
}
|
||||
|
||||
static int
|
||||
static enum prompt_result
|
||||
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;
|
||||
char *error;
|
||||
@@ -188,26 +206,30 @@ cmd_command_prompt_callback(struct client *c, void *data, const char *s,
|
||||
int argc = 0;
|
||||
char **argv = NULL;
|
||||
|
||||
if (s == NULL)
|
||||
if (s == NULL || key == PROMPT_KEY_MOVE)
|
||||
goto out;
|
||||
|
||||
if (done) {
|
||||
if (key == PROMPT_KEY_CLOSE) {
|
||||
if (cdata->flags & PROMPT_INCREMENTAL)
|
||||
goto out;
|
||||
cmd_append_argv(&cdata->argc, &cdata->argv, s);
|
||||
if (++cdata->current != cdata->count) {
|
||||
prompt = &cdata->prompts[cdata->current];
|
||||
status_prompt_update(c, prompt->prompt, prompt->input);
|
||||
return (1);
|
||||
if (cdata->wp != NULL) {
|
||||
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;
|
||||
argv = cmd_copy_argv(cdata->argc, cdata->argv);
|
||||
if (!done)
|
||||
if (key != PROMPT_KEY_CLOSE)
|
||||
cmd_append_argv(&argc, &argv, s);
|
||||
|
||||
if (done) {
|
||||
else {
|
||||
cmd_free_argv(cdata->argc, cdata->argv);
|
||||
cdata->argc = argc;
|
||||
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);
|
||||
|
||||
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:
|
||||
if (item != NULL)
|
||||
if (item != NULL) {
|
||||
cdata->item = NULL;
|
||||
cmdq_continue(item);
|
||||
return (0);
|
||||
}
|
||||
return (PROMPT_CLOSE);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -241,6 +270,11 @@ cmd_command_prompt_free(void *data)
|
||||
struct cmd_command_prompt_cdata *cdata = data;
|
||||
u_int i;
|
||||
|
||||
if (cdata->item != NULL) {
|
||||
cmdq_continue(cdata->item);
|
||||
cdata->item = NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < cdata->count; i++) {
|
||||
free(cdata->prompts[i].prompt);
|
||||
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 *,
|
||||
struct cmdq_item *);
|
||||
|
||||
static int cmd_confirm_before_callback(struct client *, void *,
|
||||
const char *, int);
|
||||
static enum prompt_result cmd_confirm_before_callback(struct client *, void *,
|
||||
const char *, enum prompt_key_result);
|
||||
static void cmd_confirm_before_free(void *);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static int
|
||||
static enum prompt_result
|
||||
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 cmdq_item *item = cdata->item, *new_item;
|
||||
@@ -151,7 +151,7 @@ out:
|
||||
cmdq_get_client(item)->retval = retcode;
|
||||
cmdq_continue(item);
|
||||
}
|
||||
return (0);
|
||||
return (PROMPT_CLOSE);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -48,6 +48,16 @@ struct cmd_display_panes_data {
|
||||
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
|
||||
cmd_display_panes_args_parse(__unused struct args *args, __unused u_int idx,
|
||||
__unused char **cause)
|
||||
@@ -56,7 +66,7 @@ cmd_display_panes_args_parse(__unused struct args *args, __unused u_int idx,
|
||||
}
|
||||
|
||||
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 client *c = ctx->c;
|
||||
@@ -76,7 +86,7 @@ cmd_display_panes_put(struct screen_redraw_ctx *ctx,
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_display_panes_draw_format(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)
|
||||
{
|
||||
@@ -112,7 +122,7 @@ cmd_display_panes_draw_format(struct screen_redraw_ctx *ctx,
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
|
||||
cmd_display_panes_draw_pane(struct cmd_display_panes_ctx *ctx,
|
||||
struct window_pane *wp)
|
||||
{
|
||||
struct client *c = ctx->c;
|
||||
@@ -123,7 +133,8 @@ cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
|
||||
struct grid_cell fgc, bgc;
|
||||
u_int pane, idx, px, py, i, j, xoff, yoff, sx, sy;
|
||||
u_int cx, cy;
|
||||
int colour, active_colour;
|
||||
const char *name;
|
||||
struct format_tree *ft;
|
||||
char buf[16], lbuf[16], *ptr;
|
||||
size_t len, llen;
|
||||
|
||||
@@ -181,18 +192,16 @@ cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
|
||||
|
||||
if (sx < len)
|
||||
return;
|
||||
colour = options_get_number(oo, "display-panes-colour");
|
||||
active_colour = options_get_number(oo, "display-panes-active-colour");
|
||||
if (w->active == wp)
|
||||
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);
|
||||
if (w->active == wp) {
|
||||
fgc.fg = active_colour;
|
||||
bgc.bg = active_colour;
|
||||
} else {
|
||||
fgc.fg = colour;
|
||||
bgc.bg = colour;
|
||||
}
|
||||
bgc.bg = fgc.fg;
|
||||
|
||||
if (pane > 9 && pane < 35)
|
||||
llen = xsnprintf(lbuf, sizeof lbuf, "%c", 'a' + (pane - 10));
|
||||
@@ -254,17 +263,30 @@ out:
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_display_panes_draw(struct client *c, __unused void *data,
|
||||
struct screen_redraw_ctx *ctx)
|
||||
cmd_display_panes_draw(struct client *c, __unused void *data)
|
||||
{
|
||||
struct window *w = c->session->curw->window;
|
||||
struct window_pane *wp;
|
||||
struct session *s = c->session;
|
||||
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);
|
||||
|
||||
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) {
|
||||
if (window_pane_is_visible(wp))
|
||||
cmd_display_panes_draw_pane(ctx, wp);
|
||||
cmd_display_panes_draw_pane(&ctx, wp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -202,24 +202,29 @@ cmd_join_pane_move(struct cmdq_item *item, struct args *args,
|
||||
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)lc->sx,
|
||||
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)lc->sy,
|
||||
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++) {
|
||||
|
||||
@@ -101,22 +101,22 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
|
||||
|
||||
if ((tmp = args_get(args, 'n')) != NULL) {
|
||||
ename = format_single(item, tmp, c, NULL, NULL, NULL);
|
||||
if (!check_name(ename, WINDOW_NAME_FORBID)) {
|
||||
if (!check_name(ename)) {
|
||||
cmdq_error(item, "invalid window name: %s", ename);
|
||||
free(ename);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
wname = clean_name(ename, WINDOW_NAME_FORBID);
|
||||
wname = clean_name(ename, 0);
|
||||
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)) {
|
||||
if (!check_name(ename)) {
|
||||
cmdq_error(item, "invalid session name: %s", ename);
|
||||
free(ename);
|
||||
goto fail;
|
||||
}
|
||||
sname = clean_name(ename, SESSION_NAME_FORBID);
|
||||
sname = clean_name(ename, 0);
|
||||
free(ename);
|
||||
}
|
||||
if (args_has(args, 'A')) {
|
||||
@@ -152,12 +152,12 @@ cmd_new_session_exec(struct cmd *self, struct cmdq_item *item)
|
||||
else if (groupwith != NULL)
|
||||
prefix = xstrdup(groupwith->name);
|
||||
else {
|
||||
if (!check_name(group, SESSION_NAME_FORBID)) {
|
||||
if (!check_name(group)) {
|
||||
cmdq_error(item,
|
||||
"invalid session group name: %s", group);
|
||||
goto fail;
|
||||
}
|
||||
prefix = clean_name(group, SESSION_NAME_FORBID);
|
||||
prefix = clean_name(group, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -73,12 +73,12 @@ cmd_new_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
name = args_get(args, 'n');
|
||||
if (name != NULL) {
|
||||
expanded = format_single(item, name, c, s, NULL, NULL);
|
||||
if (!check_name(expanded, WINDOW_NAME_FORBID)) {
|
||||
if (!check_name(expanded)) {
|
||||
cmdq_error(item, "invalid window name: %s", expanded);
|
||||
free(expanded);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
wname = clean_name(expanded, WINDOW_NAME_FORBID);
|
||||
wname = clean_name(expanded, 0);
|
||||
free(expanded);
|
||||
}
|
||||
if (args_has(args, 'S') && wname != NULL && target->idx == -1) {
|
||||
|
||||
@@ -52,12 +52,12 @@ cmd_rename_session_exec(struct cmd *self, struct cmdq_item *item)
|
||||
char *newname, *tmp;
|
||||
|
||||
tmp = format_single_from_target(item, args_string(args, 0));
|
||||
if (!check_name(tmp, SESSION_NAME_FORBID)) {
|
||||
if (!check_name(tmp)) {
|
||||
cmdq_error(item, "invalid session name: %s", tmp);
|
||||
free(tmp);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
newname = clean_name(tmp, SESSION_NAME_FORBID);
|
||||
newname = clean_name(tmp, 0);
|
||||
free(tmp);
|
||||
if (strcmp(newname, s->name) == 0) {
|
||||
free(newname);
|
||||
|
||||
@@ -51,13 +51,13 @@ cmd_rename_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
char *name;
|
||||
|
||||
name = format_single_from_target(item, args_string(args, 0));
|
||||
if (!check_name(name, WINDOW_NAME_FORBID)) {
|
||||
if (!check_name(name)) {
|
||||
cmdq_error(item, "invalid window name: %s", name);
|
||||
free(name);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
|
||||
window_set_name(wl->window, name, WINDOW_NAME_FORBID);
|
||||
window_set_name(wl->window, name, 0);
|
||||
options_set_number(wl->window->options, "automatic-rename", 0);
|
||||
free(name);
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -63,8 +64,7 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
const char *errstr, *argval;
|
||||
const char flags[4] = { 'U', 'D', 'L', 'R' };
|
||||
char *cause = NULL, flag;
|
||||
u_int opposite = 0;
|
||||
int adjust, x, y, status;
|
||||
int adjust, x, y, status, opposite = 0;
|
||||
long unsigned i;
|
||||
struct grid *gd = wp->base.grid;
|
||||
|
||||
@@ -94,16 +94,15 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
server_unzoom_window(w);
|
||||
|
||||
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) {
|
||||
cmdq_error(item, "width %s", cause);
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
if (window_pane_is_floating(wp)) {
|
||||
layout_resize_floating_pane_to(wp, LAYOUT_LEFTRIGHT, x,
|
||||
&cause);
|
||||
if (cause != NULL) {
|
||||
if (layout_resize_floating_pane_to(wp, LAYOUT_LEFTRIGHT,
|
||||
x, &cause) != 0) {
|
||||
cmdq_error(item, "size %s", cause);
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
@@ -112,7 +111,7 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
layout_resize_pane_to(wp, LAYOUT_LEFTRIGHT, x);
|
||||
}
|
||||
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) {
|
||||
cmdq_error(item, "height %s", cause);
|
||||
free(cause);
|
||||
@@ -130,9 +129,8 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
break;
|
||||
}
|
||||
if (window_pane_is_floating(wp)) {
|
||||
layout_resize_floating_pane_to(wp, LAYOUT_TOPBOTTOM, y,
|
||||
&cause);
|
||||
if (cause != NULL) {
|
||||
if (layout_resize_floating_pane_to(wp, LAYOUT_TOPBOTTOM,
|
||||
y, &cause) != 0) {
|
||||
cmdq_error(item, "size %s", cause);
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
@@ -147,8 +145,12 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
continue;
|
||||
|
||||
argval = args_get(args, flag);
|
||||
if (argval == NULL)
|
||||
argval = "1";
|
||||
if (argval == NULL) {
|
||||
if (args_count(args) == 0)
|
||||
argval = "1";
|
||||
else
|
||||
argval = args_string(args, 0);
|
||||
}
|
||||
|
||||
adjust = strtonum(argval, INT_MIN, INT_MAX, &errstr);
|
||||
if (errstr != NULL) {
|
||||
@@ -164,9 +166,8 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (flag == 'L' || flag == 'U')
|
||||
opposite = 1;
|
||||
|
||||
layout_resize_floating_pane(wp, type, adjust, opposite,
|
||||
&cause);
|
||||
if (cause != NULL) {
|
||||
if (layout_resize_floating_pane(wp, type, adjust,
|
||||
opposite, &cause) != 0) {
|
||||
cmdq_error(item, "adjustment %s", cause);
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
@@ -234,7 +235,7 @@ cmd_resize_pane_mouse_resize_move_floating(struct client *c,
|
||||
struct window_pane *wp;
|
||||
struct layout_cell *lc;
|
||||
int y, ly, x, lx, sx, sy, new_sx, new_sy;
|
||||
int scrollbars, sb_pos, left, right;
|
||||
int left, right;
|
||||
int new_xoff, new_yoff, resizes = 0;
|
||||
|
||||
wp = cmd_mouse_pane(m, NULL, &wl);
|
||||
@@ -246,15 +247,13 @@ cmd_resize_pane_mouse_resize_move_floating(struct client *c,
|
||||
lc = wp->layout_cell;
|
||||
sx = wp->sx;
|
||||
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) {
|
||||
if (window_pane_scrollbar_reserve(wp) &&
|
||||
w->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) {
|
||||
} else if (window_pane_scrollbar_reserve(wp) &&
|
||||
w->sb_pos == PANE_SCROLLBARS_RIGHT) {
|
||||
right += wp->scrollbar_style.width + wp->scrollbar_style.pad;
|
||||
}
|
||||
|
||||
|
||||
@@ -109,6 +109,7 @@ cmd_rotate_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
window_set_active_pane(w, wp, 1);
|
||||
cmd_find_from_winlink_pane(current, wl, wp, 0);
|
||||
window_pop_zoom(w);
|
||||
redraw_invalidate_scene(w);
|
||||
server_redraw_window(w);
|
||||
|
||||
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);
|
||||
const char *typestr = args_get(args, 'T');
|
||||
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 (typestr == NULL) {
|
||||
for (tidx = 0; tidx < PROMPT_NTYPES; tidx++) {
|
||||
for (hidx = 0; hidx < status_prompt_hsize[tidx];
|
||||
hidx++)
|
||||
free(status_prompt_hlist[tidx][hidx]);
|
||||
free(status_prompt_hlist[tidx]);
|
||||
status_prompt_hlist[tidx] = NULL;
|
||||
status_prompt_hsize[tidx] = 0;
|
||||
}
|
||||
for (t = 0; t < PROMPT_NTYPES; t++)
|
||||
prompt_history_clear(t);
|
||||
} else {
|
||||
type = status_prompt_type(typestr);
|
||||
type = prompt_type(typestr);
|
||||
if (type == PROMPT_TYPE_INVALID) {
|
||||
cmdq_error(item, "invalid type: %s", typestr);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
for (hidx = 0; hidx < status_prompt_hsize[type]; hidx++)
|
||||
free(status_prompt_hlist[type][hidx]);
|
||||
free(status_prompt_hlist[type]);
|
||||
status_prompt_hlist[type] = NULL;
|
||||
status_prompt_hsize[type] = 0;
|
||||
prompt_history_clear(type);
|
||||
}
|
||||
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
if (typestr == NULL) {
|
||||
for (tidx = 0; tidx < PROMPT_NTYPES; tidx++) {
|
||||
cmdq_print(item, "History for %s:\n",
|
||||
status_prompt_type_string(tidx));
|
||||
for (hidx = 0; hidx < status_prompt_hsize[tidx];
|
||||
hidx++) {
|
||||
cmdq_print(item, "%d: %s", hidx + 1,
|
||||
status_prompt_hlist[tidx][hidx]);
|
||||
for (t = 0; t < PROMPT_NTYPES; t++) {
|
||||
typestr = prompt_type_string(t);
|
||||
cmdq_print(item, "History for %s:\n", typestr);
|
||||
for (h = 0; h < prompt_history_size(t); h++) {
|
||||
v = prompt_history_get(t, h);
|
||||
cmdq_print(item, "%d: %s", h + 1, v);
|
||||
}
|
||||
cmdq_print(item, "%s", "");
|
||||
}
|
||||
} else {
|
||||
type = status_prompt_type(typestr);
|
||||
type = prompt_type(typestr);
|
||||
if (type == PROMPT_TYPE_INVALID) {
|
||||
cmdq_error(item, "invalid type: %s", typestr);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
cmdq_print(item, "History for %s:\n",
|
||||
status_prompt_type_string(type));
|
||||
for (hidx = 0; hidx < status_prompt_hsize[type]; hidx++) {
|
||||
cmdq_print(item, "%d: %s", hidx + 1,
|
||||
status_prompt_hlist[type][hidx]);
|
||||
cmdq_print(item, "History for %s:\n", prompt_type_string(type));
|
||||
for (h = 0; h < prompt_history_size(type); h++) {
|
||||
v = prompt_history_get(type, h);
|
||||
cmdq_print(item, "%d: %s", h + 1, v);
|
||||
}
|
||||
cmdq_print(item, "%s", "");
|
||||
}
|
||||
|
||||
@@ -40,8 +40,8 @@ const struct cmd_entry cmd_new_pane_entry = {
|
||||
|
||||
.args = { "bB:c:de:EfF:hIkl:Lm:p:PR:s:S:t:T:vWx:X:y:Y:Z", 0, -1, NULL },
|
||||
.usage = "[-bdefhIklPvWZ] [-B border-lines] "
|
||||
"[-c start-directory] [-e environment] "
|
||||
"[-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] "
|
||||
"[-R inactive-border-style] [-T title] [-x width] [-y height] "
|
||||
"[-X x-position] [-Y y-position] " CMD_TARGET_PANE_USAGE " "
|
||||
@@ -87,7 +87,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
int input, empty, is_floating, flags = 0;
|
||||
const char *template, *style, *value;
|
||||
char *cause = NULL, *cp, *title;
|
||||
struct options_entry *oe;
|
||||
const struct options_table_entry *oe;
|
||||
struct args_value *av;
|
||||
enum pane_lines lines;
|
||||
u_int count = args_count(args);
|
||||
@@ -95,7 +95,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (cmd_get_entry(self) == &cmd_new_pane_entry)
|
||||
is_floating = !args_has(args, 'L');
|
||||
else
|
||||
is_floating = 0;
|
||||
is_floating = window_pane_is_floating(wp);
|
||||
|
||||
flags = is_floating ? SPAWN_FLOATING : 0;
|
||||
if (args_has(args, 'b'))
|
||||
@@ -117,8 +117,20 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (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)
|
||||
lc = layout_get_floating_cell(item, args, w, wp, &cause);
|
||||
lc = layout_get_floating_cell(item, args, lines, w, wp, &cause);
|
||||
else
|
||||
lc = layout_get_tiled_cell(item, args, w, wp, flags, &cause);
|
||||
if (cause != NULL) {
|
||||
@@ -155,10 +167,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if ((new_wp = spawn_pane(&sc, &cause)) == NULL) {
|
||||
cmdq_error(item, "create pane failed: %s", cause);
|
||||
free(cause);
|
||||
if (sc.argv != NULL)
|
||||
cmd_free_argv(sc.argc, sc.argv);
|
||||
environ_free(sc.environ);
|
||||
return (CMD_RETURN_ERROR);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
style = args_get(args, 's');
|
||||
@@ -166,7 +175,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (options_set_string(new_wp->options, "window-style", 0,
|
||||
"%s", style) == NULL) {
|
||||
cmdq_error(item, "bad style: %s", style);
|
||||
return (CMD_RETURN_ERROR);
|
||||
goto fail;
|
||||
}
|
||||
options_set_string(new_wp->options, "window-active-style", 0,
|
||||
"%s", style);
|
||||
@@ -178,7 +187,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (options_set_string(new_wp->options,
|
||||
"pane-active-border-style", 0, "%s", style) == NULL) {
|
||||
cmdq_error(item, "bad active border style: %s", style);
|
||||
return (CMD_RETURN_ERROR);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
style = args_get(args, 'R');
|
||||
@@ -187,22 +196,11 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
"%s", style) == NULL) {
|
||||
cmdq_error(item, "bad inactive border style: %s",
|
||||
style);
|
||||
return (CMD_RETURN_ERROR);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
value = args_get(args, 'B');
|
||||
if (value != NULL) {
|
||||
oe = options_get(new_wp->options, "pane-border-lines");
|
||||
lines = options_find_choice(options_table_entry(oe), value,
|
||||
&cause);
|
||||
if (cause != NULL) {
|
||||
cmdq_error(item, "pane-border-lines %s", cause);
|
||||
free(cause);
|
||||
return (CMD_RETURN_ERROR);
|
||||
}
|
||||
options_set_number(new_wp->options, "pane-border-lines",
|
||||
lines);
|
||||
}
|
||||
if (args_has(args, 'B'))
|
||||
options_set_number(new_wp->options, "pane-border-lines", lines);
|
||||
if (args_has(args, 'k') || args_has(args, 'm')) {
|
||||
options_set_number(new_wp->options, "remain-on-exit", 3);
|
||||
if (args_has(args, 'm')) {
|
||||
@@ -227,10 +225,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
window_remove_pane(wp->window, new_wp);
|
||||
cmdq_error(item, "%s", cause);
|
||||
free(cause);
|
||||
if (sc.argv != NULL)
|
||||
cmd_free_argv(sc.argc, sc.argv);
|
||||
environ_free(sc.environ);
|
||||
return (CMD_RETURN_ERROR);
|
||||
goto fail;
|
||||
case 1:
|
||||
input = 0;
|
||||
break;
|
||||
@@ -272,4 +267,13 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
|
||||
return (CMD_RETURN_WAIT);
|
||||
}
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
@@ -143,9 +143,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(&dst_wp->palette, dst_wp->options);
|
||||
layout_fix_panes(src_w, NULL);
|
||||
redraw_invalidate_scene(src_w);
|
||||
server_redraw_window(src_w);
|
||||
}
|
||||
layout_fix_panes(dst_w, NULL);
|
||||
redraw_invalidate_scene(dst_w);
|
||||
server_redraw_window(dst_w);
|
||||
|
||||
notify_window("window-layout-changed", src_w);
|
||||
|
||||
2
cmd.c
2
cmd.c
@@ -117,6 +117,7 @@ extern const struct cmd_entry cmd_suspend_client_entry;
|
||||
extern const struct cmd_entry cmd_swap_pane_entry;
|
||||
extern const struct cmd_entry cmd_swap_window_entry;
|
||||
extern const struct cmd_entry cmd_switch_client_entry;
|
||||
extern const struct cmd_entry cmd_switch_mode_entry;
|
||||
extern const struct cmd_entry cmd_unbind_key_entry;
|
||||
extern const struct cmd_entry cmd_unlink_window_entry;
|
||||
extern const struct cmd_entry cmd_wait_for_entry;
|
||||
@@ -212,6 +213,7 @@ const struct cmd_entry *cmd_table[] = {
|
||||
&cmd_swap_pane_entry,
|
||||
&cmd_swap_window_entry,
|
||||
&cmd_switch_client_entry,
|
||||
&cmd_switch_mode_entry,
|
||||
&cmd_unbind_key_entry,
|
||||
&cmd_unlink_window_entry,
|
||||
&cmd_wait_for_entry,
|
||||
|
||||
94
colour.c
94
colour.c
@@ -26,6 +26,85 @@
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
/* Theme colour slots and their server options. */
|
||||
static const struct {
|
||||
const char *name;
|
||||
const char *dark_option;
|
||||
const char *light_option;
|
||||
int terminal_colour;
|
||||
} colour_theme_table[] = {
|
||||
{ "themeblack",
|
||||
"dark-theme-black",
|
||||
"light-theme-black",
|
||||
0
|
||||
},
|
||||
{ "themewhite",
|
||||
"dark-theme-white",
|
||||
"light-theme-white",
|
||||
7
|
||||
},
|
||||
{ "themelightgrey",
|
||||
"dark-theme-light-grey",
|
||||
"light-theme-light-grey",
|
||||
7
|
||||
},
|
||||
{ "themedarkgrey",
|
||||
"dark-theme-dark-grey",
|
||||
"light-theme-dark-grey",
|
||||
0
|
||||
},
|
||||
{ "themegreen",
|
||||
"dark-theme-green",
|
||||
"light-theme-green",
|
||||
2
|
||||
},
|
||||
{ "themeyellow",
|
||||
"dark-theme-yellow",
|
||||
"light-theme-yellow",
|
||||
3
|
||||
},
|
||||
{ "themered",
|
||||
"dark-theme-red",
|
||||
"light-theme-red",
|
||||
1
|
||||
},
|
||||
{ "themeblue",
|
||||
"dark-theme-blue",
|
||||
"light-theme-blue",
|
||||
4
|
||||
},
|
||||
{ "themecyan",
|
||||
"dark-theme-cyan",
|
||||
"light-theme-cyan",
|
||||
6
|
||||
},
|
||||
{ "thememagenta",
|
||||
"dark-theme-magenta",
|
||||
"light-theme-magenta",
|
||||
5
|
||||
}
|
||||
};
|
||||
|
||||
/* Get theme colour option. */
|
||||
const char *
|
||||
colour_theme_option(u_int n, enum client_theme theme)
|
||||
{
|
||||
if (n >= nitems(colour_theme_table))
|
||||
return (NULL);
|
||||
if (theme == THEME_LIGHT)
|
||||
return (colour_theme_table[n].light_option);
|
||||
return (colour_theme_table[n].dark_option);
|
||||
}
|
||||
|
||||
/* Get theme terminal colour. */
|
||||
int
|
||||
colour_theme_terminal_colour(u_int n)
|
||||
{
|
||||
if (n >= nitems(colour_theme_table))
|
||||
return (8);
|
||||
return (colour_theme_table[n].terminal_colour);
|
||||
}
|
||||
|
||||
static int
|
||||
colour_dist_sq(int R, int G, int B, int r, int g, int b)
|
||||
{
|
||||
@@ -126,7 +205,7 @@ colour_dim(int c, u_int dim)
|
||||
{
|
||||
u_char r, g, b;
|
||||
|
||||
if (dim == 0 || COLOUR_DEFAULT(c))
|
||||
if (dim == 0 || COLOUR_DEFAULT(c) || (c & COLOUR_FLAG_THEME))
|
||||
return (c);
|
||||
if (dim >= 100)
|
||||
return (colour_join_rgb(0, 0, 0));
|
||||
@@ -152,6 +231,13 @@ colour_tostring(int c)
|
||||
if (c == -1)
|
||||
return ("none");
|
||||
|
||||
if (c & COLOUR_FLAG_THEME) {
|
||||
c &= 0xff;
|
||||
if (c >= 0 && (u_int)c < nitems(colour_theme_table))
|
||||
return (colour_theme_table[c].name);
|
||||
return ("invalid");
|
||||
}
|
||||
|
||||
if (c & COLOUR_FLAG_RGB) {
|
||||
colour_split_rgb(c, &r, &g, &b);
|
||||
xsnprintf(s, sizeof s, "#%02x%02x%02x", r, g, b);
|
||||
@@ -252,6 +338,7 @@ colour_fromstring(const char *s)
|
||||
const char *cp;
|
||||
int n;
|
||||
u_char r, g, b;
|
||||
u_int i;
|
||||
|
||||
if (*s == '#' && strlen(s) == 7) {
|
||||
for (cp = s + 1; isxdigit((u_char) *cp); cp++)
|
||||
@@ -282,6 +369,11 @@ colour_fromstring(const char *s)
|
||||
if (strcasecmp(s, "terminal") == 0)
|
||||
return (9);
|
||||
|
||||
for (i = 0; i < nitems(colour_theme_table); i++) {
|
||||
if (strcasecmp(s, colour_theme_table[i].name) == 0)
|
||||
return (i|COLOUR_FLAG_THEME);
|
||||
}
|
||||
|
||||
if (strcasecmp(s, "black") == 0 || strcmp(s, "0") == 0)
|
||||
return (0);
|
||||
if (strcasecmp(s, "red") == 0 || strcmp(s, "1") == 0)
|
||||
|
||||
@@ -710,6 +710,7 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
|
||||
"AFTER" };
|
||||
size_t size = strlen(expanded);
|
||||
struct screen *os = octx->s, s[TOTAL];
|
||||
struct hyperlinks *hl = os->hyperlinks;
|
||||
struct screen_write_ctx ctx[TOTAL];
|
||||
u_int ocx = os->cx, ocy = os->cy, n, i, width[TOTAL];
|
||||
u_int map[] = { LEFT,
|
||||
@@ -723,7 +724,7 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
|
||||
struct grid_cell gc, current_default, base_default;
|
||||
struct style sy, saved_sy;
|
||||
struct utf8_data *ud = &sy.gc.data;
|
||||
const char *cp, *end;
|
||||
const char *cp, *end, *link_uri;
|
||||
enum utf8_state more;
|
||||
char *tmp;
|
||||
struct format_range *fr = NULL, *fr1;
|
||||
@@ -838,6 +839,17 @@ format_draw(struct screen_write_ctx *octx, const struct grid_cell *base,
|
||||
sy.gc.fg = base->fg;
|
||||
}
|
||||
|
||||
/*
|
||||
* Resolve any hyperlink and store it in the cell. The URI
|
||||
* doubles as the internal ID so repeated links share one entry
|
||||
* and the ID stays stable across redraws.
|
||||
*/
|
||||
link_uri = style_link(&sy);
|
||||
if (link_uri != NULL && hl != NULL)
|
||||
sy.gc.link = hyperlinks_put(hl, link_uri, link_uri);
|
||||
else
|
||||
sy.gc.link = 0;
|
||||
|
||||
/* If this style has a fill colour, store it for later. */
|
||||
if (sy.fill != 8)
|
||||
fill = sy.fill;
|
||||
|
||||
75
format.c
75
format.c
@@ -1477,6 +1477,33 @@ format_cb_client_cell_width(struct format_tree *ft)
|
||||
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. */
|
||||
static void *
|
||||
format_cb_client_control_mode(struct format_tree *ft)
|
||||
@@ -3228,6 +3255,9 @@ static const struct format_table_entry format_table[] = {
|
||||
{ "client_cell_width", FORMAT_TABLE_STRING,
|
||||
format_cb_client_cell_width
|
||||
},
|
||||
{ "client_colours", FORMAT_TABLE_STRING,
|
||||
format_cb_client_colours
|
||||
},
|
||||
{ "client_control_mode", FORMAT_TABLE_STRING,
|
||||
format_cb_client_control_mode
|
||||
},
|
||||
@@ -4542,6 +4572,47 @@ format_build_modifiers(struct format_expand_state *es, const char **s,
|
||||
return (list);
|
||||
}
|
||||
|
||||
/* Match using the fuzzy matcher. */
|
||||
static char *
|
||||
format_match_fuzzy(const char *pattern, const char *text, int positions)
|
||||
{
|
||||
struct evbuffer *buffer;
|
||||
bitstr_t *bs;
|
||||
char *value;
|
||||
size_t size;
|
||||
u_int i, width;
|
||||
|
||||
width = format_width(text);
|
||||
if (width == 0)
|
||||
width = 1;
|
||||
bs = fuzzy_match(pattern, text, width, NULL);
|
||||
if (bs == NULL)
|
||||
return (xstrdup(positions ? "" : "0"));
|
||||
|
||||
if (!positions) {
|
||||
free(bs);
|
||||
return (xstrdup("1"));
|
||||
}
|
||||
|
||||
buffer = evbuffer_new();
|
||||
if (buffer == NULL)
|
||||
fatalx("out of memory");
|
||||
for (i = 0; i < width; i++) {
|
||||
if (!bit_test(bs, i))
|
||||
continue;
|
||||
if (EVBUFFER_LENGTH(buffer) != 0)
|
||||
evbuffer_add(buffer, ",", 1);
|
||||
evbuffer_add_printf(buffer, "%u", i);
|
||||
}
|
||||
if ((size = EVBUFFER_LENGTH(buffer)) != 0)
|
||||
value = xmemdup(EVBUFFER_DATA(buffer), size);
|
||||
else
|
||||
value = xstrdup("");
|
||||
evbuffer_free(buffer);
|
||||
free(bs);
|
||||
return (value);
|
||||
}
|
||||
|
||||
/* Match against an fnmatch(3) pattern or regular expression. */
|
||||
static char *
|
||||
format_match(struct format_modifier *fm, const char *pattern, const char *text)
|
||||
@@ -4552,6 +4623,10 @@ format_match(struct format_modifier *fm, const char *pattern, const char *text)
|
||||
|
||||
if (fm->argc >= 1)
|
||||
s = fm->argv[0];
|
||||
if (strchr(s, 'p') != NULL)
|
||||
return (format_match_fuzzy(pattern, text, 1));
|
||||
if (strchr(s, 'z') != NULL)
|
||||
return (format_match_fuzzy(pattern, text, 0));
|
||||
if (strchr(s, 'r') == NULL) {
|
||||
if (strchr(s, 'i') != NULL)
|
||||
flags |= FNM_CASEFOLD;
|
||||
|
||||
655
fuzzy.c
Normal file
655
fuzzy.c
Normal file
@@ -0,0 +1,655 @@
|
||||
/* $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 <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
/*
|
||||
* Fuzzy matching in the style of fzf. The pattern is split into groups by |
|
||||
* and each group is split on spaces into terms. A row matches if any group
|
||||
* matches; within a group all positive terms must match and all inverse terms
|
||||
* must not match.
|
||||
*
|
||||
* Plain positive terms are fuzzy subsequences. A leading ' makes a term an
|
||||
* exact substring match, ^ anchors a term at the start and $ anchors it at
|
||||
* the end. A leading ! inverts the term. Plain inverse terms are exact
|
||||
* substring matches rather than inverse fuzzy matches, like fzf.
|
||||
*
|
||||
* Both the pattern and the text are UTF-8. The text may contain tmux style
|
||||
* directives (#[...]); these and their contents are invisible to matching and
|
||||
* occupy no columns, but align= styles do move the surrounding text and are
|
||||
* accounted for exactly as format_draw lays it out (the no-list layout, see
|
||||
* format_draw_none). Matching is smart-case: case is ignored unless the pattern
|
||||
* contains an uppercase character (ASCII case folding only; other characters
|
||||
* are compared exactly by their UTF-8 data).
|
||||
*
|
||||
* On a match a bitstr_t of the requested display width is returned with a bit
|
||||
* set for every column occupied by a matched character, so the caller can
|
||||
* highlight them; NULL is returned if there is no match. A cheap fzf-style
|
||||
* score (matches at the start, after word boundaries and in contiguous runs
|
||||
* score higher) is also produced so callers can rank best-match-first.
|
||||
*/
|
||||
|
||||
#define FUZZY_BONUS_EXACT 1000
|
||||
#define FUZZY_BONUS_PREFIX 200
|
||||
#define FUZZY_BONUS_SUFFIX 100
|
||||
#define FUZZY_BONUS_START 12
|
||||
#define FUZZY_BONUS_BOUNDARY 8
|
||||
#define FUZZY_BONUS_CONSECUTIVE 6
|
||||
#define FUZZY_PENALTY_LEADING 1
|
||||
#define FUZZY_PENALTY_LEADING_MAX 10
|
||||
#define FUZZY_PENALTY_GAP 1
|
||||
|
||||
/* A single visible character of the text. */
|
||||
struct fuzzy_char {
|
||||
enum style_align align;
|
||||
struct utf8_data ud; /* original UTF-8 data */
|
||||
u_int width; /* display width */
|
||||
u_int offset; /* within its alignment */
|
||||
};
|
||||
|
||||
/* One parsed query term. */
|
||||
struct fuzzy_term {
|
||||
int inverse;
|
||||
int exact;
|
||||
int prefix;
|
||||
int suffix;
|
||||
const char *text;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
/* Is this character a word boundary, so a match after it scores higher? */
|
||||
static int
|
||||
fuzzy_is_boundary(const struct utf8_data *ud)
|
||||
{
|
||||
static const char *boundary = " -_/.:";
|
||||
|
||||
if (ud->size != 1)
|
||||
return (0);
|
||||
return (strchr(boundary, ud->data[0]) != NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare two characters, folding ASCII case if wanted. UTF-8 is compared
|
||||
* directly without case folding.
|
||||
*/
|
||||
static int
|
||||
fuzzy_char_equal(const struct utf8_data *a, const struct utf8_data *b, int fold)
|
||||
{
|
||||
if (fold &&
|
||||
a->size == 1 &&
|
||||
b->size == 1 &&
|
||||
a->data[0] < 0x80 &&
|
||||
b->data[0] < 0x80)
|
||||
return (tolower(a->data[0]) == tolower(b->data[0]));
|
||||
return (a->size == b->size && memcmp(a->data, b->data, a->size) == 0);
|
||||
}
|
||||
|
||||
/* Map a style alignment onto one of the four layout columns. */
|
||||
static enum style_align
|
||||
fuzzy_align(enum style_align align)
|
||||
{
|
||||
if (align == STYLE_ALIGN_DEFAULT)
|
||||
return (STYLE_ALIGN_LEFT);
|
||||
return (align);
|
||||
}
|
||||
|
||||
/* Add a visible character to the array, updating the alignment width. */
|
||||
static void
|
||||
fuzzy_add(struct fuzzy_char **cs, u_int *ncs, u_int *alloc, enum style_align a,
|
||||
const struct utf8_data *ud, u_int *widths)
|
||||
{
|
||||
struct fuzzy_char *fc;
|
||||
|
||||
if (*ncs == *alloc) {
|
||||
*alloc = (*alloc == 0) ? 64 : *alloc * 2;
|
||||
*cs = xreallocarray(*cs, *alloc, sizeof **cs);
|
||||
}
|
||||
fc = &(*cs)[(*ncs)++];
|
||||
fc->align = a;
|
||||
memcpy(&fc->ud, ud, sizeof fc->ud);
|
||||
fc->width = ud->width;
|
||||
fc->offset = widths[a];
|
||||
widths[a] += ud->width;
|
||||
}
|
||||
|
||||
/* Decode a character as UTF-8. */
|
||||
static const char *
|
||||
fuzzy_decode_one(const char *cp, const char *end, struct utf8_data *ud)
|
||||
{
|
||||
enum utf8_state more;
|
||||
const char *start = cp;
|
||||
|
||||
if ((more = utf8_open(ud, (u_char)*cp)) == UTF8_MORE) {
|
||||
while (++cp != end && more == UTF8_MORE)
|
||||
more = utf8_append(ud, (u_char)*cp);
|
||||
if (more == UTF8_DONE)
|
||||
return (cp);
|
||||
cp = start;
|
||||
}
|
||||
utf8_set(ud, (u_char)*cp);
|
||||
return (cp + 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Scan the text into an array of visible characters, skipping styles and
|
||||
* recording the alignment and intra-alignment offset of each. Returns the
|
||||
* array and its length and fills in the per-alignment widths.
|
||||
*/
|
||||
static struct fuzzy_char *
|
||||
fuzzy_scan(const char *text, u_int *ncs, u_int *widths)
|
||||
{
|
||||
struct fuzzy_char *cs = NULL;
|
||||
u_int alloc = 0, n, leading, i;
|
||||
enum style_align current = STYLE_ALIGN_LEFT;
|
||||
struct style sy;
|
||||
const char *cp = text, *textend = text + strlen(text);
|
||||
const char *end;
|
||||
struct utf8_data ud, hash, bracket;
|
||||
char *tmp;
|
||||
|
||||
*ncs = 0;
|
||||
memset(widths, 0, sizeof *widths * (STYLE_ALIGN_ABSOLUTE_CENTRE + 1));
|
||||
style_set(&sy, &grid_default_cell);
|
||||
utf8_set(&hash, '#');
|
||||
utf8_set(&bracket, '[');
|
||||
|
||||
while (*cp != '\0') {
|
||||
/* Handle a run of #s, which may introduce a style. */
|
||||
if (*cp == '#') {
|
||||
for (n = 0; cp[n] == '#'; n++)
|
||||
/* nothing */;
|
||||
if (cp[n] != '[') {
|
||||
/* Escaped #s: ##->#, so half (rounded up). */
|
||||
leading = (n % 2 == 0) ? n / 2 : n / 2 + 1;
|
||||
for (i = 0; i < leading; i++) {
|
||||
fuzzy_add(&cs, ncs, &alloc, current,
|
||||
&hash, widths);
|
||||
}
|
||||
cp += n;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Even count: all #s escaped, the [ is literal. */
|
||||
for (i = 0; i < n / 2; i++)
|
||||
fuzzy_add(&cs, ncs, &alloc, current, &hash,
|
||||
widths);
|
||||
if (n % 2 == 0) {
|
||||
fuzzy_add(&cs, ncs, &alloc, current, &bracket,
|
||||
widths);
|
||||
cp += n + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Odd count: this is a style, find and parse it. */
|
||||
end = format_skip(cp + n + 1, "]");
|
||||
if (end == NULL)
|
||||
break;
|
||||
tmp = xstrndup(cp + n + 1, end - (cp + n + 1));
|
||||
if (style_parse(&sy, &grid_default_cell, tmp) == 0)
|
||||
current = fuzzy_align(sy.align);
|
||||
free(tmp);
|
||||
cp = end + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Decode one character, multibyte or single byte. */
|
||||
cp = fuzzy_decode_one(cp, textend, &ud);
|
||||
|
||||
/*
|
||||
* Skip non-printable single bytes (control characters and raw
|
||||
* bytes left over from a failed decode); keep printable ASCII
|
||||
* and any decoded UTF-8.
|
||||
*/
|
||||
if (ud.size == 1 && (ud.data[0] <= 0x1f || ud.data[0] >= 0x7f))
|
||||
continue;
|
||||
fuzzy_add(&cs, ncs, &alloc, current, &ud, widths);
|
||||
}
|
||||
return (cs);
|
||||
}
|
||||
|
||||
/*
|
||||
* Work out the display column of a visible character given the trimmed widths
|
||||
* and start columns of each alignment. Returns 0 and sets the column if the
|
||||
* character is visible, otherwise returns -1.
|
||||
*/
|
||||
static int
|
||||
fuzzy_column(const struct fuzzy_char *fc, const u_int *start, const u_int *src,
|
||||
const u_int *vis, u_int *column)
|
||||
{
|
||||
enum style_align a = fc->align;
|
||||
|
||||
if (fc->offset < src[a] || fc->offset >= src[a] + vis[a])
|
||||
return (-1);
|
||||
*column = start[a] + (fc->offset - src[a]);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Decode a UTF-8 term into an array of characters. */
|
||||
static u_int
|
||||
fuzzy_decode(const char *tok, size_t len, struct utf8_data *out)
|
||||
{
|
||||
const char *cp = tok, *end = tok + len;
|
||||
u_int n = 0;
|
||||
|
||||
while (cp != end)
|
||||
cp = fuzzy_decode_one(cp, end, &out[n++]);
|
||||
return (n);
|
||||
}
|
||||
|
||||
/* Add the score for a fuzzy token matched at the given positions. */
|
||||
static int
|
||||
fuzzy_score_positions(const u_int *pos, u_int npos, const struct fuzzy_char *cs)
|
||||
{
|
||||
u_int i, gap, span;
|
||||
int score = 0;
|
||||
|
||||
if (npos == 0)
|
||||
return (0);
|
||||
if (pos[0] == 0)
|
||||
score += FUZZY_BONUS_START;
|
||||
else {
|
||||
if (fuzzy_is_boundary(&cs[pos[0] - 1].ud))
|
||||
score += FUZZY_BONUS_BOUNDARY;
|
||||
if (pos[0] < FUZZY_PENALTY_LEADING_MAX)
|
||||
score -= pos[0] * FUZZY_PENALTY_LEADING;
|
||||
else {
|
||||
score -= FUZZY_PENALTY_LEADING_MAX *
|
||||
FUZZY_PENALTY_LEADING;
|
||||
}
|
||||
}
|
||||
for (i = 1; i < npos; i++) {
|
||||
if (pos[i] == pos[i - 1] + 1)
|
||||
score += FUZZY_BONUS_CONSECUTIVE;
|
||||
else if (fuzzy_is_boundary(&cs[pos[i] - 1].ud))
|
||||
score += FUZZY_BONUS_BOUNDARY;
|
||||
}
|
||||
span = pos[npos - 1] - pos[0] + 1;
|
||||
gap = span - npos;
|
||||
score -= gap * FUZZY_PENALTY_GAP;
|
||||
return (score);
|
||||
}
|
||||
|
||||
/*
|
||||
* Match a token as a subsequence of the visible characters. Returns if the
|
||||
* token matches.
|
||||
*/
|
||||
static int
|
||||
fuzzy_match_fuzzy(const struct utf8_data *tok, u_int toklen,
|
||||
struct fuzzy_char *cs, u_int ncs, int fold, int *score, char *matched)
|
||||
{
|
||||
u_int pi, ci, *pos;
|
||||
int found, value;
|
||||
|
||||
if (toklen == 0 || ncs == 0)
|
||||
return (0);
|
||||
pos = xcalloc(toklen, sizeof *pos);
|
||||
|
||||
/* First find a subsequence from the start. */
|
||||
ci = 0;
|
||||
for (pi = 0; pi < toklen; pi++) {
|
||||
while (ci != ncs &&
|
||||
!fuzzy_char_equal(&tok[pi], &cs[ci].ud, fold))
|
||||
ci++;
|
||||
if (ci == ncs) {
|
||||
free(pos);
|
||||
return (0);
|
||||
}
|
||||
pos[pi] = ci++;
|
||||
}
|
||||
|
||||
/* Then compact it backwards to prefer a shorter span. */
|
||||
ci = pos[toklen - 1];
|
||||
for (pi = toklen; pi > 0; pi--) {
|
||||
found = 0;
|
||||
for (;;) {
|
||||
if (fuzzy_char_equal(&tok[pi - 1], &cs[ci].ud, fold)) {
|
||||
pos[pi - 1] = ci;
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
if (ci == 0)
|
||||
break;
|
||||
ci--;
|
||||
}
|
||||
if (!found) {
|
||||
free(pos);
|
||||
return (0);
|
||||
}
|
||||
if (pi != 1)
|
||||
ci--;
|
||||
}
|
||||
|
||||
value = fuzzy_score_positions(pos, toklen, cs);
|
||||
*score += value;
|
||||
for (pi = 0; pi < toklen; pi++)
|
||||
matched[pos[pi]] = 1;
|
||||
free(pos);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Score an exact, prefix or suffix match. */
|
||||
static int
|
||||
fuzzy_score_exact(u_int start, u_int toklen, u_int ncs,
|
||||
const struct fuzzy_char *cs, int prefix, int suffix)
|
||||
{
|
||||
int score;
|
||||
|
||||
score = FUZZY_BONUS_EXACT + toklen * FUZZY_BONUS_CONSECUTIVE;
|
||||
if (prefix)
|
||||
score += FUZZY_BONUS_PREFIX;
|
||||
if (suffix)
|
||||
score += FUZZY_BONUS_SUFFIX;
|
||||
if (start == 0)
|
||||
score += FUZZY_BONUS_START;
|
||||
else if (fuzzy_is_boundary(&cs[start - 1].ud))
|
||||
score += FUZZY_BONUS_BOUNDARY;
|
||||
if (start < FUZZY_PENALTY_LEADING_MAX)
|
||||
score -= start * FUZZY_PENALTY_LEADING;
|
||||
else
|
||||
score -= FUZZY_PENALTY_LEADING_MAX * FUZZY_PENALTY_LEADING;
|
||||
if (!prefix && !suffix)
|
||||
score -= ncs - (start + toklen);
|
||||
return (score);
|
||||
}
|
||||
|
||||
/* Match an exact, prefix or suffix term against the visible characters. */
|
||||
static int
|
||||
fuzzy_match_exact(const struct utf8_data *tok, u_int toklen,
|
||||
struct fuzzy_char *cs, u_int ncs, int fold, int prefix, int suffix,
|
||||
int *score, char *matched)
|
||||
{
|
||||
u_int start, end, i, j, best = 0;
|
||||
int ok, found = 0, value, bestscore = 0;
|
||||
|
||||
if (toklen == 0 || toklen > ncs)
|
||||
return (0);
|
||||
|
||||
if (prefix && suffix) {
|
||||
if (toklen != ncs)
|
||||
return (0);
|
||||
start = 0;
|
||||
end = 1;
|
||||
} else if (prefix) {
|
||||
start = 0;
|
||||
end = 1;
|
||||
} else if (suffix) {
|
||||
start = ncs - toklen;
|
||||
end = start + 1;
|
||||
} else {
|
||||
start = 0;
|
||||
end = ncs - toklen + 1;
|
||||
}
|
||||
|
||||
for (i = start; i < end; i++) {
|
||||
ok = 1;
|
||||
for (j = 0; j < toklen; j++) {
|
||||
if (!fuzzy_char_equal(&tok[j], &cs[i + j].ud, fold)) {
|
||||
ok = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ok)
|
||||
continue;
|
||||
value = fuzzy_score_exact(i, toklen, ncs, cs, prefix, suffix);
|
||||
if (!found || value > bestscore) {
|
||||
found = 1;
|
||||
best = i;
|
||||
bestscore = value;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
return (0);
|
||||
*score += bestscore;
|
||||
if (matched != NULL) {
|
||||
for (i = 0; i < toklen; i++)
|
||||
matched[best + i] = 1;
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Parse one term. */
|
||||
static int
|
||||
fuzzy_parse_term(const char *start, const char *end, struct fuzzy_term *term)
|
||||
{
|
||||
memset(term, 0, sizeof *term);
|
||||
if (start == end)
|
||||
return (0);
|
||||
if (*start == '!') {
|
||||
term->inverse = 1;
|
||||
start++;
|
||||
}
|
||||
if (start == end)
|
||||
return (0);
|
||||
if (*start == '\'') {
|
||||
term->exact = 1;
|
||||
start++;
|
||||
} else if (*start == '^') {
|
||||
term->exact = 1;
|
||||
term->prefix = 1;
|
||||
start++;
|
||||
}
|
||||
if (start == end)
|
||||
return (0);
|
||||
if (end[-1] == '$') {
|
||||
term->exact = 1;
|
||||
term->suffix = 1;
|
||||
end--;
|
||||
}
|
||||
if (start == end)
|
||||
return (0);
|
||||
|
||||
if (term->inverse)
|
||||
term->exact = 1;
|
||||
term->text = start;
|
||||
term->len = end - start;
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Match one parsed term. */
|
||||
static int
|
||||
fuzzy_match_term(const struct fuzzy_term *term, struct utf8_data *tok,
|
||||
struct fuzzy_char *cs, u_int ncs, int fold, int *score, char *matched)
|
||||
{
|
||||
u_int toklen;
|
||||
int value = 0, matched_term;
|
||||
|
||||
toklen = fuzzy_decode(term->text, term->len, tok);
|
||||
if (term->exact) {
|
||||
matched_term = fuzzy_match_exact(tok, toklen, cs, ncs, fold,
|
||||
term->prefix, term->suffix, &value,
|
||||
term->inverse ? NULL : matched);
|
||||
} else {
|
||||
matched_term = fuzzy_match_fuzzy(tok, toklen, cs, ncs, fold,
|
||||
&value, term->inverse ? NULL : matched);
|
||||
}
|
||||
|
||||
if (term->inverse)
|
||||
return (!matched_term);
|
||||
if (!matched_term)
|
||||
return (0);
|
||||
*score += value;
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Match one AND group of terms. */
|
||||
static int
|
||||
fuzzy_match_group(const char *start, const char *end, struct utf8_data *tok,
|
||||
struct fuzzy_char *cs, u_int ncs, int fold, int *score, char *matched)
|
||||
{
|
||||
const char *cp = start, *sp;
|
||||
struct fuzzy_term term;
|
||||
int any = 0;
|
||||
|
||||
*score = 0;
|
||||
while (cp != end) {
|
||||
while (cp != end && *cp == ' ')
|
||||
cp++;
|
||||
if (cp == end)
|
||||
break;
|
||||
sp = cp;
|
||||
while (cp != end && *cp != ' ')
|
||||
cp++;
|
||||
if (!fuzzy_parse_term(sp, cp, &term))
|
||||
return (0);
|
||||
any = 1;
|
||||
if (!fuzzy_match_term(&term, tok, cs, ncs, fold, score,
|
||||
matched))
|
||||
return (0);
|
||||
}
|
||||
return (any);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fuzzy match pattern against text, which is drawn into a region of the given
|
||||
* display width. Returns a bitstr_t of width bits with a bit set for each
|
||||
* column occupied by a matched character, or NULL if there is no match. A
|
||||
* higher returned score is better.
|
||||
*/
|
||||
bitstr_t *
|
||||
fuzzy_match(const char *pattern, const char *text, u_int width, u_int *score)
|
||||
{
|
||||
struct fuzzy_char *cs;
|
||||
char *matched = NULL, *best = NULL, *groupmatched;
|
||||
struct utf8_data *tok;
|
||||
bitstr_t *mask;
|
||||
u_int ncs, i, j, column;
|
||||
u_int widths[STYLE_ALIGN_ABSOLUTE_CENTRE + 1];
|
||||
u_int start[STYLE_ALIGN_ABSOLUTE_CENTRE + 1];
|
||||
u_int src[STYLE_ALIGN_ABSOLUTE_CENTRE + 1];
|
||||
u_int vis[STYLE_ALIGN_ABSOLUTE_CENTRE + 1];
|
||||
u_int wl, wc, wr, wa;
|
||||
const char *cp, *sp;
|
||||
int bestscore = 0, groupscore, found = 0, fold;
|
||||
|
||||
if (width == 0)
|
||||
return (NULL);
|
||||
|
||||
/* An empty query matches everything, with nothing highlighted. */
|
||||
for (cp = pattern; *cp == ' ' || *cp == '|'; cp++)
|
||||
/* nothing */;
|
||||
if (*cp == '\0') {
|
||||
if (score != NULL)
|
||||
*score = 0;
|
||||
return (bit_alloc(width));
|
||||
}
|
||||
|
||||
/* Smart-case: fold unless the pattern has an uppercase character. */
|
||||
fold = 1;
|
||||
for (cp = pattern; *cp != '\0'; cp++) {
|
||||
if (*cp >= 'A' && *cp <= 'Z') {
|
||||
fold = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Scan the text into visible characters. */
|
||||
cs = fuzzy_scan(text, &ncs, widths);
|
||||
matched = xcalloc(ncs == 0 ? 1 : ncs, sizeof *matched);
|
||||
best = xcalloc(ncs == 0 ? 1 : ncs, sizeof *best);
|
||||
tok = xreallocarray(NULL, strlen(pattern) + 1, sizeof *tok);
|
||||
|
||||
/* Match each |-separated group and keep the best-scoring one. */
|
||||
cp = pattern;
|
||||
while (*cp != '\0') {
|
||||
while (*cp == ' ' || *cp == '|')
|
||||
cp++;
|
||||
if (*cp == '\0')
|
||||
break;
|
||||
sp = cp;
|
||||
while (*cp != '\0' && *cp != '|')
|
||||
cp++;
|
||||
memset(matched, 0, ncs == 0 ? 1 : ncs);
|
||||
groupmatched = matched;
|
||||
if (fuzzy_match_group(sp, cp, tok, cs, ncs, fold,
|
||||
&groupscore, groupmatched)) {
|
||||
if (!found || groupscore > bestscore) {
|
||||
found = 1;
|
||||
bestscore = groupscore;
|
||||
memcpy(best, matched, ncs == 0 ? 1 : ncs);
|
||||
}
|
||||
}
|
||||
}
|
||||
free(tok);
|
||||
if (!found) {
|
||||
free(best);
|
||||
free(matched);
|
||||
free(cs);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Work out the trimmed widths and start columns of each alignment,
|
||||
* mirroring format_draw_none.
|
||||
*/
|
||||
wl = widths[STYLE_ALIGN_LEFT];
|
||||
wc = widths[STYLE_ALIGN_CENTRE];
|
||||
wr = widths[STYLE_ALIGN_RIGHT];
|
||||
wa = widths[STYLE_ALIGN_ABSOLUTE_CENTRE];
|
||||
while (wl + wc + wr > width) {
|
||||
if (wc > 0)
|
||||
wc--;
|
||||
else if (wr > 0)
|
||||
wr--;
|
||||
else
|
||||
wl--;
|
||||
}
|
||||
if (wa > width)
|
||||
wa = width;
|
||||
|
||||
start[STYLE_ALIGN_LEFT] = 0;
|
||||
src[STYLE_ALIGN_LEFT] = 0;
|
||||
vis[STYLE_ALIGN_LEFT] = wl;
|
||||
|
||||
start[STYLE_ALIGN_RIGHT] = width - wr;
|
||||
src[STYLE_ALIGN_RIGHT] = widths[STYLE_ALIGN_RIGHT] - wr;
|
||||
vis[STYLE_ALIGN_RIGHT] = wr;
|
||||
|
||||
start[STYLE_ALIGN_CENTRE] =
|
||||
wl + ((width - wr) - wl) / 2 - wc / 2;
|
||||
src[STYLE_ALIGN_CENTRE] = widths[STYLE_ALIGN_CENTRE] / 2 - wc / 2;
|
||||
vis[STYLE_ALIGN_CENTRE] = wc;
|
||||
|
||||
start[STYLE_ALIGN_ABSOLUTE_CENTRE] = (width - wa) / 2;
|
||||
src[STYLE_ALIGN_ABSOLUTE_CENTRE] = 0;
|
||||
vis[STYLE_ALIGN_ABSOLUTE_CENTRE] = wa;
|
||||
|
||||
/* Set a bit for each column of each matched character. */
|
||||
mask = bit_alloc(width);
|
||||
for (i = 0; i < ncs; i++) {
|
||||
if (!best[i])
|
||||
continue;
|
||||
if (fuzzy_column(&cs[i], start, src, vis, &column) != 0)
|
||||
continue;
|
||||
for (j = 0; j < cs[i].width && column + j < width; j++)
|
||||
bit_set(mask, column + j);
|
||||
}
|
||||
|
||||
free(best);
|
||||
free(matched);
|
||||
free(cs);
|
||||
|
||||
if (score != NULL)
|
||||
*score = (bestscore < 0) ? 0 : (u_int)bestscore;
|
||||
return (mask);
|
||||
}
|
||||
84
grid.c
84
grid.c
@@ -18,6 +18,9 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <assert.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -56,6 +59,28 @@ static const struct grid_cell_entry grid_cleared_entry = {
|
||||
{ .data = { 0, 8, 8, ' ' } }, GRID_FLAG_CLEARED
|
||||
};
|
||||
|
||||
#ifdef __APPLE__
|
||||
static void
|
||||
grid_check_lines(struct grid *gd)
|
||||
{
|
||||
u_int i, j;
|
||||
|
||||
for (i = 0; i < gd->hsize + gd->sy; i++) {
|
||||
for (j = i + 1; j < gd->hsize + gd->sy; j++) {
|
||||
if (gd->linedata[i].celldata != NULL)
|
||||
assert(gd->linedata[i].celldata != gd->linedata[j].celldata);
|
||||
if (gd->linedata[i].extddata != NULL)
|
||||
assert(gd->linedata[i].extddata != gd->linedata[j].extddata);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
static void
|
||||
grid_check_lines(__unused struct grid *gd)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Store cell in entry. */
|
||||
static void
|
||||
grid_store_cell(struct grid_cell_entry *gce, const struct grid_cell *gc,
|
||||
@@ -86,7 +111,8 @@ grid_need_extended_cell(const struct grid_cell_entry *gce,
|
||||
return (1);
|
||||
if (gc->data.size > 1 || gc->data.width > 1)
|
||||
return (1);
|
||||
if ((gc->fg & COLOUR_FLAG_RGB) || (gc->bg & COLOUR_FLAG_RGB))
|
||||
if ((gc->fg & (COLOUR_FLAG_RGB|COLOUR_FLAG_THEME)) ||
|
||||
(gc->bg & (COLOUR_FLAG_RGB|COLOUR_FLAG_THEME)))
|
||||
return (1);
|
||||
if (gc->us != 8) /* only supports 256 or RGB */
|
||||
return (1);
|
||||
@@ -218,7 +244,7 @@ grid_clear_cell(struct grid *gd, u_int px, u_int py, u_int bg, int moved)
|
||||
if (bg != 8)
|
||||
gee->bg = bg;
|
||||
} else if (bg != 8) {
|
||||
if (bg & COLOUR_FLAG_RGB) {
|
||||
if (bg & (COLOUR_FLAG_RGB|COLOUR_FLAG_THEME)) {
|
||||
grid_get_extended_cell(gl, gce, gce->flags);
|
||||
gee = grid_extended_cell(gl, gce, &grid_cleared_cell);
|
||||
gee->bg = bg;
|
||||
@@ -286,9 +312,17 @@ grid_set_tab(struct grid_cell *gc, u_int width)
|
||||
static void
|
||||
grid_free_line(struct grid *gd, u_int py)
|
||||
{
|
||||
free(gd->linedata[py].celldata);
|
||||
free(gd->linedata[py].extddata);
|
||||
memset(&gd->linedata[py], 0, sizeof gd->linedata[py]);
|
||||
struct grid_line *gl = &gd->linedata[py];
|
||||
|
||||
#ifdef __APPLE__
|
||||
assert(gl->cellused <= gl->cellsize);
|
||||
assert(gl->extdsize == 0 || gl->extddata != NULL);
|
||||
assert(gl->cellsize == 0 || gl->celldata != NULL);
|
||||
#endif
|
||||
|
||||
free(gl->celldata);
|
||||
free(gl->extddata);
|
||||
memset(gl, 0, sizeof *gl);
|
||||
}
|
||||
|
||||
/* Free several lines. */
|
||||
@@ -448,6 +482,8 @@ grid_scroll_history(struct grid *gd, u_int bg)
|
||||
gd->linedata[gd->hsize].time = current_time;
|
||||
gd->hsize++;
|
||||
gd->scroll_added++;
|
||||
|
||||
grid_check_lines(gd);
|
||||
}
|
||||
|
||||
/* Clear the history. */
|
||||
@@ -497,6 +533,8 @@ grid_scroll_history_region(struct grid *gd, u_int upper, u_int lower, u_int bg)
|
||||
gd->hscrolled++;
|
||||
gd->hsize++;
|
||||
gd->scroll_added++;
|
||||
|
||||
grid_check_lines(gd);
|
||||
}
|
||||
|
||||
/* Expand line to fit to cell. */
|
||||
@@ -758,6 +796,8 @@ grid_move_lines(struct grid *gd, u_int dy, u_int py, u_int ny, u_int bg)
|
||||
}
|
||||
if (py != 0 && (py < dy || py >= dy + ny))
|
||||
gd->linedata[py - 1].flags &= ~GRID_LINE_WRAPPED;
|
||||
|
||||
grid_check_lines(gd);
|
||||
}
|
||||
|
||||
/* Move a group of cells. */
|
||||
@@ -796,9 +836,16 @@ grid_string_cells_fg(const struct grid_cell *gc, int *values)
|
||||
{
|
||||
size_t n;
|
||||
u_char r, g, b;
|
||||
int c;
|
||||
|
||||
n = 0;
|
||||
if (gc->fg & COLOUR_FLAG_256) {
|
||||
if (gc->fg & COLOUR_FLAG_THEME) {
|
||||
c = colour_theme_terminal_colour(gc->fg & 0xff);
|
||||
if (c == 8)
|
||||
values[n++] = 39;
|
||||
else
|
||||
values[n++] = c + 30;
|
||||
} else if (gc->fg & COLOUR_FLAG_256) {
|
||||
values[n++] = 38;
|
||||
values[n++] = 5;
|
||||
values[n++] = gc->fg & 0xff;
|
||||
@@ -845,9 +892,16 @@ grid_string_cells_bg(const struct grid_cell *gc, int *values)
|
||||
{
|
||||
size_t n;
|
||||
u_char r, g, b;
|
||||
int c;
|
||||
|
||||
n = 0;
|
||||
if (gc->bg & COLOUR_FLAG_256) {
|
||||
if (gc->bg & COLOUR_FLAG_THEME) {
|
||||
c = colour_theme_terminal_colour(gc->bg & 0xff);
|
||||
if (c == 8)
|
||||
values[n++] = 49;
|
||||
else
|
||||
values[n++] = c + 40;
|
||||
} else if (gc->bg & COLOUR_FLAG_256) {
|
||||
values[n++] = 48;
|
||||
values[n++] = 5;
|
||||
values[n++] = gc->bg & 0xff;
|
||||
@@ -894,9 +948,19 @@ grid_string_cells_us(const struct grid_cell *gc, int *values)
|
||||
{
|
||||
size_t n;
|
||||
u_char r, g, b;
|
||||
int c;
|
||||
|
||||
n = 0;
|
||||
if (gc->us & COLOUR_FLAG_256) {
|
||||
if (gc->us & COLOUR_FLAG_THEME) {
|
||||
c = colour_theme_terminal_colour(gc->us & 0xff);
|
||||
if (c == 8)
|
||||
values[n++] = 59;
|
||||
else {
|
||||
values[n++] = 58;
|
||||
values[n++] = 5;
|
||||
values[n++] = c;
|
||||
}
|
||||
} else if (gc->us & COLOUR_FLAG_256) {
|
||||
values[n++] = 58;
|
||||
values[n++] = 5;
|
||||
values[n++] = gc->us & 0xff;
|
||||
@@ -1223,6 +1287,8 @@ grid_duplicate_lines(struct grid *dst, u_int dy, struct grid *src, u_int sy,
|
||||
sy++;
|
||||
dy++;
|
||||
}
|
||||
|
||||
grid_check_lines(dst);
|
||||
}
|
||||
|
||||
/* Mark line as dead. */
|
||||
@@ -1519,6 +1585,8 @@ grid_reflow(struct grid *gd, u_int sx)
|
||||
gd->linedata = target->linedata;
|
||||
free(target);
|
||||
gd->scroll_generation++;
|
||||
|
||||
grid_check_lines(gd);
|
||||
}
|
||||
|
||||
/* Convert to position based on wrapped lines. */
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
*/
|
||||
|
||||
#define MAX_HYPERLINKS 5000
|
||||
#define MAX_HYPERLINK_URI 1024
|
||||
|
||||
static long long hyperlinks_next_external_id = 1;
|
||||
static u_int global_hyperlinks_count;
|
||||
@@ -145,9 +146,13 @@ hyperlinks_put(struct hyperlinks *hl, const char *uri_in,
|
||||
internal_id_in = "";
|
||||
|
||||
utf8_stravis(&uri, uri_in, VIS_OCTAL|VIS_CSTYLE);
|
||||
utf8_stravis(&internal_id, internal_id_in, VIS_OCTAL|VIS_CSTYLE);
|
||||
if (strlen(uri) > MAX_HYPERLINK_URI) {
|
||||
free(uri);
|
||||
return (0);
|
||||
}
|
||||
|
||||
if (*internal_id_in != '\0') {
|
||||
utf8_stravis(&internal_id, internal_id_in, VIS_OCTAL|VIS_CSTYLE);
|
||||
if (*internal_id != '\0') {
|
||||
find.uri = uri;
|
||||
find.internal_id = internal_id;
|
||||
|
||||
|
||||
@@ -586,7 +586,7 @@ sixel_print(struct sixel_image *si, struct sixel_image *map, size_t *size)
|
||||
len = 8192;
|
||||
buf = xmalloc(len);
|
||||
|
||||
tmplen = xsnprintf(tmp, sizeof tmp, "\033P0;%uq", si->p2);
|
||||
tmplen = xsnprintf(tmp, sizeof tmp, "\033P9;%uq", si->p2);
|
||||
sixel_print_add(&buf, &len, &used, tmp, tmplen);
|
||||
|
||||
if (si->set_ra) {
|
||||
|
||||
14
input.c
14
input.c
@@ -1953,16 +1953,14 @@ input_csi_dispatch_rm_private(struct input_ctx *ictx)
|
||||
case 2004:
|
||||
screen_write_mode_clear(sctx, MODE_BRACKETPASTE);
|
||||
break;
|
||||
case 2026:
|
||||
screen_write_stop_sync(ictx->wp);
|
||||
break;
|
||||
case 2031:
|
||||
screen_write_mode_clear(sctx, MODE_THEME_UPDATES);
|
||||
if (ictx->wp != NULL)
|
||||
ictx->wp->flags &= ~PANE_THEMECHANGED;
|
||||
break;
|
||||
case 2026: /* synchronized output */
|
||||
screen_write_stop_sync(ictx->wp);
|
||||
if (ictx->wp != NULL)
|
||||
ictx->wp->flags |= PANE_REDRAW;
|
||||
break;
|
||||
default:
|
||||
log_debug("%s: unknown '%c'", __func__, ictx->ch);
|
||||
break;
|
||||
@@ -2065,7 +2063,7 @@ input_csi_dispatch_sm_private(struct input_ctx *ictx)
|
||||
ictx->wp->flags &= ~PANE_THEMECHANGED;
|
||||
}
|
||||
break;
|
||||
case 2026: /* synchronized output */
|
||||
case 2026:
|
||||
screen_write_start_sync(ictx->wp);
|
||||
break;
|
||||
default:
|
||||
@@ -2822,10 +2820,10 @@ input_exit_rename(struct input_ctx *ictx)
|
||||
if (o != NULL)
|
||||
options_remove_or_default(o, -1, NULL);
|
||||
if (!options_get_number(w->options, "automatic-rename"))
|
||||
window_set_name(w, "", WINDOW_NAME_FORBID_EXT);
|
||||
window_set_name(w, "", 1);
|
||||
} else {
|
||||
options_set_number(w->options, "automatic-rename", 0);
|
||||
window_set_name(w, ictx->input_buf, WINDOW_NAME_FORBID_EXT);
|
||||
window_set_name(w, ictx->input_buf, 1);
|
||||
}
|
||||
server_redraw_window_borders(w);
|
||||
server_status_window(w);
|
||||
|
||||
@@ -405,6 +405,8 @@ key_bindings_init(void)
|
||||
"bind -N 'Redraw the current client' r { refresh-client }",
|
||||
"bind -N 'Choose a session from a list' s { choose-tree -Zs }",
|
||||
"bind -N 'Show a clock' t { clock-mode }",
|
||||
"bind -N 'Switch to a window' Tab { new-pane -E -x75% -y30% -X0 -Y0; move-pane -P bottom-centre; switch-mode -wk }",
|
||||
"bind -N 'Switch to a session' BTab { new-pane -E -x75% -y30% -X0 -Y0; move-pane -P bottom-centre; switch-mode -sk }",
|
||||
"bind -N 'Choose a window from a list' w { choose-tree -Zw }",
|
||||
"bind -N 'Kill the active pane' x { confirm-before -p\"kill-pane #P? (y/n)\" kill-pane }",
|
||||
"bind -N 'Zoom the active pane' z { resize-pane -Z }",
|
||||
@@ -517,8 +519,8 @@ key_bindings_init(void)
|
||||
"bind -Tcopy-mode M-l { send -X cursor-centre-horizontal }",
|
||||
"bind -Tcopy-mode C-n { send -X cursor-down }",
|
||||
"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-s { command-prompt -T search -ip'(search down)' -I'#{pane_search_string}' { send -X search-forward-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 -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-w { send -X copy-pipe-and-cancel }",
|
||||
"bind -Tcopy-mode Escape { send -X cancel }",
|
||||
@@ -526,18 +528,18 @@ key_bindings_init(void)
|
||||
"bind -Tcopy-mode Space { send -X page-down }",
|
||||
"bind -Tcopy-mode , { send -X jump-reverse }",
|
||||
"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 P { send -X toggle-position }",
|
||||
"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 f { command-prompt -1p'(jump forward)' { send -X jump-forward -- '%%' } }",
|
||||
"bind -Tcopy-mode g { command-prompt -p'(goto line)' { send -X goto-line -- '%%' } }",
|
||||
"bind -Tcopy-mode f { command-prompt -P -1p'(jump forward)' { send -X jump-forward -- '%%' } }",
|
||||
"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 q { send -X cancel }",
|
||||
"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 End { send -X end-of-line }",
|
||||
"bind -Tcopy-mode MouseDown1Pane select-pane",
|
||||
@@ -553,15 +555,15 @@ key_bindings_init(void)
|
||||
"bind -Tcopy-mode Down { send -X cursor-down }",
|
||||
"bind -Tcopy-mode Left { send -X cursor-left }",
|
||||
"bind -Tcopy-mode Right { send -X cursor-right }",
|
||||
"bind -Tcopy-mode M-1 { command-prompt -Np'(repeat)' -I1 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode M-2 { command-prompt -Np'(repeat)' -I2 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode M-3 { command-prompt -Np'(repeat)' -I3 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode M-4 { command-prompt -Np'(repeat)' -I4 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode M-5 { command-prompt -Np'(repeat)' -I5 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode M-6 { command-prompt -Np'(repeat)' -I6 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode M-7 { command-prompt -Np'(repeat)' -I7 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode M-8 { command-prompt -Np'(repeat)' -I8 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode M-9 { command-prompt -Np'(repeat)' -I9 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode M-1 { command-prompt -P -Np'(repeat)' -I1 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode M-2 { command-prompt -P -Np'(repeat)' -I2 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode M-3 { command-prompt -P -Np'(repeat)' -I3 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode M-4 { command-prompt -P -Np'(repeat)' -I4 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode M-5 { command-prompt -P -Np'(repeat)' -I5 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode M-6 { command-prompt -P -Np'(repeat)' -I6 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode M-7 { command-prompt -P -Np'(repeat)' -I7 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode M-8 { command-prompt -P -Np'(repeat)' -I8 { 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-bottom }",
|
||||
"bind -Tcopy-mode M-R { send -X top-line }",
|
||||
@@ -602,25 +604,25 @@ key_bindings_init(void)
|
||||
"bind -Tcopy-mode-vi Space { send -X begin-selection }",
|
||||
"bind -Tcopy-mode-vi '$' { send -X end-of-line }",
|
||||
"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 1 { command-prompt -Np'(repeat)' -I1 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode-vi 2 { command-prompt -Np'(repeat)' -I2 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode-vi 3 { command-prompt -Np'(repeat)' -I3 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode-vi 4 { command-prompt -Np'(repeat)' -I4 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode-vi 5 { command-prompt -Np'(repeat)' -I5 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode-vi 6 { command-prompt -Np'(repeat)' -I6 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode-vi 7 { command-prompt -Np'(repeat)' -I7 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode-vi 8 { command-prompt -Np'(repeat)' -I8 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode-vi 9 { command-prompt -Np'(repeat)' -I9 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode-vi : { command-prompt -p'(goto line)' { send -X goto-line -- '%%' } }",
|
||||
"bind -Tcopy-mode-vi 1 { command-prompt -P -Np'(repeat)' -I1 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode-vi 2 { command-prompt -P -Np'(repeat)' -I2 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode-vi 3 { command-prompt -P -Np'(repeat)' -I3 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode-vi 4 { command-prompt -P -Np'(repeat)' -I4 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode-vi 5 { command-prompt -P -Np'(repeat)' -I5 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode-vi 6 { command-prompt -P -Np'(repeat)' -I6 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode-vi 7 { command-prompt -P -Np'(repeat)' -I7 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode-vi 8 { command-prompt -P -Np'(repeat)' -I8 { send -N '%%' } }",
|
||||
"bind -Tcopy-mode-vi 9 { command-prompt -P -Np'(repeat)' -I9 { send -N '%%' } }",
|
||||
"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 ? { 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 B { send -X previous-space }",
|
||||
"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 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 H { send -X top-line }",
|
||||
"bind -Tcopy-mode-vi J { send -X scroll-down }",
|
||||
@@ -629,14 +631,14 @@ key_bindings_init(void)
|
||||
"bind -Tcopy-mode-vi M { send -X middle-line }",
|
||||
"bind -Tcopy-mode-vi N { send -X search-reverse }",
|
||||
"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 W { send -X next-space }",
|
||||
"bind -Tcopy-mode-vi X { send -X set-mark }",
|
||||
"bind -Tcopy-mode-vi ^ { send -X back-to-indentation }",
|
||||
"bind -Tcopy-mode-vi b { send -X previous-word }",
|
||||
"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 h { send -X cursor-left }",
|
||||
"bind -Tcopy-mode-vi j { send -X cursor-down }",
|
||||
@@ -647,7 +649,7 @@ key_bindings_init(void)
|
||||
"bind -Tcopy-mode-vi o { send -X other-end }",
|
||||
"bind -Tcopy-mode-vi q { send -X cancel }",
|
||||
"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 w { send -X next-word }",
|
||||
"bind -Tcopy-mode-vi '{' { send -X previous-paragraph }",
|
||||
|
||||
380
layout.c
380
layout.c
@@ -20,6 +20,7 @@
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
@@ -443,18 +444,22 @@ layout_fix_panes(struct window *w, struct window_pane *skip)
|
||||
{
|
||||
struct window_pane *wp;
|
||||
struct layout_cell *lc;
|
||||
int status, scrollbars, sb_pos, sb_w, sb_pad;
|
||||
u_int sx, sy;
|
||||
int status, sb_w, sb_pad;
|
||||
int old_xoff, old_yoff, changed = 0;
|
||||
u_int sx, sy, old_sx, old_sy;
|
||||
|
||||
status = window_get_pane_status(w);
|
||||
scrollbars = options_get_number(w->options, "pane-scrollbars");
|
||||
sb_pos = options_get_number(w->options, "pane-scrollbars-position");
|
||||
|
||||
TAILQ_FOREACH(wp, &w->panes, entry) {
|
||||
if ((lc = wp->layout_cell) == NULL || wp == skip ||
|
||||
!window_pane_is_visible(wp))
|
||||
continue;
|
||||
|
||||
old_xoff = wp->xoff;
|
||||
old_yoff = wp->yoff;
|
||||
old_sx = wp->sx;
|
||||
old_sy = wp->sy;
|
||||
|
||||
wp->xoff = lc->xoff;
|
||||
wp->yoff = lc->yoff;
|
||||
sx = lc->sx;
|
||||
@@ -467,15 +472,15 @@ layout_fix_panes(struct window *w, struct window_pane *skip)
|
||||
sy--;
|
||||
}
|
||||
|
||||
if (window_pane_show_scrollbar(wp, scrollbars)) {
|
||||
if (window_pane_scrollbar_reserve(wp)) {
|
||||
sb_w = wp->scrollbar_style.width;
|
||||
sb_pad = wp->scrollbar_style.pad;
|
||||
if (sb_w < 1)
|
||||
sb_w = 1;
|
||||
if (sb_pad < 0)
|
||||
sb_pad = 0;
|
||||
if (sb_pos == PANE_SCROLLBARS_LEFT) {
|
||||
if ((int)sx - sb_w < PANE_MINIMUM) {
|
||||
if (w->sb_pos == PANE_SCROLLBARS_LEFT) {
|
||||
if ((int)sx - sb_w - sb_pad < PANE_MINIMUM) {
|
||||
wp->xoff = wp->xoff +
|
||||
(int)sx - PANE_MINIMUM;
|
||||
sx = PANE_MINIMUM;
|
||||
@@ -492,7 +497,15 @@ layout_fix_panes(struct window *w, struct window_pane *skip)
|
||||
}
|
||||
|
||||
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. */
|
||||
@@ -523,16 +536,15 @@ layout_resize_check(struct window *w, struct layout_cell *lc,
|
||||
struct layout_cell *lcchild;
|
||||
struct style *sb_style = &w->active->scrollbar_style;
|
||||
u_int available, minimum;
|
||||
int status, scrollbars;
|
||||
int status;
|
||||
|
||||
status = window_get_pane_status(w);
|
||||
scrollbars = options_get_number(w->options, "pane-scrollbars");
|
||||
|
||||
if (lc->type == LAYOUT_WINDOWPANE) {
|
||||
/* Space available in this cell only. */
|
||||
if (type == LAYOUT_LEFTRIGHT) {
|
||||
available = lc->sx;
|
||||
if (scrollbars)
|
||||
if (w->sb == PANE_SCROLLBARS_ALWAYS)
|
||||
minimum = PANE_MINIMUM + sb_style->width +
|
||||
sb_style->pad;
|
||||
else
|
||||
@@ -858,7 +870,7 @@ layout_resize_pane_to(struct window_pane *wp, enum layout_type type,
|
||||
}
|
||||
|
||||
/* Resize a floating pane to an absolute size. */
|
||||
void
|
||||
int
|
||||
layout_resize_floating_pane_to(struct window_pane *wp, enum layout_type type,
|
||||
u_int size, char **cause)
|
||||
{
|
||||
@@ -866,7 +878,7 @@ layout_resize_floating_pane_to(struct window_pane *wp, enum layout_type type,
|
||||
|
||||
if (~lc->flags & LAYOUT_CELL_FLOATING) {
|
||||
*cause = xstrdup("pane is not floating");
|
||||
return;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (window_pane_get_pane_lines(wp) != PANE_LINES_NONE &&
|
||||
@@ -874,17 +886,24 @@ layout_resize_floating_pane_to(struct window_pane *wp, enum layout_type type,
|
||||
size -= 2;
|
||||
if (size < PANE_MINIMUM || size > PANE_MAXIMUM) {
|
||||
*cause = xstrdup("size is too big or too small");
|
||||
return;
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (type == LAYOUT_TOPBOTTOM)
|
||||
if (type == LAYOUT_TOPBOTTOM) {
|
||||
if (lc->sy == size)
|
||||
return (0);
|
||||
lc->sy = size;
|
||||
else
|
||||
} else {
|
||||
if (lc->sx == size)
|
||||
return (0);
|
||||
lc->sx = size;
|
||||
}
|
||||
redraw_invalidate_scene(wp->window);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Resize a floating pane relative to its current size. */
|
||||
void
|
||||
int
|
||||
layout_resize_floating_pane(struct window_pane *wp, enum layout_type type,
|
||||
int change, int opposite, char **cause)
|
||||
{
|
||||
@@ -893,14 +912,16 @@ layout_resize_floating_pane(struct window_pane *wp, enum layout_type type,
|
||||
|
||||
if (~lc->flags & LAYOUT_CELL_FLOATING) {
|
||||
*cause = xstrdup("pane is not floating");
|
||||
return;
|
||||
return (-1);
|
||||
}
|
||||
if (change == 0)
|
||||
return (0);
|
||||
|
||||
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;
|
||||
return (-1);
|
||||
}
|
||||
lc->sy = size;
|
||||
if (opposite)
|
||||
@@ -909,12 +930,14 @@ layout_resize_floating_pane(struct window_pane *wp, enum layout_type type,
|
||||
size = lc->sx + change;
|
||||
if (size < PANE_MINIMUM || size > PANE_MAXIMUM) {
|
||||
*cause = xstrdup("change is too big or too small");
|
||||
return;
|
||||
return (-1);
|
||||
}
|
||||
lc->sx = size;
|
||||
if (opposite)
|
||||
lc->xoff -= change;
|
||||
}
|
||||
redraw_invalidate_scene(wp->window);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Resize a layout cell. */
|
||||
@@ -1278,6 +1301,100 @@ layout_split_sizes(struct layout_cell *lc, int size, int before,
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Replaces the provided layout cell with a new node of the specified type and
|
||||
* inserts the cell into it. Used when creating new cells requires a different
|
||||
* layout type, or when the root layout is a window pane.
|
||||
*/
|
||||
struct layout_cell *
|
||||
layout_replace_with_node(struct window *w, struct layout_cell *lc,
|
||||
enum layout_type type)
|
||||
{
|
||||
struct layout_cell *lcparent;
|
||||
|
||||
lcparent = layout_create_cell(lc->parent);
|
||||
layout_make_node(lcparent, type);
|
||||
layout_set_size(lcparent, lc->sx, lc->sy, lc->xoff, lc->yoff);
|
||||
if (lc->parent == NULL)
|
||||
w->layout_root = lcparent;
|
||||
else
|
||||
TAILQ_REPLACE(&lc->parent->cells, lc, lcparent, entry);
|
||||
|
||||
/* Insert the old cell. */
|
||||
lc->parent = lcparent;
|
||||
TAILQ_INSERT_HEAD(&lcparent->cells, lc, entry);
|
||||
|
||||
return (lcparent);
|
||||
}
|
||||
|
||||
/* Checks if there is enough space for two new panes. */
|
||||
int
|
||||
layout_split_check_space(struct window_pane *wp, struct layout_cell *lc,
|
||||
enum layout_type type)
|
||||
{
|
||||
struct style *sb_style = &wp->scrollbar_style;
|
||||
u_int minimum, sx = lc->sx, sy = lc->sy;
|
||||
int status;
|
||||
|
||||
if (lc->flags & LAYOUT_CELL_FLOATING)
|
||||
fatalx("floating cells cannot be split");
|
||||
|
||||
status = window_get_pane_status(wp->window);
|
||||
|
||||
switch (type) {
|
||||
case LAYOUT_LEFTRIGHT:
|
||||
if (wp->window->sb == PANE_SCROLLBARS_ALWAYS) {
|
||||
minimum = PANE_MINIMUM * 2 + sb_style->width +
|
||||
sb_style->pad;
|
||||
} else
|
||||
minimum = PANE_MINIMUM * 2 + 1;
|
||||
if (sx < minimum)
|
||||
return (0);
|
||||
break;
|
||||
case LAYOUT_TOPBOTTOM:
|
||||
if (layout_add_horizontal_border(wp->window, lc, status))
|
||||
minimum = PANE_MINIMUM * 2 + 2;
|
||||
else
|
||||
minimum = PANE_MINIMUM * 2 + 1;
|
||||
if (sy < minimum)
|
||||
return (0);
|
||||
break;
|
||||
default:
|
||||
fatalx("bad layout type");
|
||||
}
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Calculates the new cell sizes when splitting a pane. */
|
||||
void
|
||||
layout_split_sizes(struct layout_cell *lc, int size, int before,
|
||||
enum layout_type type, u_int *size1, u_int *size2, u_int *saved_size)
|
||||
{
|
||||
u_int s1, s2, ss;
|
||||
u_int sx = lc->sx, sy = lc->sy;
|
||||
|
||||
if (type == LAYOUT_LEFTRIGHT)
|
||||
ss = sx;
|
||||
else
|
||||
ss = sy;
|
||||
if (size < 0)
|
||||
s2 = ((ss + 1) / 2) - 1;
|
||||
else if (before)
|
||||
s2 = ss - size - 1;
|
||||
else
|
||||
s2 = size;
|
||||
if (s2 < PANE_MINIMUM)
|
||||
s2 = PANE_MINIMUM;
|
||||
else if (s2 > sx - 2)
|
||||
s2 = ss - 2;
|
||||
s1 = ss - 1 - s2;
|
||||
|
||||
*size1 = s1;
|
||||
*size2 = s2;
|
||||
*saved_size = ss;
|
||||
}
|
||||
|
||||
/*
|
||||
* Split a pane into two. size is a hint, or -1 for default half/half
|
||||
* split. This must be followed by layout_assign_pane before much else happens!
|
||||
@@ -1373,17 +1490,7 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
|
||||
*/
|
||||
|
||||
/* Create and insert the replacement parent. */
|
||||
lcparent = layout_create_cell(lc->parent);
|
||||
layout_make_node(lcparent, type);
|
||||
layout_set_size(lcparent, sx, sy, xoff, yoff);
|
||||
if (lc->parent == NULL)
|
||||
wp->window->layout_root = lcparent;
|
||||
else
|
||||
TAILQ_REPLACE(&lc->parent->cells, lc, lcparent, entry);
|
||||
|
||||
/* Insert the old cell. */
|
||||
lc->parent = lcparent;
|
||||
TAILQ_INSERT_HEAD(&lcparent->cells, lc, entry);
|
||||
lcparent = layout_replace_with_node(wp->window, lc, type);
|
||||
|
||||
/* Create the new child cell. */
|
||||
lcnew = layout_create_cell(lcparent);
|
||||
@@ -1442,14 +1549,7 @@ layout_floating_pane(struct window *w, struct window_pane *wp, u_int sx,
|
||||
* Adding a pane to a root that isn't node. Must create and
|
||||
* insert a new root.
|
||||
*/
|
||||
lcparent = layout_create_cell(NULL);
|
||||
layout_make_node(lcparent, LAYOUT_TOPBOTTOM);
|
||||
layout_set_size(lcparent, w->sx, w->sy, 0, 0);
|
||||
w->layout_root = lcparent;
|
||||
|
||||
/* Insert the old cell. */
|
||||
lc->parent = lcparent;
|
||||
TAILQ_INSERT_HEAD(&lcparent->cells, lc, entry);
|
||||
lcparent = layout_replace_with_node(w, lc, LAYOUT_TOPBOTTOM);
|
||||
}
|
||||
|
||||
lcnew = layout_create_cell(lcparent);
|
||||
@@ -1574,6 +1674,7 @@ layout_get_tiled_cell(struct cmdq_item *item, struct args *args,
|
||||
enum layout_type type;
|
||||
u_int curval;
|
||||
int size = -1;
|
||||
char *error = NULL;
|
||||
|
||||
if (window_pane_is_floating(wp)) {
|
||||
*cause = xstrdup("can't split a floating pane");
|
||||
@@ -1600,15 +1701,16 @@ layout_get_tiled_cell(struct cmdq_item *item, struct args *args,
|
||||
|
||||
if (args_has(args, 'l')) {
|
||||
size = args_percentage_and_expand(args, 'l', 0, INT_MAX, curval,
|
||||
item, cause);
|
||||
item, &error);
|
||||
} else if (args_has(args, 'p')) {
|
||||
size = args_strtonum_and_expand(args, 'p', 0, 100, item,
|
||||
cause);
|
||||
if (*cause == NULL)
|
||||
&error);
|
||||
if (error == NULL)
|
||||
size = curval * size / 100;
|
||||
}
|
||||
if (*cause != NULL) {
|
||||
*cause = xstrdup("invalid tiled geometry");
|
||||
if (error != NULL) {
|
||||
xasprintf(cause, "invalid tiled geometry %s", error);
|
||||
free(error);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
@@ -1625,11 +1727,30 @@ layout_get_tiled_cell(struct cmdq_item *item, struct args *args,
|
||||
return (lc);
|
||||
}
|
||||
|
||||
void
|
||||
layout_cell_floating_args_parse(struct cmdq_item *item, struct args *args,
|
||||
struct window *w, u_int *sxp, u_int *syp, int *oxp, int *oyp, char **cause)
|
||||
struct layout_cell *
|
||||
layout_get_floating_cell(struct cmdq_item *item, struct args *args,
|
||||
enum pane_lines lines, struct window *w, struct window_pane *wp,
|
||||
char **cause)
|
||||
{
|
||||
int sx, sy, ox, oy;
|
||||
struct layout_cell *lcnew;
|
||||
u_int sx = UINT_MAX, sy = UINT_MAX;
|
||||
int ox = INT_MAX, oy = INT_MAX;
|
||||
|
||||
if (layout_floating_args_parse(item, args, lines, w, &sx, &sy, &ox, &oy,
|
||||
cause) != 0)
|
||||
return (NULL);
|
||||
|
||||
lcnew = layout_floating_pane(w, wp, sx, sy, ox, oy);
|
||||
return (lcnew);
|
||||
}
|
||||
|
||||
int
|
||||
layout_floating_args_parse(struct cmdq_item *item, struct args *args,
|
||||
enum pane_lines lines, struct window *w, u_int *sxp, u_int *syp, int *oxp,
|
||||
int *oyp, char **cause)
|
||||
{
|
||||
int sx, sy, ox, oy;
|
||||
char *error = NULL;
|
||||
|
||||
sx = *sxp == UINT_MAX ? w->sx / 2 : *sxp;
|
||||
sy = *syp == UINT_MAX ? w->sy / 4 : *syp;
|
||||
@@ -1637,28 +1758,44 @@ layout_cell_floating_args_parse(struct cmdq_item *item, struct args *args,
|
||||
oy = *oyp == INT_MAX ? INT_MAX : *oyp;
|
||||
|
||||
if (args_has(args, 'x')) {
|
||||
sx = args_percentage_and_expand(args, 'x', 0, w->sx - 1, w->sx,
|
||||
item, cause);
|
||||
if (*cause != NULL)
|
||||
return;
|
||||
sx = args_percentage_and_expand(args, 'x', 0, PANE_MAXIMUM,
|
||||
w->sx, item, &error);
|
||||
if (error != NULL) {
|
||||
xasprintf(cause, "position %s", error);
|
||||
free(error);
|
||||
return (-1);
|
||||
}
|
||||
if (lines != PANE_LINES_NONE)
|
||||
sx -= 2;
|
||||
}
|
||||
if (args_has(args, 'y')) {
|
||||
sy = args_percentage_and_expand(args, 'y', 0, w->sy - 1, w->sy,
|
||||
item, cause);
|
||||
if (*cause != NULL)
|
||||
return;
|
||||
sy = args_percentage_and_expand(args, 'y', 0, PANE_MAXIMUM,
|
||||
w->sy, item, &error);
|
||||
if (error != NULL) {
|
||||
xasprintf(cause, "position %s", error);
|
||||
free(error);
|
||||
return (-1);
|
||||
}
|
||||
if (lines != PANE_LINES_NONE)
|
||||
sy -= 2;
|
||||
}
|
||||
if (args_has(args, 'X')) {
|
||||
ox = args_percentage_and_expand(args, 'X', -(int)w->sx, w->sx,
|
||||
w->sx, item, cause);
|
||||
if (*cause != NULL)
|
||||
return;
|
||||
ox = args_percentage_and_expand(args, 'X', -sx, w->sx,
|
||||
w->sx, item, &error);
|
||||
if (error != NULL) {
|
||||
xasprintf(cause, "position %s", error);
|
||||
free(error);
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
if (args_has(args, 'Y')) {
|
||||
oy = args_percentage_and_expand(args, 'Y', -(int)w->sy, w->sy,
|
||||
w->sy, item, cause);
|
||||
if (*cause != NULL)
|
||||
return;
|
||||
oy = args_percentage_and_expand(args, 'Y', -sy, w->sy,
|
||||
w->sy, item, &error);
|
||||
if (error != NULL) {
|
||||
xasprintf(cause, "position %s", error);
|
||||
free(error);
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
|
||||
if (ox == INT_MAX) {
|
||||
@@ -1670,7 +1807,9 @@ layout_cell_floating_args_parse(struct cmdq_item *item, struct args *args,
|
||||
ox = 4;
|
||||
}
|
||||
w->last_new_pane_x = ox;
|
||||
}
|
||||
} else
|
||||
if (lines != PANE_LINES_NONE)
|
||||
ox += 1;
|
||||
if (oy == INT_MAX) {
|
||||
if (w->last_new_pane_y == 0)
|
||||
oy = 2;
|
||||
@@ -1680,39 +1819,24 @@ layout_cell_floating_args_parse(struct cmdq_item *item, struct args *args,
|
||||
oy = 2;
|
||||
}
|
||||
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 (-1);
|
||||
}
|
||||
if (sy < PANE_MINIMUM || sy > PANE_MAXIMUM) {
|
||||
*cause = xstrdup("invalid height");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
*sxp = sx;
|
||||
*syp = sy;
|
||||
*oxp = ox;
|
||||
*oyp = oy;
|
||||
}
|
||||
|
||||
/* Get a new floating cell. */
|
||||
struct layout_cell *
|
||||
layout_get_floating_cell(struct cmdq_item *item, struct args *args,
|
||||
struct window *w, struct window_pane *wp, char **cause)
|
||||
{
|
||||
struct layout_cell *lcnew;
|
||||
u_int sx = UINT_MAX, sy = UINT_MAX;
|
||||
int ox = INT_MAX, oy = INT_MAX;
|
||||
|
||||
layout_cell_floating_args_parse(item, args, w, &sx, &sy, &ox, &oy,
|
||||
cause);
|
||||
if (*cause != NULL) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
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, wp, sx, sy, ox, oy);
|
||||
return (lcnew);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1746,8 +1870,76 @@ layout_remove_tile(struct window *w, struct layout_cell *lc)
|
||||
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);
|
||||
/*
|
||||
* Zeroing out the cell geometry until the cell is retiled unless this
|
||||
* is the top level node.
|
||||
*/
|
||||
if (lc->parent != NULL)
|
||||
layout_set_size(lc, 0, 0, 0, 0);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Inserts a cell back into the tiled layout by taking half the space from its
|
||||
* nearest neighbour.
|
||||
*/
|
||||
int
|
||||
layout_insert_tile(struct window *w, struct layout_cell *lc)
|
||||
{
|
||||
struct layout_cell *lcneighbour, *lctiled, *lcparent;
|
||||
enum layout_type type;
|
||||
u_int size1, size2, saved_size;
|
||||
|
||||
if (lc == NULL)
|
||||
fatalx("layout cell cannot be null when tiling");
|
||||
|
||||
lcparent = lc->parent;
|
||||
if (lc->flags & LAYOUT_CELL_FLOATING)
|
||||
return (1);
|
||||
|
||||
if (lcparent == NULL) {
|
||||
/* Only pane in the layout. */
|
||||
layout_set_size(lc, w->sx, w->sy, 0, 0);
|
||||
return (1);
|
||||
}
|
||||
|
||||
type = lcparent->type;
|
||||
lcneighbour = layout_cell_get_neighbour(lc);
|
||||
if (lcneighbour == NULL) {
|
||||
/*
|
||||
* This will become the only visible cell in the parent.
|
||||
* Tile the parent, then set the child's 'split' size.
|
||||
*/
|
||||
layout_insert_tile(w, lcparent);
|
||||
if (type == LAYOUT_LEFTRIGHT)
|
||||
size1 = lcparent->sx;
|
||||
else
|
||||
size1 = lcparent->sy;
|
||||
layout_resize_set_size(w, lc, type, size1);
|
||||
} else {
|
||||
/*
|
||||
* If the neighbour is a node, a tiled child in the subtree of
|
||||
* the neighbour is needed to check for space.
|
||||
*/
|
||||
lctiled = layout_cell_get_first_tiled(lcneighbour);
|
||||
if (!layout_split_check_space(lctiled->wp, lcneighbour, type))
|
||||
return (0);
|
||||
layout_split_sizes(lcneighbour, -1, 0, type, &size1, &size2,
|
||||
&saved_size);
|
||||
layout_resize_set_size(w, lc, type, size1);
|
||||
layout_resize_set_size(w, lcneighbour, type, size2);
|
||||
}
|
||||
|
||||
/* Setting opposite of the 'split' size to that of the parent. */
|
||||
if (lcparent->type == LAYOUT_LEFTRIGHT) {
|
||||
size1 = lcparent->sy;
|
||||
type = LAYOUT_TOPBOTTOM;
|
||||
} else {
|
||||
size1 = lcparent->sx;
|
||||
type = LAYOUT_LEFTRIGHT;
|
||||
}
|
||||
layout_resize_set_size(w, lc, type, size1);
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
|
||||
7
menu.c
7
menu.c
@@ -257,8 +257,7 @@ menu_reapply_styles(struct menu_data *md, struct client *c)
|
||||
}
|
||||
|
||||
void
|
||||
menu_draw_cb(struct client *c, void *data,
|
||||
__unused struct screen_redraw_ctx *rctx)
|
||||
menu_draw_cb(struct client *c, void *data)
|
||||
{
|
||||
struct menu_data *md = data;
|
||||
struct tty *tty = &c->tty;
|
||||
@@ -636,7 +635,7 @@ menu_display(struct menu *menu, int flags, int starting_choice,
|
||||
style, selected_style, border_style, fs, cb, data);
|
||||
if (md == NULL)
|
||||
return (-1);
|
||||
server_client_set_overlay(c, 0, NULL, menu_mode_cb, menu_draw_cb,
|
||||
menu_key_cb, menu_free_cb, menu_resize_cb, md);
|
||||
server_client_set_overlay(c, 0, menu_check_cb, menu_mode_cb,
|
||||
menu_draw_cb, menu_key_cb, menu_free_cb, menu_resize_cb, md);
|
||||
return (0);
|
||||
}
|
||||
|
||||
585
mode-tree.c
585
mode-tree.c
@@ -36,7 +36,26 @@ enum mode_tree_preview {
|
||||
MODE_TREE_PREVIEW_BIG
|
||||
};
|
||||
|
||||
#define MODE_TREE_PREFIX_STYLE \
|
||||
"#{?mode_tree_selected,#[default]#[noacs]," \
|
||||
"#[fg=themelightgrey]#[bg=default]#[noacs]}"
|
||||
|
||||
#define MODE_TREE_PREFIX_FORMAT \
|
||||
MODE_TREE_PREFIX_STYLE \
|
||||
"#{p/#{mode_tree_key_width}:" \
|
||||
"#{?#{!=:#{mode_tree_key},},(#{mode_tree_key}),}}" \
|
||||
"#{R:#{?mode_tree_parent_last, ," \
|
||||
"#[acs]x" MODE_TREE_PREFIX_STYLE " }," \
|
||||
"#{mode_tree_repeat}}" \
|
||||
"#{?mode_tree_branch," \
|
||||
"#[acs]#{?mode_tree_last,mq,tq}" MODE_TREE_PREFIX_STYLE "> ,}" \
|
||||
"#{?mode_tree_has_children," \
|
||||
"#{?mode_tree_expanded,#[fg=themered]-" MODE_TREE_PREFIX_STYLE " ," \
|
||||
"#[fg=themegreen]+" MODE_TREE_PREFIX_STYLE " }," \
|
||||
"#{?mode_tree_flat,, }}"
|
||||
|
||||
struct mode_tree_item;
|
||||
struct mode_tree_prompt;
|
||||
TAILQ_HEAD(mode_tree_list, mode_tree_item);
|
||||
|
||||
struct mode_tree_data {
|
||||
@@ -51,11 +70,11 @@ struct mode_tree_data {
|
||||
struct sort_criteria sort_crit;
|
||||
const char *view_name;
|
||||
|
||||
mode_tree_build_cb buildcb;
|
||||
mode_tree_draw_cb drawcb;
|
||||
mode_tree_search_cb searchcb;
|
||||
mode_tree_menu_cb menucb;
|
||||
mode_tree_height_cb heightcb;
|
||||
mode_tree_build_cb buildcb;
|
||||
mode_tree_draw_cb drawcb;
|
||||
mode_tree_search_cb searchcb;
|
||||
mode_tree_menu_cb menucb;
|
||||
mode_tree_height_cb heightcb;
|
||||
mode_tree_key_cb keycb;
|
||||
mode_tree_swap_cb swapcb;
|
||||
mode_tree_sort_cb sortcb;
|
||||
@@ -77,6 +96,10 @@ struct mode_tree_data {
|
||||
u_int current;
|
||||
|
||||
struct screen screen;
|
||||
struct prompt *prompt;
|
||||
struct mode_tree_prompt *prompt_data;
|
||||
u_int prompt_cx;
|
||||
int prompt_top;
|
||||
|
||||
int preview;
|
||||
char *search;
|
||||
@@ -124,9 +147,25 @@ struct mode_tree_menu {
|
||||
u_int line;
|
||||
};
|
||||
|
||||
static void mode_tree_free_items(struct mode_tree_list *);
|
||||
static void mode_tree_draw_help(struct mode_tree_data *,
|
||||
struct screen_write_ctx *);
|
||||
/*
|
||||
* 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[] = {
|
||||
{ "Scroll Left", '<', NULL },
|
||||
@@ -138,31 +177,53 @@ static const struct menu_item mode_tree_menu_items[] = {
|
||||
};
|
||||
|
||||
static const char* mode_tree_help_start[] = {
|
||||
"#[bold] Up, k #[default]#[acs]x#[default] Move cursor up",
|
||||
"#[bold] Down, j #[default]#[acs]x#[default] Move cursor down",
|
||||
"#[bold] g #[default]#[acs]x#[default] Go to top",
|
||||
"#[bold] G #[default]#[acs]x#[default] Go to bottom",
|
||||
"#[bold] PPage, C-b #[default]#[acs]x#[default] Page up",
|
||||
"#[bold] NPage, C-f #[default]#[acs]x#[default] Page down",
|
||||
"#[bold] Left, h #[default]#[acs]x#[default] Collapse %1",
|
||||
"#[bold] Right, l #[default]#[acs]x#[default] Expand %1",
|
||||
"#[bold] M-- #[default]#[acs]x#[default] Collapse all %1s",
|
||||
"#[bold] M-+ #[default]#[acs]x#[default] Expand all %1s",
|
||||
"#[bold] t #[default]#[acs]x#[default] Toggle %1 tag",
|
||||
"#[bold] T #[default]#[acs]x#[default] Untag all %1s",
|
||||
"#[bold] C-t #[default]#[acs]x#[default] Tag all %1s",
|
||||
"#[bold] C-s #[default]#[acs]x#[default] Search forward",
|
||||
"#[bold] C-r #[default]#[acs]x#[default] Search backward",
|
||||
"#[bold] n #[default]#[acs]x#[default] Repeat search forward",
|
||||
"#[bold] N #[default]#[acs]x#[default] Repeat search backward",
|
||||
"#[bold] f #[default]#[acs]x#[default] Filter %1s",
|
||||
"#[bold] O #[default]#[acs]x#[default] Change sort order",
|
||||
"#[bold] r #[default]#[acs]x#[default] Reverse sort order",
|
||||
"#[bold] v #[default]#[acs]x#[default] Toggle preview",
|
||||
"#[fg=themelightgrey]"
|
||||
" Up, k #[#{E:tree-mode-border-style},acs]x#[default] Move cursor up",
|
||||
"#[fg=themelightgrey]"
|
||||
" Down, j #[#{E:tree-mode-border-style},acs]x#[default] Move cursor down",
|
||||
"#[fg=themelightgrey]"
|
||||
" g #[#{E:tree-mode-border-style},acs]x#[default] Go to top",
|
||||
"#[fg=themelightgrey]"
|
||||
" G #[#{E:tree-mode-border-style},acs]x#[default] Go to bottom",
|
||||
"#[fg=themelightgrey]"
|
||||
" PPage, C-b #[#{E:tree-mode-border-style},acs]x#[default] Page up",
|
||||
"#[fg=themelightgrey]"
|
||||
" NPage, C-f #[#{E:tree-mode-border-style},acs]x#[default] Page down",
|
||||
"#[fg=themelightgrey]"
|
||||
" Left, h #[#{E:tree-mode-border-style},acs]x#[default] Collapse %1",
|
||||
"#[fg=themelightgrey]"
|
||||
" Right, l #[#{E:tree-mode-border-style},acs]x#[default] Expand %1",
|
||||
"#[fg=themelightgrey]"
|
||||
" M-- #[#{E:tree-mode-border-style},acs]x#[default] Collapse all %1s",
|
||||
"#[fg=themelightgrey]"
|
||||
" M-+ #[#{E:tree-mode-border-style},acs]x#[default] Expand all %1s",
|
||||
"#[fg=themelightgrey]"
|
||||
" t #[#{E:tree-mode-border-style},acs]x#[default] Toggle %1 tag",
|
||||
"#[fg=themelightgrey]"
|
||||
" T #[#{E:tree-mode-border-style},acs]x#[default] Untag all %1s",
|
||||
"#[fg=themelightgrey]"
|
||||
" C-t #[#{E:tree-mode-border-style},acs]x#[default] Tag all %1s",
|
||||
"#[fg=themelightgrey]"
|
||||
" C-s #[#{E:tree-mode-border-style},acs]x#[default] Search forward",
|
||||
"#[fg=themelightgrey]"
|
||||
" C-r #[#{E:tree-mode-border-style},acs]x#[default] Search backward",
|
||||
"#[fg=themelightgrey]"
|
||||
" n #[#{E:tree-mode-border-style},acs]x#[default] Repeat search forward",
|
||||
"#[fg=themelightgrey]"
|
||||
" N #[#{E:tree-mode-border-style},acs]x#[default] Repeat search backward",
|
||||
"#[fg=themelightgrey]"
|
||||
" f #[#{E:tree-mode-border-style},acs]x#[default] Filter %1s",
|
||||
"#[fg=themelightgrey]"
|
||||
" O #[#{E:tree-mode-border-style},acs]x#[default] Change sort order",
|
||||
"#[fg=themelightgrey]"
|
||||
" r #[#{E:tree-mode-border-style},acs]x#[default] Reverse sort order",
|
||||
"#[fg=themelightgrey]"
|
||||
" v #[#{E:tree-mode-border-style},acs]x#[default] Toggle preview",
|
||||
NULL
|
||||
};
|
||||
static const char* mode_tree_help_end[] = {
|
||||
"#[bold] q, Escape #[default]#[acs]x#[default] Exit mode",
|
||||
"#[fg=themelightgrey]"
|
||||
" q, Escape #[#{E:tree-mode-border-style},acs]x#[default] Exit mode",
|
||||
NULL
|
||||
};
|
||||
#define MODE_TREE_HELP_DEFAULT_WIDTH 39
|
||||
@@ -382,6 +443,13 @@ mode_tree_get_current_name(struct mode_tree_data *mtd)
|
||||
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
|
||||
mode_tree_expand_current(struct mode_tree_data *mtd)
|
||||
{
|
||||
@@ -509,7 +577,9 @@ mode_tree_start(struct window_pane *wp, struct args *args,
|
||||
mtd->modedata = modedata;
|
||||
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;
|
||||
else if (args_has(args, 'N'))
|
||||
mtd->preview = MODE_TREE_PREVIEW_OFF;
|
||||
@@ -641,6 +711,7 @@ mode_tree_free(struct mode_tree_data *mtd)
|
||||
if (mtd->zoomed == 0)
|
||||
server_unzoom_window(wp->window);
|
||||
|
||||
mode_tree_clear_prompt(mtd);
|
||||
mode_tree_free_items(&mtd->children);
|
||||
mode_tree_clear_lines(mtd);
|
||||
screen_free(&mtd->screen);
|
||||
@@ -723,8 +794,8 @@ mode_tree_no_tag(struct mode_tree_item *mti)
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the alignment of mti->name: -1 to align left, 0 (default) to not align,
|
||||
* or 1 to align right.
|
||||
* Set the alignment of the item name: -1 to align left, 0 (default) to not
|
||||
* align, or 1 to align right.
|
||||
*/
|
||||
void
|
||||
mode_tree_align(struct mode_tree_item *mti, int align)
|
||||
@@ -753,25 +824,34 @@ mode_tree_draw(struct mode_tree_data *mtd)
|
||||
struct mode_tree_item *mti;
|
||||
struct options *oo = wp->window->options;
|
||||
struct screen_write_ctx ctx;
|
||||
struct grid_cell gc0, gc;
|
||||
u_int w, h, i, j, sy, box_x, box_y, width;
|
||||
char *text, *start, *key;
|
||||
const char *tag, *symbol;
|
||||
size_t size, n;
|
||||
int keylen, pad, alignlen[mtd->maxdepth + 1];
|
||||
struct format_tree *ft;
|
||||
struct grid_cell gc0, gc, box_gc;
|
||||
u_int w, h, i, sy, box_x, box_y;
|
||||
u_int width, text_width, prefix_width, left;
|
||||
char *text, *prefix;
|
||||
const char *tag, *separator;
|
||||
size_t n;
|
||||
int keylen, alignlen[mtd->maxdepth + 1];
|
||||
int dfg, dfg0;
|
||||
|
||||
if (mtd->line_size == 0)
|
||||
return;
|
||||
|
||||
memcpy(&gc0, &grid_default_cell, sizeof gc0);
|
||||
memcpy(&gc, &grid_default_cell, sizeof gc);
|
||||
style_apply(&gc, oo, "mode-style", NULL);
|
||||
style_apply(&gc, oo, "tree-mode-selection-style", NULL);
|
||||
memcpy(&box_gc, &grid_default_cell, sizeof box_gc);
|
||||
style_apply(&box_gc, oo, "tree-mode-border-style", NULL);
|
||||
|
||||
dfg = gc.fg;
|
||||
dfg0 = gc0.fg;
|
||||
|
||||
w = mtd->width;
|
||||
h = mtd->height;
|
||||
|
||||
screen_write_start(&ctx, s);
|
||||
screen_write_clearscreen(&ctx, 8);
|
||||
ft = format_create_defaults(NULL, NULL, NULL, NULL, wp);
|
||||
|
||||
keylen = 0;
|
||||
for (i = 0; i < mtd->line_size; i++) {
|
||||
@@ -802,81 +882,98 @@ mode_tree_draw(struct mode_tree_data *mtd)
|
||||
|
||||
screen_write_cursormove(&ctx, 0, i - mtd->offset, 0);
|
||||
|
||||
pad = keylen - 2 - mti->keylen;
|
||||
if (mti->key != KEYC_NONE)
|
||||
xasprintf(&key, "(%s)%*s", mti->keystr, pad, "");
|
||||
format_add(ft, "mode_tree_key", "%s", mti->keystr);
|
||||
else
|
||||
key = xstrdup("");
|
||||
|
||||
if (line->flat)
|
||||
symbol = "";
|
||||
else if (TAILQ_EMPTY(&mti->children))
|
||||
symbol = " ";
|
||||
else if (mti->expanded)
|
||||
symbol = "- ";
|
||||
else
|
||||
symbol = "+ ";
|
||||
|
||||
if (line->depth == 0)
|
||||
start = xstrdup(symbol);
|
||||
else {
|
||||
size = (4 * line->depth) + 32;
|
||||
|
||||
start = xcalloc(1, size);
|
||||
for (j = 1; j < line->depth; j++) {
|
||||
if (mti->parent != NULL &&
|
||||
mtd->line_list[mti->parent->line].last)
|
||||
strlcat(start, " ", size);
|
||||
else
|
||||
strlcat(start, "\001x\001 ", size);
|
||||
}
|
||||
if (line->last)
|
||||
strlcat(start, "\001mq\001> ", size);
|
||||
format_add(ft, "mode_tree_key", "%s", "");
|
||||
format_add(ft, "mode_tree_key_width", "%d", keylen);
|
||||
format_add(ft, "mode_tree_selected", "%d", i == mtd->current);
|
||||
if (line->depth == 0) {
|
||||
format_add(ft, "mode_tree_repeat", "%u", 0);
|
||||
format_add(ft, "mode_tree_branch", "0");
|
||||
format_add(ft, "mode_tree_parent_last", "0");
|
||||
} else {
|
||||
format_add(ft, "mode_tree_repeat", "%u",
|
||||
line->depth - 1);
|
||||
format_add(ft, "mode_tree_branch", "1");
|
||||
if (mti->parent != NULL &&
|
||||
mtd->line_list[mti->parent->line].last)
|
||||
format_add(ft, "mode_tree_parent_last", "1");
|
||||
else
|
||||
strlcat(start, "\001tq\001> ", size);
|
||||
strlcat(start, symbol, size);
|
||||
format_add(ft, "mode_tree_parent_last", "0");
|
||||
}
|
||||
if (TAILQ_EMPTY(&mti->children))
|
||||
format_add(ft, "mode_tree_has_children", "0");
|
||||
else
|
||||
format_add(ft, "mode_tree_has_children", "1");
|
||||
format_add(ft, "mode_tree_last", "%d", line->last);
|
||||
format_add(ft, "mode_tree_expanded", "%d", mti->expanded);
|
||||
format_add(ft, "mode_tree_flat", "%d", line->flat);
|
||||
prefix = format_expand(ft, MODE_TREE_PREFIX_FORMAT);
|
||||
prefix_width = format_width(prefix);
|
||||
if (prefix_width > w)
|
||||
prefix_width = w;
|
||||
|
||||
if (mti->tagged)
|
||||
tag = "*";
|
||||
else
|
||||
tag = "";
|
||||
xasprintf(&text, "%-*s%s%*s%s%s", keylen, key, start,
|
||||
mti->align * alignlen[line->depth], mti->name, tag,
|
||||
(mti->text != NULL) ? ": " : "" );
|
||||
width = utf8_cstrwidth(text);
|
||||
if (width > w)
|
||||
width = w;
|
||||
free(start);
|
||||
if (mti->text != NULL)
|
||||
separator = "#[fg=themelightgrey]: #[default]";
|
||||
else
|
||||
separator = "";
|
||||
xasprintf(&text, "%*s%s%s",
|
||||
mti->align * alignlen[line->depth], mti->name, tag, separator);
|
||||
text_width = format_width(text);
|
||||
left = (prefix_width < w) ? (w - prefix_width) : 0;
|
||||
if (text_width > left)
|
||||
text_width = left;
|
||||
width = prefix_width + text_width;
|
||||
|
||||
if (mti->tagged) {
|
||||
gc.attr ^= GRID_ATTR_BRIGHT;
|
||||
gc0.attr ^= GRID_ATTR_BRIGHT;
|
||||
gc.fg = COLOUR_THEME_CYAN|COLOUR_FLAG_THEME;
|
||||
gc0.fg = COLOUR_THEME_CYAN|COLOUR_FLAG_THEME;
|
||||
}
|
||||
|
||||
if (i != mtd->current) {
|
||||
screen_write_clearendofline(&ctx, 8);
|
||||
screen_write_nputs(&ctx, w, &gc0, "%s", text);
|
||||
if (mti->text != NULL) {
|
||||
format_draw(&ctx, &gc0, w - width, mti->text,
|
||||
NULL, 0);
|
||||
format_draw(&ctx, &grid_default_cell, prefix_width,
|
||||
prefix, NULL, 0);
|
||||
if (left != 0) {
|
||||
screen_write_cursormove(&ctx, prefix_width,
|
||||
i - mtd->offset, 0);
|
||||
format_draw(&ctx, &gc0, left, text, NULL, 0);
|
||||
if (mti->text != NULL && width < w) {
|
||||
screen_write_cursormove(&ctx, width,
|
||||
i - mtd->offset, 0);
|
||||
format_draw(&ctx, &gc0, w - width,
|
||||
mti->text, NULL, 0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
screen_write_clearendofline(&ctx, gc.bg);
|
||||
screen_write_nputs(&ctx, w, &gc, "%s", text);
|
||||
if (mti->text != NULL) {
|
||||
format_draw(&ctx, &gc, w - width, mti->text,
|
||||
NULL, 0);
|
||||
format_draw(&ctx, &gc, prefix_width, prefix, NULL, 0);
|
||||
if (left != 0) {
|
||||
screen_write_cursormove(&ctx, prefix_width,
|
||||
i - mtd->offset, 0);
|
||||
format_draw(&ctx, &gc, left, text, NULL, 0);
|
||||
if (mti->text != NULL && width < w) {
|
||||
screen_write_cursormove(&ctx, width,
|
||||
i - mtd->offset, 0);
|
||||
format_draw(&ctx, &gc, w - width,
|
||||
mti->text, NULL, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
free(text);
|
||||
free(key);
|
||||
free(prefix);
|
||||
|
||||
if (mti->tagged) {
|
||||
gc.attr ^= GRID_ATTR_BRIGHT;
|
||||
gc0.attr ^= GRID_ATTR_BRIGHT;
|
||||
gc.fg = dfg;
|
||||
gc0.fg = dfg0;
|
||||
}
|
||||
}
|
||||
format_free(ft);
|
||||
|
||||
if (mtd->preview == MODE_TREE_PREVIEW_OFF)
|
||||
goto done;
|
||||
@@ -891,7 +988,7 @@ mode_tree_draw(struct mode_tree_data *mtd)
|
||||
mti = mti->parent;
|
||||
|
||||
screen_write_cursormove(&ctx, 0, h, 0);
|
||||
screen_write_box(&ctx, w, sy - h, BOX_LINES_DEFAULT, NULL, NULL);
|
||||
screen_write_box(&ctx, w, sy - h, BOX_LINES_DEFAULT, &box_gc, NULL);
|
||||
|
||||
if (mtd->sort_crit.order_seq != NULL) {
|
||||
xasprintf(&text, " %s (sort: %s%s)%s%s%s", mti->name,
|
||||
@@ -904,21 +1001,21 @@ mode_tree_draw(struct mode_tree_data *mtd)
|
||||
xasprintf(&text, " %s", mti->name);
|
||||
if (w - 2 >= strlen(text)) {
|
||||
screen_write_cursormove(&ctx, 1, h, 0);
|
||||
screen_write_puts(&ctx, &gc0, "%s", text);
|
||||
screen_write_puts(&ctx, &box_gc, "%s", text);
|
||||
|
||||
if (mtd->no_matches)
|
||||
n = (sizeof "no matches") - 1;
|
||||
else
|
||||
n = (sizeof "active") - 1;
|
||||
if (mtd->filter != NULL && w - 2 >= strlen(text) + 10 + n + 2) {
|
||||
screen_write_puts(&ctx, &gc0, " (filter: ");
|
||||
screen_write_puts(&ctx, &box_gc, " (filter: ");
|
||||
if (mtd->no_matches)
|
||||
screen_write_puts(&ctx, &gc, "no matches");
|
||||
screen_write_puts(&ctx, &box_gc, "no matches");
|
||||
else
|
||||
screen_write_puts(&ctx, &gc0, "active");
|
||||
screen_write_puts(&ctx, &gc0, ") ");
|
||||
screen_write_puts(&ctx, &box_gc, "active");
|
||||
screen_write_puts(&ctx, &box_gc, ") ");
|
||||
} else
|
||||
screen_write_puts(&ctx, &gc0, " ");
|
||||
screen_write_puts(&ctx, &box_gc, " ");
|
||||
}
|
||||
free(text);
|
||||
|
||||
@@ -933,10 +1030,149 @@ mode_tree_draw(struct mode_tree_data *mtd)
|
||||
done:
|
||||
if (mtd->help)
|
||||
mode_tree_draw_help(mtd, &ctx);
|
||||
screen_write_cursormove(&ctx, 0, mtd->current - mtd->offset, 0);
|
||||
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);
|
||||
}
|
||||
|
||||
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->c = c;
|
||||
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 *
|
||||
mode_tree_search_backward(struct mode_tree_data *mtd)
|
||||
{
|
||||
@@ -1057,41 +1293,37 @@ mode_tree_search_set(struct mode_tree_data *mtd)
|
||||
mtd->wp->flags |= PANE_REDRAW;
|
||||
}
|
||||
|
||||
static int
|
||||
static enum prompt_result
|
||||
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;
|
||||
|
||||
if (mtd->dead)
|
||||
return (0);
|
||||
return (PROMPT_CLOSE);
|
||||
|
||||
free(mtd->search);
|
||||
if (s == NULL || *s == '\0') {
|
||||
if (s == NULL || *s == '\0')
|
||||
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
|
||||
mode_tree_search_free(void *data)
|
||||
{
|
||||
mode_tree_remove_ref(data);
|
||||
}
|
||||
|
||||
static int
|
||||
static enum prompt_result
|
||||
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;
|
||||
|
||||
if (mtd->dead)
|
||||
return (0);
|
||||
return (PROMPT_CLOSE);
|
||||
|
||||
if (mtd->filter != NULL)
|
||||
free(mtd->filter);
|
||||
@@ -1104,13 +1336,20 @@ mode_tree_filter_callback(__unused struct client *c, void *data, const char *s,
|
||||
mode_tree_draw(mtd);
|
||||
mtd->wp->flags |= PANE_REDRAW;
|
||||
|
||||
return (0);
|
||||
if (key == PROMPT_KEY_HANDLED)
|
||||
return (PROMPT_CONTINUE);
|
||||
return (PROMPT_CLOSE);
|
||||
}
|
||||
|
||||
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
|
||||
@@ -1181,12 +1420,14 @@ mode_tree_display_menu(struct mode_tree_data *mtd, struct client *c, u_int x,
|
||||
|
||||
static void
|
||||
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)
|
||||
const struct grid_cell *gc, struct format_tree *ft, const char *line,
|
||||
const char *item, u_int x, u_int y, u_int w)
|
||||
{
|
||||
char *expanded;
|
||||
char *expanded, *replaced;
|
||||
|
||||
expanded = cmd_template_replace(line, item, 1);
|
||||
replaced = cmd_template_replace(line, item, 1);
|
||||
expanded = format_expand(ft, replaced);
|
||||
free(replaced);
|
||||
screen_write_cursormove(ctx, x, y, 0);
|
||||
screen_write_clearcharacter(ctx, w, gc->bg);
|
||||
screen_write_cursormove(ctx, x, y, 0);
|
||||
@@ -1198,10 +1439,12 @@ 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;
|
||||
struct options *oo = mtd->wp->window->options;
|
||||
struct grid_cell box_gc, gc;
|
||||
struct format_tree *ft;
|
||||
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;
|
||||
u_int x, y, w, h = 0, box_w, box_h;
|
||||
|
||||
if (mtd->helpcb == NULL)
|
||||
w = MODE_TREE_HELP_DEFAULT_WIDTH;
|
||||
@@ -1224,18 +1467,22 @@ mode_tree_draw_help(struct mode_tree_data *mtd, struct screen_write_ctx *ctx)
|
||||
x = (sx - box_w) / 2;
|
||||
y = (sy - box_h) / 2;
|
||||
|
||||
memcpy(&box_gc, &grid_default_cell, sizeof box_gc);
|
||||
style_apply(&box_gc, oo, "tree-mode-border-style", NULL);
|
||||
memcpy(&gc, &grid_default_cell, sizeof gc);
|
||||
ft = format_create_defaults(NULL, NULL, NULL, NULL, mtd->wp);
|
||||
screen_write_cursormove(ctx, x, y, 0);
|
||||
screen_write_box(ctx, box_w, box_h, BOX_LINES_DEFAULT, &gc, NULL);
|
||||
screen_write_box(ctx, box_w, box_h, BOX_LINES_DEFAULT, &box_gc, NULL);
|
||||
|
||||
y++;
|
||||
x++;
|
||||
for (line = mode_tree_help_start; *line != NULL; line++, y++)
|
||||
mode_tree_draw_help_line(ctx, &gc, *line, item, x, y, w);
|
||||
mode_tree_draw_help_line(ctx, &gc, ft, *line, item, x, y, w);
|
||||
for (line = lines; line != NULL && *line != NULL; line++, y++)
|
||||
mode_tree_draw_help_line(ctx, &gc, *line, item, x, y, w);
|
||||
mode_tree_draw_help_line(ctx, &gc, ft, *line, item, x, y, w);
|
||||
for (line = mode_tree_help_end; *line != NULL; line++, y++)
|
||||
mode_tree_draw_help_line(ctx, &gc, *line, item, x, y, w);
|
||||
mode_tree_draw_help_line(ctx, &gc, ft, *line, item, x, y, w);
|
||||
format_free(ft);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1251,15 +1498,75 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
|
||||
{
|
||||
struct mode_tree_line *line;
|
||||
struct mode_tree_item *current, *parent, *mti;
|
||||
u_int i, x, y;
|
||||
u_int i, x, y, py, sx;
|
||||
int choice, preview;
|
||||
enum prompt_key_result result;
|
||||
int redraw;
|
||||
struct prompt *prompt;
|
||||
struct mode_tree_prompt *mtp;
|
||||
|
||||
if (mtd->line_size == 0) {
|
||||
*key = KEYC_NONE;
|
||||
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);
|
||||
}
|
||||
if (*key == KEYC_FOCUS_IN || *key == KEYC_FOCUS_OUT) {
|
||||
*key = KEYC_NONE;
|
||||
return (0);
|
||||
}
|
||||
mtd->help = 0;
|
||||
mode_tree_draw(mtd);
|
||||
*key = KEYC_NONE;
|
||||
@@ -1461,11 +1768,10 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
|
||||
case '?':
|
||||
case '/':
|
||||
case 's'|KEYC_CTRL:
|
||||
mtd->references++;
|
||||
mtd->search_dir = MODE_TREE_SEARCH_FORWARD;
|
||||
status_prompt_set(c, NULL, "(search) ", "",
|
||||
mode_tree_search_callback, mode_tree_search_free, mtd,
|
||||
PROMPT_NOFORMAT, PROMPT_TYPE_SEARCH);
|
||||
mode_tree_set_prompt(mtd, c, "(search) ", "",
|
||||
PROMPT_TYPE_SEARCH, PROMPT_NOFORMAT,
|
||||
mode_tree_search_callback, NULL, mtd);
|
||||
break;
|
||||
case 'n':
|
||||
mtd->search_dir = MODE_TREE_SEARCH_FORWARD;
|
||||
@@ -1476,10 +1782,13 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
|
||||
mode_tree_search_set(mtd);
|
||||
break;
|
||||
case 'f':
|
||||
mtd->references++;
|
||||
status_prompt_set(c, NULL, "(filter) ", mtd->filter,
|
||||
mode_tree_filter_callback, mode_tree_filter_free, mtd,
|
||||
PROMPT_NOFORMAT, PROMPT_TYPE_SEARCH);
|
||||
mode_tree_set_prompt(mtd, c, "(filter) ", mtd->filter,
|
||||
PROMPT_TYPE_SEARCH, PROMPT_NOFORMAT,
|
||||
mode_tree_filter_callback, NULL, mtd);
|
||||
break;
|
||||
case 'c':
|
||||
mode_tree_clear_prompt(mtd);
|
||||
mode_tree_clear_filter(mtd);
|
||||
break;
|
||||
case 'v':
|
||||
switch (mtd->preview) {
|
||||
|
||||
4
names.c
4
names.c
@@ -95,7 +95,7 @@ check_window_name(struct window *w)
|
||||
name = format_window_name(w);
|
||||
if (strcmp(name, w->name) != 0) {
|
||||
log_debug("@%u new name %s (was %s)", w->id, name, w->name);
|
||||
window_set_name(w, name, WINDOW_NAME_FORBID_EXT);
|
||||
window_set_name(w, name, 1);
|
||||
server_redraw_window_borders(w);
|
||||
server_status_window(w);
|
||||
} else
|
||||
@@ -166,7 +166,7 @@ parse_window_name(const char *in)
|
||||
|
||||
if (*name == '/')
|
||||
name = basename(name);
|
||||
name = clean_name(name, WINDOW_NAME_FORBID);
|
||||
name = clean_name(name, 0);
|
||||
free(copy);
|
||||
if (name == NULL)
|
||||
return (xstrdup(""));
|
||||
|
||||
298
options-table.c
298
options-table.c
@@ -64,7 +64,7 @@ static const char *options_table_cursor_style_list[] = {
|
||||
"blinking-bar", "bar", NULL
|
||||
};
|
||||
static const char *options_table_pane_scrollbars_list[] = {
|
||||
"off", "modal", "on", NULL
|
||||
"off", "modal", "on", "auto-hide", NULL
|
||||
};
|
||||
static const char *options_table_pane_scrollbars_position_list[] = {
|
||||
"right", "left", NULL
|
||||
@@ -108,6 +108,9 @@ static const char *options_table_extended_keys_format_list[] = {
|
||||
static const char *options_table_allow_passthrough_list[] = {
|
||||
"off", "on", "all", NULL
|
||||
};
|
||||
static const char *options_table_theme_list[] = {
|
||||
"detect", "terminal", "light", "dark", NULL
|
||||
};
|
||||
static const char *options_table_copy_mode_line_numbers_list[] = {
|
||||
"off", "default", "absolute", "relative", "hybrid", NULL
|
||||
};
|
||||
@@ -270,6 +273,7 @@ const struct options_name_map options_other_names[] = {
|
||||
{ "clock-mode-color", "clock-mode-colour" },
|
||||
{ "cursor-color", "cursor-colour" },
|
||||
{ "prompt-cursor-color", "prompt-cursor-colour" },
|
||||
{ "prompt-command-cursor-color", "prompt-command-cursor-colour" },
|
||||
{ "pane-colors", "pane-colours" },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
@@ -327,9 +331,10 @@ const struct options_table_entry options_table[] = {
|
||||
},
|
||||
|
||||
{ .name = "cursor-colour",
|
||||
.type = OPTIONS_TABLE_COLOUR,
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
|
||||
.default_num = -1,
|
||||
.flags = OPTIONS_TABLE_IS_COLOUR,
|
||||
.default_str = "",
|
||||
.text = "Colour of the cursor."
|
||||
},
|
||||
|
||||
@@ -444,7 +449,7 @@ const struct options_table_entry options_table[] = {
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_WINDOW,
|
||||
.flags = OPTIONS_TABLE_IS_STYLE,
|
||||
.default_str = "default",
|
||||
.default_str = "bg=themedarkgrey,fg=themewhite",
|
||||
.separator = ",",
|
||||
.text = "Default style of menu."
|
||||
},
|
||||
@@ -453,7 +458,7 @@ const struct options_table_entry options_table[] = {
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_WINDOW,
|
||||
.flags = OPTIONS_TABLE_IS_STYLE,
|
||||
.default_str = "bg=yellow,fg=black",
|
||||
.default_str = "bg=themeyellow,fg=themeblack",
|
||||
.separator = ",",
|
||||
.text = "Default style of selected menu item."
|
||||
},
|
||||
@@ -461,7 +466,7 @@ const struct options_table_entry options_table[] = {
|
||||
{ .name = "menu-border-style",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_WINDOW,
|
||||
.default_str = "default",
|
||||
.default_str = "bg=themedarkgrey,fg=themelightgrey",
|
||||
.flags = OPTIONS_TABLE_IS_STYLE,
|
||||
.separator = ",",
|
||||
.text = "Default style of menu borders."
|
||||
@@ -536,6 +541,175 @@ const struct options_table_entry options_table[] = {
|
||||
"automatically detected."
|
||||
},
|
||||
|
||||
{ .name = "theme",
|
||||
.type = OPTIONS_TABLE_CHOICE,
|
||||
.scope = OPTIONS_TABLE_SERVER,
|
||||
.choices = options_table_theme_list,
|
||||
.default_num = 0,
|
||||
.text = "Whether tmux should detect the terminal theme, use terminal "
|
||||
"ANSI colours, or force the light or dark theme."
|
||||
},
|
||||
|
||||
{ .name = "dark-theme-black",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_SERVER,
|
||||
.flags = OPTIONS_TABLE_IS_COLOUR,
|
||||
.default_str = "#{?#{e|>=:#{client_colours},256},gray5,black}",
|
||||
.text = "Dark theme colour for black."
|
||||
},
|
||||
|
||||
{ .name = "dark-theme-white",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_SERVER,
|
||||
.flags = OPTIONS_TABLE_IS_COLOUR,
|
||||
.default_str = "#{?#{e|>=:#{client_colours},256},gray90,white}",
|
||||
.text = "Dark theme colour for white."
|
||||
},
|
||||
|
||||
{ .name = "dark-theme-light-grey",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_SERVER,
|
||||
.flags = OPTIONS_TABLE_IS_COLOUR,
|
||||
.default_str = "#{?#{e|>=:#{client_colours},256},gray70,white}",
|
||||
.text = "Dark theme colour for light grey."
|
||||
},
|
||||
|
||||
{ .name = "dark-theme-dark-grey",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_SERVER,
|
||||
.flags = OPTIONS_TABLE_IS_COLOUR,
|
||||
.default_str = "#{?#{e|>=:#{client_colours},256},gray15,black}",
|
||||
.text = "Dark theme colour for dark grey."
|
||||
},
|
||||
|
||||
{ .name = "dark-theme-green",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_SERVER,
|
||||
.flags = OPTIONS_TABLE_IS_COLOUR,
|
||||
.default_str = "#{?#{e|>=:#{client_colours},256},yellowgreen,green}",
|
||||
.text = "Dark theme colour for green."
|
||||
},
|
||||
|
||||
{ .name = "dark-theme-yellow",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_SERVER,
|
||||
.flags = OPTIONS_TABLE_IS_COLOUR,
|
||||
.default_str = "#{?#{e|>=:#{client_colours},256},darkgoldenrod,yellow}",
|
||||
.text = "Dark theme colour for yellow."
|
||||
},
|
||||
|
||||
{ .name = "dark-theme-red",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_SERVER,
|
||||
.flags = OPTIONS_TABLE_IS_COLOUR,
|
||||
.default_str = "#{?#{e|>=:#{client_colours},256},indianred,red}",
|
||||
.text = "Dark theme colour for red."
|
||||
},
|
||||
|
||||
{ .name = "dark-theme-blue",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_SERVER,
|
||||
.flags = OPTIONS_TABLE_IS_COLOUR,
|
||||
.default_str = "#{?#{e|>=:#{client_colours},256},skyblue3,blue}",
|
||||
.text = "Dark theme colour for blue."
|
||||
},
|
||||
|
||||
{ .name = "dark-theme-cyan",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_SERVER,
|
||||
.flags = OPTIONS_TABLE_IS_COLOUR,
|
||||
.default_str = "#{?#{e|>=:#{client_colours},256},cadetblue,cyan}",
|
||||
.text = "Dark theme colour for cyan."
|
||||
},
|
||||
|
||||
{ .name = "dark-theme-magenta",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_SERVER,
|
||||
.flags = OPTIONS_TABLE_IS_COLOUR,
|
||||
.default_str = "#{?#{e|>=:#{client_colours},256},mediumpurple,magenta}",
|
||||
.text = "Dark theme colour for magenta."
|
||||
},
|
||||
|
||||
{ .name = "light-theme-black",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_SERVER,
|
||||
.flags = OPTIONS_TABLE_IS_COLOUR,
|
||||
.default_str = "#{?#{e|>=:#{client_colours},256},gray10,black}",
|
||||
.text = "Light theme colour for black."
|
||||
},
|
||||
|
||||
{ .name = "light-theme-white",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_SERVER,
|
||||
.flags = OPTIONS_TABLE_IS_COLOUR,
|
||||
.default_str = "#{?#{e|>=:#{client_colours},256},gray95,white}",
|
||||
.text = "Light theme colour for white."
|
||||
},
|
||||
|
||||
{ .name = "light-theme-light-grey",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_SERVER,
|
||||
.flags = OPTIONS_TABLE_IS_COLOUR,
|
||||
.default_str = "#{?#{e|>=:#{client_colours},256},gray80,white}",
|
||||
.text = "Light theme colour for light grey."
|
||||
},
|
||||
|
||||
{ .name = "light-theme-dark-grey",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_SERVER,
|
||||
.flags = OPTIONS_TABLE_IS_COLOUR,
|
||||
.default_str = "#{?#{e|>=:#{client_colours},256},gray45,black}",
|
||||
.text = "Light theme colour for dark grey."
|
||||
},
|
||||
|
||||
{ .name = "light-theme-green",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_SERVER,
|
||||
.flags = OPTIONS_TABLE_IS_COLOUR,
|
||||
.default_str = "#{?#{e|>=:#{client_colours},256},seagreen,green}",
|
||||
.text = "Light theme colour for green."
|
||||
},
|
||||
|
||||
{ .name = "light-theme-yellow",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_SERVER,
|
||||
.flags = OPTIONS_TABLE_IS_COLOUR,
|
||||
.default_str = "#{?#{e|>=:#{client_colours},256},darkgoldenrod,yellow}",
|
||||
.text = "Light theme colour for yellow."
|
||||
},
|
||||
|
||||
{ .name = "light-theme-red",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_SERVER,
|
||||
.flags = OPTIONS_TABLE_IS_COLOUR,
|
||||
.default_str = "#{?#{e|>=:#{client_colours},256},indianred4,red}",
|
||||
.text = "Light theme colour for red."
|
||||
},
|
||||
|
||||
{ .name = "light-theme-blue",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_SERVER,
|
||||
.flags = OPTIONS_TABLE_IS_COLOUR,
|
||||
.default_str = "#{?#{e|>=:#{client_colours},256},steelblue,blue}",
|
||||
.text = "Light theme colour for blue."
|
||||
},
|
||||
|
||||
{ .name = "light-theme-cyan",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_SERVER,
|
||||
.flags = OPTIONS_TABLE_IS_COLOUR,
|
||||
.default_str = "#{?#{e|>=:#{client_colours},256},darkcyan,cyan}",
|
||||
.text = "Light theme colour for cyan."
|
||||
},
|
||||
|
||||
{ .name = "light-theme-magenta",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_SERVER,
|
||||
.flags = OPTIONS_TABLE_IS_COLOUR,
|
||||
.default_str = "#{?#{e|>=:#{client_colours},256},purple4,magenta}",
|
||||
.text = "Light theme colour for magenta."
|
||||
},
|
||||
|
||||
{ .name = "user-keys",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_SERVER,
|
||||
@@ -634,16 +808,18 @@ const struct options_table_entry options_table[] = {
|
||||
},
|
||||
|
||||
{ .name = "display-panes-active-colour",
|
||||
.type = OPTIONS_TABLE_COLOUR,
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_SESSION,
|
||||
.default_num = 1,
|
||||
.flags = OPTIONS_TABLE_IS_COLOUR,
|
||||
.default_str = "themered",
|
||||
.text = "Colour of the active pane for 'display-panes'."
|
||||
},
|
||||
|
||||
{ .name = "display-panes-colour",
|
||||
.type = OPTIONS_TABLE_COLOUR,
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_SESSION,
|
||||
.default_num = 4,
|
||||
.flags = OPTIONS_TABLE_IS_COLOUR,
|
||||
.default_str = "themeblue",
|
||||
.text = "Colour of not active panes for 'display-panes'."
|
||||
},
|
||||
|
||||
@@ -734,7 +910,9 @@ const struct options_table_entry options_table[] = {
|
||||
{ .name = "message-command-style",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_SESSION,
|
||||
.default_str = "bg=black,fg=yellow,fill=black",
|
||||
.default_str = "bg=themeblack,fg=themeyellow,"
|
||||
"#{?#{m/r:(^|#,)IS(PANE|MODE)($|#,),#{prompt_flags}},,"
|
||||
"fill=themeblack}",
|
||||
.flags = OPTIONS_TABLE_IS_STYLE,
|
||||
.separator = ",",
|
||||
.text = "Style of the command prompt when in command mode, if "
|
||||
@@ -763,7 +941,9 @@ const struct options_table_entry options_table[] = {
|
||||
{ .name = "message-style",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_SESSION,
|
||||
.default_str = "bg=yellow,fg=black,fill=yellow",
|
||||
.default_str = "bg=themeyellow,fg=themeblack,"
|
||||
"#{?#{m/r:(^|#,)IS(PANE|MODE)($|#,),#{prompt_flags}},,"
|
||||
"fill=themeyellow}",
|
||||
.flags = OPTIONS_TABLE_IS_STYLE,
|
||||
.separator = ",",
|
||||
.text = "Style of messages and the command prompt. "
|
||||
@@ -962,7 +1142,7 @@ const struct options_table_entry options_table[] = {
|
||||
{ .name = "status-style",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_SESSION,
|
||||
.default_str = "bg=green,fg=black",
|
||||
.default_str = "bg=themegreen,fg=themeblack",
|
||||
.flags = OPTIONS_TABLE_IS_STYLE,
|
||||
.separator = ",",
|
||||
.text = "Style of the status line."
|
||||
@@ -971,7 +1151,7 @@ const struct options_table_entry options_table[] = {
|
||||
{ .name = "pane-status-current-style",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_WINDOW,
|
||||
.default_str = "default",
|
||||
.default_str = "underscore",
|
||||
.flags = OPTIONS_TABLE_IS_STYLE,
|
||||
.separator = ",",
|
||||
.text = "Style of the current pane in the status line."
|
||||
@@ -988,12 +1168,22 @@ const struct options_table_entry options_table[] = {
|
||||
},
|
||||
|
||||
{ .name = "prompt-cursor-colour",
|
||||
.type = OPTIONS_TABLE_COLOUR,
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_SESSION,
|
||||
.default_num = -1,
|
||||
.flags = OPTIONS_TABLE_IS_COLOUR,
|
||||
.default_str = "",
|
||||
.text = "Colour of the cursor when in the command prompt."
|
||||
},
|
||||
|
||||
{ .name = "prompt-command-cursor-colour",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_SESSION,
|
||||
.flags = OPTIONS_TABLE_IS_COLOUR,
|
||||
.default_str = "",
|
||||
.text = "Colour of the cursor in the command prompt when in command "
|
||||
"mode, if 'status-keys' is set to 'vi'."
|
||||
},
|
||||
|
||||
{ .name = "prompt-cursor-style",
|
||||
.type = OPTIONS_TABLE_CHOICE,
|
||||
.scope = OPTIONS_TABLE_SESSION,
|
||||
@@ -1014,7 +1204,7 @@ const struct options_table_entry options_table[] = {
|
||||
{ .name = "session-status-current-style",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_WINDOW,
|
||||
.default_str = "default",
|
||||
.default_str = "underscore",
|
||||
.flags = OPTIONS_TABLE_IS_STYLE,
|
||||
.separator = ",",
|
||||
.text = "Style of the current session in the status line."
|
||||
@@ -1142,9 +1332,10 @@ const struct options_table_entry options_table[] = {
|
||||
},
|
||||
|
||||
{ .name = "clock-mode-colour",
|
||||
.type = OPTIONS_TABLE_COLOUR,
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_WINDOW,
|
||||
.default_num = 4,
|
||||
.flags = OPTIONS_TABLE_IS_COLOUR,
|
||||
.default_str = "themeblue",
|
||||
.text = "Colour of the clock in clock mode."
|
||||
},
|
||||
|
||||
@@ -1159,7 +1350,7 @@ const struct options_table_entry options_table[] = {
|
||||
{ .name = "copy-mode-match-style",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_WINDOW,
|
||||
.default_str = "bg=cyan,fg=black",
|
||||
.default_str = "bg=themecyan,fg=themeblack",
|
||||
.flags = OPTIONS_TABLE_IS_STYLE,
|
||||
.separator = ",",
|
||||
.text = "Style of search matches in copy mode."
|
||||
@@ -1168,7 +1359,7 @@ const struct options_table_entry options_table[] = {
|
||||
{ .name = "copy-mode-current-match-style",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_WINDOW,
|
||||
.default_str = "bg=magenta,fg=black",
|
||||
.default_str = "bg=thememagenta,fg=themeblack",
|
||||
.flags = OPTIONS_TABLE_IS_STYLE,
|
||||
.separator = ",",
|
||||
.text = "Style of the current search match in copy mode."
|
||||
@@ -1177,7 +1368,7 @@ const struct options_table_entry options_table[] = {
|
||||
{ .name = "copy-mode-mark-style",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_WINDOW,
|
||||
.default_str = "bg=red,fg=black",
|
||||
.default_str = "bg=themeyellow,fg=themeblack",
|
||||
.flags = OPTIONS_TABLE_IS_STYLE,
|
||||
.separator = ",",
|
||||
.text = "Style of the marked line in copy mode."
|
||||
@@ -1216,7 +1407,7 @@ const struct options_table_entry options_table[] = {
|
||||
{ .name = "copy-mode-current-line-number-style",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_WINDOW,
|
||||
.default_str = "fg=yellow",
|
||||
.default_str = "fg=themeyellow",
|
||||
.flags = OPTIONS_TABLE_IS_STYLE,
|
||||
.separator = ",",
|
||||
.text = "Style of current line number in copy mode."
|
||||
@@ -1225,7 +1416,7 @@ const struct options_table_entry options_table[] = {
|
||||
{ .name = "copy-mode-line-number-style",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_WINDOW,
|
||||
.default_str = "fg=white,dim",
|
||||
.default_str = "fg=themelightgrey,dim",
|
||||
.flags = OPTIONS_TABLE_IS_STYLE,
|
||||
.separator = ",",
|
||||
.text = "Style of line numbers in copy mode."
|
||||
@@ -1296,7 +1487,7 @@ const struct options_table_entry options_table[] = {
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_WINDOW,
|
||||
.flags = OPTIONS_TABLE_IS_STYLE,
|
||||
.default_str = "noattr,bg=yellow,fg=black",
|
||||
.default_str = "noattr,bg=themeyellow,fg=themeblack",
|
||||
.separator = ",",
|
||||
.text = "Style of indicators and highlighting in modes."
|
||||
},
|
||||
@@ -1345,7 +1536,9 @@ const struct options_table_entry options_table[] = {
|
||||
{ .name = "pane-active-border-style",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
|
||||
.default_str = "#{?pane_in_mode,fg=yellow,#{?synchronize-panes,fg=red,fg=green}}",
|
||||
.default_str = "fg=#{?pane_marked,thememagenta,"
|
||||
"#{?synchronize-panes,themered,"
|
||||
"#{?pane_in_mode,themeyellow,themegreen}}}",
|
||||
.flags = OPTIONS_TABLE_IS_STYLE,
|
||||
.separator = ",",
|
||||
.text = "Style of the active pane border."
|
||||
@@ -1404,7 +1597,7 @@ const struct options_table_entry options_table[] = {
|
||||
{ .name = "pane-border-style",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
|
||||
.default_str = "default",
|
||||
.default_str = "fg=themelightgrey",
|
||||
.flags = OPTIONS_TABLE_IS_STYLE,
|
||||
.separator = ",",
|
||||
.text = "Style of the pane status lines."
|
||||
@@ -1423,13 +1616,23 @@ const struct options_table_entry options_table[] = {
|
||||
.scope = OPTIONS_TABLE_WINDOW,
|
||||
.choices = options_table_pane_scrollbars_list,
|
||||
.default_num = PANE_SCROLLBARS_OFF,
|
||||
.text = "Pane scrollbar state."
|
||||
.text = "Pane scrollbar state: off, on, modal, or auto-hide."
|
||||
},
|
||||
|
||||
{ .name = "pane-scrollbars-timeout",
|
||||
.type = OPTIONS_TABLE_NUMBER,
|
||||
.scope = OPTIONS_TABLE_WINDOW,
|
||||
.minimum = 0,
|
||||
.maximum = INT_MAX,
|
||||
.default_num = 500,
|
||||
.unit = "milliseconds",
|
||||
.text = "Time before modal and auto-hide pane scrollbars disappear."
|
||||
},
|
||||
|
||||
{ .name = "pane-scrollbars-style",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
|
||||
.default_str = "bg=black,fg=white,width=1,pad=0",
|
||||
.default_str = "bg=themedarkgrey,fg=themelightgrey,width=1,pad=0",
|
||||
.flags = OPTIONS_TABLE_IS_STYLE,
|
||||
.separator = ",",
|
||||
.text = "Style of the pane scrollbar."
|
||||
@@ -1446,7 +1649,7 @@ const struct options_table_entry options_table[] = {
|
||||
{ .name = "popup-style",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_WINDOW,
|
||||
.default_str = "default",
|
||||
.default_str = "bg=themedarkgrey,fg=themewhite",
|
||||
.flags = OPTIONS_TABLE_IS_STYLE,
|
||||
.separator = ",",
|
||||
.text = "Default style of popups."
|
||||
@@ -1455,7 +1658,7 @@ const struct options_table_entry options_table[] = {
|
||||
{ .name = "popup-border-style",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_WINDOW,
|
||||
.default_str = "default",
|
||||
.default_str = "bg=themedarkgrey,fg=themelightgrey",
|
||||
.flags = OPTIONS_TABLE_IS_STYLE,
|
||||
.separator = ",",
|
||||
.text = "Default style of popup borders."
|
||||
@@ -1501,6 +1704,15 @@ const struct options_table_entry options_table[] = {
|
||||
"history when clearing the whole screen."
|
||||
},
|
||||
|
||||
{ .name = "switch-mode-match-style",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
|
||||
.default_str = "bg=cyan fg=black",
|
||||
.flags = OPTIONS_TABLE_IS_STYLE,
|
||||
.separator = ",",
|
||||
.text = "Style of matched characters in switch mode."
|
||||
},
|
||||
|
||||
{ .name = "synchronize-panes",
|
||||
.type = OPTIONS_TABLE_FLAG,
|
||||
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
|
||||
@@ -1518,6 +1730,15 @@ const struct options_table_entry options_table[] = {
|
||||
"A value of 0 means no limit."
|
||||
},
|
||||
|
||||
{ .name = "tree-mode-border-style",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_WINDOW,
|
||||
.default_str = "bg=themedarkgrey,fg=themelightgrey",
|
||||
.flags = OPTIONS_TABLE_IS_STYLE,
|
||||
.separator = ",",
|
||||
.text = "Style of borders in tree mode."
|
||||
},
|
||||
|
||||
{ .name = "tree-mode-preview-format",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
|
||||
@@ -1533,13 +1754,22 @@ const struct options_table_entry options_table[] = {
|
||||
.default_str = "fg=#{?#{||:"
|
||||
"#{&&:#{pane_format},#{pane_active}},"
|
||||
"#{&&:#{window_format},#{window_active}}},"
|
||||
"#{display-panes-active-colour},"
|
||||
"#{display-panes-colour}}",
|
||||
"themered,"
|
||||
"themeblue}",
|
||||
.flags = OPTIONS_TABLE_IS_STYLE,
|
||||
.separator = ",",
|
||||
.text = "Style of preview indicator in tree mode."
|
||||
},
|
||||
|
||||
{ .name = "tree-mode-selection-style",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_WINDOW,
|
||||
.default_str = "#{E:mode-style}",
|
||||
.flags = OPTIONS_TABLE_IS_STYLE,
|
||||
.separator = ",",
|
||||
.text = "Style of the selected line in tree mode."
|
||||
},
|
||||
|
||||
{ .name = "window-active-style",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
|
||||
@@ -1613,7 +1843,7 @@ const struct options_table_entry options_table[] = {
|
||||
{ .name = "window-status-current-style",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_WINDOW,
|
||||
.default_str = "default",
|
||||
.default_str = "underscore",
|
||||
.flags = OPTIONS_TABLE_IS_STYLE,
|
||||
.separator = ",",
|
||||
.text = "Style of the current window in the status line."
|
||||
|
||||
78
options.c
78
options.c
@@ -662,6 +662,18 @@ options_parse_get(struct options *oo, const char *s, int *idx, int only)
|
||||
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 *
|
||||
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,
|
||||
struct format_tree *ft)
|
||||
{
|
||||
struct options_entry *o;
|
||||
const char *s;
|
||||
char *expanded;
|
||||
struct options_entry *o;
|
||||
const struct options_table_entry *oe;
|
||||
const struct grid_cell *dgc = &grid_default_cell;
|
||||
const char *s;
|
||||
char *expanded;
|
||||
int failed;
|
||||
|
||||
o = options_get(oo, name);
|
||||
if (o == NULL || !OPTIONS_IS_STRING(o))
|
||||
@@ -988,20 +1003,27 @@ options_string_to_style(struct options *oo, const char *name,
|
||||
if (o->cached)
|
||||
return (&o->style);
|
||||
s = o->value.string;
|
||||
oe = o->tableentry;
|
||||
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);
|
||||
|
||||
if (ft != NULL && !o->cached) {
|
||||
expanded = format_expand(ft, s);
|
||||
if (style_parse(&o->style, &grid_default_cell, expanded) != 0) {
|
||||
free(expanded);
|
||||
return (NULL);
|
||||
}
|
||||
if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_COLOUR))
|
||||
failed = style_parse_colour(&o->style, dgc, expanded);
|
||||
else
|
||||
failed = style_parse(&o->style, dgc, expanded);
|
||||
free(expanded);
|
||||
if (failed != 0)
|
||||
return (NULL);
|
||||
} 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 (&o->style);
|
||||
@@ -1029,6 +1051,12 @@ options_from_string_check(const struct options_table_entry *oe,
|
||||
xasprintf(cause, "invalid style: %s", value);
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -1186,6 +1214,17 @@ options_push_changes(const char *name)
|
||||
|
||||
log_debug("%s: %s", __func__, name);
|
||||
|
||||
if (strcmp(name, "theme") == 0 ||
|
||||
strncmp(name, "dark-theme-", 11) == 0 ||
|
||||
strncmp(name, "light-theme-", 12) == 0) {
|
||||
TAILQ_FOREACH(loop, &clients, entry) {
|
||||
server_client_update_theme_colours(loop);
|
||||
if (loop->tty.flags & TTY_OPENED)
|
||||
tty_invalidate(&loop->tty);
|
||||
server_redraw_client(loop);
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp(name, "automatic-rename") == 0) {
|
||||
RB_FOREACH(w, windows, &windows) {
|
||||
if (w->active == NULL)
|
||||
@@ -1219,6 +1258,16 @@ options_push_changes(const char *name)
|
||||
if (strcmp(name, "status") == 0 ||
|
||||
strcmp(name, "status-interval") == 0)
|
||||
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-timeout") == 0 ||
|
||||
strcmp(name, "pane-scrollbars-position") == 0 ||
|
||||
strcmp(name, "pane-scrollbars-style") == 0)
|
||||
redraw_invalidate_all_scenes();
|
||||
if (strcmp(name, "monitor-silence") == 0)
|
||||
alerts_reset_all();
|
||||
if (strcmp(name, "window-style") == 0 ||
|
||||
@@ -1237,8 +1286,17 @@ options_push_changes(const char *name)
|
||||
if (strcmp(name, "pane-border-status") == 0 ||
|
||||
strcmp(name, "pane-scrollbars") == 0 ||
|
||||
strcmp(name, "pane-scrollbars-position") == 0) {
|
||||
RB_FOREACH(w, windows, &windows)
|
||||
RB_FOREACH(w, windows, &windows) {
|
||||
w->sb = options_get_number(w->options,
|
||||
"pane-scrollbars");
|
||||
w->sb_pos = options_get_number(w->options,
|
||||
"pane-scrollbars-position");
|
||||
layout_fix_panes(w, NULL);
|
||||
}
|
||||
}
|
||||
if (strcmp(name, "pane-scrollbars") == 0) {
|
||||
RB_FOREACH(wp, window_pane_tree, &all_window_panes)
|
||||
window_pane_scrollbar_hide(wp);
|
||||
}
|
||||
if (strcmp(name, "pane-scrollbars-style") == 0) {
|
||||
RB_FOREACH(wp, window_pane_tree, &all_window_panes) {
|
||||
|
||||
4
paste.c
4
paste.c
@@ -219,7 +219,7 @@ paste_rename(const char *oldname, const char *newname, char **cause)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
name = clean_name(newname, "");
|
||||
name = clean_name(newname, 0);
|
||||
if (name == NULL) {
|
||||
if (cause != NULL)
|
||||
xasprintf(cause, "invalid buffer name: %s", newname);
|
||||
@@ -287,7 +287,7 @@ paste_set(char *data, size_t size, const char *name, char **cause)
|
||||
return (-1);
|
||||
}
|
||||
|
||||
newname = clean_name(name, "");
|
||||
newname = clean_name(name, 0);
|
||||
if (newname == NULL) {
|
||||
if (cause != NULL)
|
||||
xasprintf(cause, "invalid buffer name: %s", name);
|
||||
|
||||
4
popup.c
4
popup.c
@@ -273,7 +273,7 @@ popup_check_cb(struct client* c, void *data, u_int px, u_int py, u_int nx)
|
||||
}
|
||||
|
||||
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 tty *tty = &c->tty;
|
||||
@@ -328,7 +328,7 @@ popup_draw_cb(struct client *c, void *data, struct screen_redraw_ctx *rctx)
|
||||
if (pd->md != NULL) {
|
||||
c->overlay_check = 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_data = pd;
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -110,20 +110,26 @@ 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'
|
||||
$TMUX send-keys "printf '\\033]2;title#[fg=red]ok\\007'" Enter || exit 1
|
||||
sleep 1
|
||||
must_equal "$($TMUX display-message -p '#{pane_title}')" 'title#[fg=red]ok'
|
||||
$TMUX send-keys "printf '\\033]2;title#(bad)\\007'" Enter || exit 1
|
||||
sleep 1
|
||||
must_equal "$($TMUX display-message -p '#{pane_title}')" 'title_(bad)'
|
||||
|
||||
# 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.
|
||||
# Window names from escape sequences allow '#' except in '#('.
|
||||
$TMUX send-keys "printf '\\033kescape#:.ok\\033\\\\'" Enter || exit 1
|
||||
sleep 1
|
||||
must_equal "$($TMUX display-message -p '#{window_name}')" 'escape___ok'
|
||||
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'
|
||||
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
|
||||
|
||||
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
|
||||
106
regress/format-fuzzy.sh
Normal file
106
regress/format-fuzzy.sh
Normal file
@@ -0,0 +1,106 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Tests of fuzzy format matching.
|
||||
|
||||
PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
TMUX="$TEST_TMUX -Ltest -f/dev/null"
|
||||
|
||||
# test_format $format $expected_result
|
||||
test_format()
|
||||
{
|
||||
fmt="$1"
|
||||
exp="$2"
|
||||
|
||||
out=$($TMUX display-message -p "$fmt")
|
||||
|
||||
if [ "$out" != "$exp" ]; then
|
||||
echo "Fuzzy format test failed for '$fmt'."
|
||||
echo "Expected: '$exp'"
|
||||
echo "But got '$out'"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
$TMUX kill-server 2>/dev/null
|
||||
$TMUX -f/dev/null new-session -d || exit 1
|
||||
|
||||
# Empty pattern matches everything but has no highlighted positions.
|
||||
test_format '#{m/z:,abc}' '1'
|
||||
test_format '#{m/p:,abc}' ''
|
||||
|
||||
# Plain fuzzy matching and positions.
|
||||
test_format '#{m/z:abc,a_b_c}' '1'
|
||||
test_format '#{m/p:abc,a_b_c}' '0,2,4'
|
||||
test_format '#{m/z:abc,acb}' '0'
|
||||
test_format '#{m/p:abc,acb}' ''
|
||||
|
||||
# Multiple terms are ANDed. Positions are for all positive matched terms.
|
||||
test_format '#{m/z:dev bash,dev:1 bash}' '1'
|
||||
test_format '#{m/p:dev bash,dev:1 bash}' '0,1,2,6,7,8,9'
|
||||
test_format '#{m/z:dev bash,dev:1 sh}' '0'
|
||||
test_format '#{m/p:dev bash,dev:1 sh}' ''
|
||||
|
||||
# Lowercase patterns are case-insensitive for ASCII; uppercase makes the
|
||||
# pattern case-sensitive.
|
||||
test_format '#{m/z:abc,ABC}' '1'
|
||||
test_format '#{m/p:abc,ABC}' '0,1,2'
|
||||
test_format '#{m/z:ABC,abc}' '0'
|
||||
test_format '#{m/p:ABC,abc}' ''
|
||||
|
||||
# Exact substring matching with a leading quote.
|
||||
test_format "#{m/z:'bash,dev bash}" '1'
|
||||
test_format "#{m/p:'bash,dev bash}" '4,5,6,7'
|
||||
test_format "#{m/z:'bash,b-a-s-h}" '0'
|
||||
test_format "#{m/p:'bash,b-a-s-h}" ''
|
||||
|
||||
# Prefix and suffix matching.
|
||||
test_format '#{m/z:^dev,dev bash}' '1'
|
||||
test_format '#{m/p:^dev,dev bash}' '0,1,2'
|
||||
test_format '#{m/z:^dev,prod dev}' '0'
|
||||
test_format '#{m/p:^dev,prod dev}' ''
|
||||
test_format '#{m/z:bash$,dev bash}' '1'
|
||||
test_format '#{m/p:bash$,dev bash}' '4,5,6,7'
|
||||
test_format '#{m/z:bash$,bash dev}' '0'
|
||||
test_format '#{m/p:bash$,bash dev}' ''
|
||||
|
||||
# Inverse terms. Plain inverse terms are exact substring tests, not fuzzy.
|
||||
test_format '#{m/z:!ssh,dev bash}' '1'
|
||||
test_format '#{m/z:!ssh,dev ssh}' '0'
|
||||
test_format '#{m/z:!ssh,s_s_h}' '1'
|
||||
test_format '#{m/z:dev !ssh,dev bash}' '1'
|
||||
test_format '#{m/p:dev !ssh,dev bash}' '0,1,2'
|
||||
test_format '#{m/z:dev !ssh,dev ssh}' '0'
|
||||
test_format '#{m/p:dev !ssh,dev ssh}' ''
|
||||
|
||||
# OR separates groups; each group is an AND of its terms.
|
||||
test_format '#{m/z:prod | dev,dev bash}' '1'
|
||||
test_format '#{m/p:prod | dev,dev bash}' '0,1,2'
|
||||
test_format '#{m/z:prod | dev,prod bash}' '1'
|
||||
test_format '#{m/p:prod | dev,prod bash}' '0,1,2,3'
|
||||
test_format '#{m/z:prod | dev,test bash}' '0'
|
||||
test_format '#{m/p:prod | dev,test bash}' ''
|
||||
|
||||
# Style sequences do not count towards display positions.
|
||||
test_format '#{m/z:dev,#[bold]dev#[default]}' '1'
|
||||
test_format '#{m/p:dev,#[bold]dev#[default]}' '0,1,2'
|
||||
test_format '#{m/p:dev,#[fg=red#,bg=blue]dev#[default]}' '0,1,2'
|
||||
test_format '#{m/p:dev,#[bold]d#[default]e#[underscore]v#[default]}' '0,1,2'
|
||||
test_format '#{m/p:bash,#[bold]dev#[default] bash}' '4,5,6,7'
|
||||
|
||||
# UTF-8. Non-ASCII matching is exact, even when ASCII would fold case.
|
||||
test_format '#{m/z:é,café}' '1'
|
||||
test_format '#{m/p:é,café}' '3'
|
||||
test_format '#{m/z:é,É}' '0'
|
||||
test_format '#{m/p:é,É}' ''
|
||||
test_format '#{m/z:éx,éx}' '1'
|
||||
test_format '#{m/p:éx,éx}' '0,1'
|
||||
|
||||
# Wide UTF-8 characters occupy two display cells and both should be marked for
|
||||
# highlighting.
|
||||
test_format '#{m/z:界,a界b}' '1'
|
||||
test_format '#{m/p:界,a界b}' '1,2'
|
||||
|
||||
exit 0
|
||||
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
|
||||
@@ -1,12 +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
|
||||
[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
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
base
|
||||
|
||||
┌────────────────────┐
|
||||
│FLOAT │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
└────────────────────┘
|
||||
|
||||
┌──────────────────┐
|
||||
│FLOAT │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
└──────────────────┘
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
bas╔════════════════════════════╗
|
||||
║FLOAT ║
|
||||
║ ║
|
||||
║ ║
|
||||
║ ║
|
||||
║ ║
|
||||
║ ║
|
||||
║ ║
|
||||
║ ║
|
||||
╚════════════════════════════╝
|
||||
base
|
||||
╔══════════════════════════╗
|
||||
║FLOAT ║
|
||||
║ ║
|
||||
║ ║
|
||||
║ ║
|
||||
║ ║
|
||||
║ ║
|
||||
╚══════════════════════════╝
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
06:abcdefghijklmnopqrstuvwxyz0123456789
|
||||
07:abcdefghijklmnopqrstuvwxyz0123456789
|
||||
08:abcdefghijklmnopqrstuvwxyz0123456789
|
||||
09:abcdef┌────────────────────┐23456789
|
||||
10:abcdef│BOTTOM │23456789
|
||||
11:abcdef│ │23456789
|
||||
│ │
|
||||
09:abcdefghijklmnopqrstuvwxyz0123456789
|
||||
10:abcdefg┌──────────────────┐123456789
|
||||
11:abcdefg│BOTTOM │123456789
|
||||
│ │
|
||||
|
||||
@@ -5,8 +5,8 @@ base
|
||||
|
||||
|
||||
|
||||
┌──────────
|
||||
│CLIP
|
||||
│
|
||||
│
|
||||
│
|
||||
|
||||
┌─────────
|
||||
│CLIP
|
||||
│
|
||||
│
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
01:abcdefghijklmnopqrstuvwxyz0123456789
|
||||
02:abcdefghijklmnopqrstuvwxyz0123456789
|
||||
──────────┐ijklmnopqrstuvwxyz0123456789
|
||||
│ijklmnopqrstuvwxyz0123456789
|
||||
│ijklmnopqrstuvwxyz0123456789
|
||||
│ijklmnopqrstuvwxyz0123456789
|
||||
│ijklmnopqrstuvwxyz0123456789
|
||||
│ijklmnopqrstuvwxyz0123456789
|
||||
│ijklmnopqrstuvwxyz0123456789
|
||||
──────────┘ijklmnopqrstuvwxyz0123456789
|
||||
03:abcdefghijklmnopqrstuvwxyz0123456789
|
||||
─────────┐hijklmnopqrstuvwxyz0123456789
|
||||
│hijklmnopqrstuvwxyz0123456789
|
||||
│hijklmnopqrstuvwxyz0123456789
|
||||
│hijklmnopqrstuvwxyz0123456789
|
||||
│hijklmnopqrstuvwxyz0123456789
|
||||
─────────┘hijklmnopqrstuvwxyz0123456789
|
||||
10:abcdefghijklmnopqrstuvwxyz0123456789
|
||||
11:abcdefghijklmnopqrstuvwxyz0123456789
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
01:abcdefghijklmnopqrstuvwxyz0123456789
|
||||
02:abcdefghijklmnopqrstuvwxyz0123456789
|
||||
03:abcdefghijklmnopqrstuvwxyz┌──────────
|
||||
04:abcdefghijklmnopqrstuvwxyz│RIGHT
|
||||
05:abcdefghijklmnopqrstuvwxyz│
|
||||
06:abcdefghijklmnopqrstuvwxyz│
|
||||
07:abcdefghijklmnopqrstuvwxyz│
|
||||
08:abcdefghijklmnopqrstuvwxyz│
|
||||
09:abcdefghijklmnopqrstuvwxyz│
|
||||
10:abcdefghijklmnopqrstuvwxyz└──────────
|
||||
03:abcdefghijklmnopqrstuvwxyz0123456789
|
||||
04:abcdefghijklmnopqrstuvwxyz0┌─────────
|
||||
05:abcdefghijklmnopqrstuvwxyz0│RIGHT
|
||||
06:abcdefghijklmnopqrstuvwxyz0│
|
||||
07:abcdefghijklmnopqrstuvwxyz0│
|
||||
08:abcdefghijklmnopqrstuvwxyz0│
|
||||
09:abcdefghijklmnopqrstuvwxyz0└─────────
|
||||
10:abcdefghijklmnopqrstuvwxyz0123456789
|
||||
11:abcdefghijklmnopqrstuvwxyz0123456789
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
01:abcdef│ │23456789
|
||||
02:abcdef│ │23456789
|
||||
03:abcdef│ │23456789
|
||||
04:abcdef└────────────────────┘23456789
|
||||
01:abcdefg│ │123456789
|
||||
02:abcdefg│ │123456789
|
||||
03:abcdefg└──────────────────┘123456789
|
||||
04:abcdefghijklmnopqrstuvwxyz0123456789
|
||||
05:abcdefghijklmnopqrstuvwxyz0123456789
|
||||
06:abcdefghijklmnopqrstuvwxyz0123456789
|
||||
07:abcdefghijklmnopqrstuvwxyz0123456789
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
│
|
||||
│
|
||||
│
|
||||
│
|
||||
──────────────┘
|
||||
│
|
||||
│
|
||||
│
|
||||
─────────────┘
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
········································
|
||||
········································
|
||||
·······┌────────────────────┐···········
|
||||
·······│FLOAT │···········
|
||||
·······│ │···········
|
||||
·······│ │···········
|
||||
·······│ │···········
|
||||
·······│ │···········
|
||||
·······│ │···········
|
||||
·······└────────────────────┘···········
|
||||
········································
|
||||
········┌──────────────────┐············
|
||||
········│FLOAT │············
|
||||
········│ │············
|
||||
········│ │············
|
||||
········│ │············
|
||||
········└──────────────────┘············
|
||||
········································
|
||||
········································
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
ba┌── one ─────────┐
|
||||
│ONE │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
└──────────────┏━━━━━━━━━━━━━━━━┓
|
||||
┃TWO ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┃ ┃
|
||||
┗━━ two ━━━━━━━━━┛
|
||||
base
|
||||
┌── one ───────┐
|
||||
│ONE │
|
||||
│ │
|
||||
└──────────────┘
|
||||
|
||||
┏━━━━━━━━━━━━━━┓
|
||||
┃TWO ┃
|
||||
┃ ┃
|
||||
┗━━ two ━━━━━━━┛
|
||||
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
base │···········
|
||||
│···········
|
||||
│···········
|
||||
┌──────────│···········
|
||||
│OUT │···········
|
||||
│ │···········
|
||||
│ │···········
|
||||
│ │···········
|
||||
────────────────────────────┘···········
|
||||
│···········
|
||||
┌─────────│···········
|
||||
│OUT │···········
|
||||
│ │···········
|
||||
│ │···········
|
||||
──────────────────└─────────┘···········
|
||||
········································
|
||||
········································
|
||||
········································
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
base [30m[47m
|
||||
[39m[49m [30m[47m
|
||||
[39m[49m [32m┌────────────────┐[30m[47m
|
||||
[39m[49m [32m│[39mOVERSB [30m[47m [32m[49m│[30m[47m
|
||||
[39m[49m [32m│[39m [30m[47m [32m[49m│[30m[47m
|
||||
[39m[49m [32m│[39m [30m[47m [32m[49m│[30m[47m
|
||||
[39m[49m [32m│[39m [30m[47m [32m[49m│[30m[47m
|
||||
[39m[49m [32m│[39m [30m[47m [32m[49m│[30m[47m
|
||||
[39m[49m [32m│[39m [30m[47m [32m[49m│[30m[47m
|
||||
[39m[49m [32m└────────────────┘[30m[47m
|
||||
[39m[49m [30m[47m
|
||||
[39m[49m [38;2;143;188;143m┌──────────────┐[39m [30m[47m
|
||||
[39m[49m [38;2;143;188;143m│[39mOVERSB [30m[47m [38;2;143;188;143m[49m│[39m [30m[47m
|
||||
[39m[49m [38;2;143;188;143m│[39m [30m[47m [38;2;143;188;143m[49m│[39m [30m[47m
|
||||
[39m[49m [38;2;143;188;143m│[39m [30m[47m [38;2;143;188;143m[49m│[39m [30m[47m
|
||||
[39m[49m [38;2;143;188;143m│[39m [30m[47m [38;2;143;188;143m[49m│[39m [30m[47m
|
||||
[39m[49m [38;2;143;188;143m└──────────────┘[39m [30m[47m
|
||||
[39m[49m [30m[47m
|
||||
[39m[49m [30m[47m
|
||||
[39m[49m [30m[47m
|
||||
|
||||
@@ -4,9 +4,9 @@ base
|
||||
|
||||
|
||||
|
||||
┌────────────────────┐
|
||||
│OVERST │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
|
||||
┌──────────────────┐
|
||||
│OVERST │
|
||||
│ │
|
||||
│ │
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
TILE01 abcdefghij │TILE01 abcdefghij
|
||||
TILE02 abcdefghij │TILE02 abcdefghij
|
||||
TILE03 abc╔════════════════╗bcdefghij
|
||||
TILE04 abc║FLT ║bcdefghij
|
||||
║ ║
|
||||
──────────║ ║────────────
|
||||
TILE00 abc║ ║bcdefghij
|
||||
TILE01 abc║ ║bcdefghij
|
||||
TILE02 abc║ ║bcdefghij
|
||||
TILE03 abc╚════════════════╝bcdefghij
|
||||
TILE03 abcdefghij │TILE03 abcdefghij
|
||||
TILE04 abcd╔══════════════╗abcdefghij
|
||||
║FLT ║
|
||||
───────────║ ║─────────────
|
||||
TILE00 abcd║ ║abcdefghij
|
||||
TILE01 abcd║ ║abcdefghij
|
||||
TILE02 abcd╚══════════════╝abcdefghij
|
||||
TILE03 abcdefghij │TILE03 abcdefghij
|
||||
TILE04 abcdefghij │TILE04 abcdefghij
|
||||
│
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
TILE01 abcdefghij │TILE01 abcdefghij
|
||||
TILE02 abcdefghij │TILE02 abcdefghij
|
||||
TILE03 abc┌────────────────┐bcdefghij
|
||||
TILE04 abc│FLT │bcdefghij
|
||||
│ │
|
||||
──────────│ │────────────
|
||||
TILE00 abc│ │bcdefghij
|
||||
TILE01 abc│ │bcdefghij
|
||||
TILE02 abc│ │bcdefghij
|
||||
TILE03 abc└────────────────┘bcdefghij
|
||||
TILE03 abcdefghij │TILE03 abcdefghij
|
||||
TILE04 abcd┌──────────────┐abcdefghij
|
||||
│FLT │
|
||||
───────────│ │─────────────
|
||||
TILE00 abcd│ │abcdefghij
|
||||
TILE01 abcd│ │abcdefghij
|
||||
TILE02 abcd└──────────────┘abcdefghij
|
||||
TILE03 abcdefghij │TILE03 abcdefghij
|
||||
TILE04 abcdefghij │TILE04 abcdefghij
|
||||
│
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
base
|
||||
┌────────────────┐
|
||||
│AAA │
|
||||
│ │
|
||||
│ │
|
||||
│ ┌────────────────┐
|
||||
│ │BBB │
|
||||
│ │ │
|
||||
└─────────│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
|
||||
┌──────────────┐
|
||||
│AAA │
|
||||
│ │
|
||||
│ │
|
||||
│ ┌──────────────┐
|
||||
└─────────│BBB │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
└──────────────┘
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
── base ────────────────────────────────
|
||||
base ┌── title ───────────┐
|
||||
│FLOAT │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
└────────────────────┘
|
||||
base
|
||||
┌── title ─────────┐
|
||||
│FLOAT │
|
||||
│ │
|
||||
│ │
|
||||
│ │
|
||||
└──────────────────┘
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
|
||||
|
||||
[7m[32m┌────────────────────┐[0m
|
||||
[7m[32m│[0m [7m[32m│[0m
|
||||
[7m[32m│[0m [7m[32m│[0m
|
||||
[7m[32m│[0m [7m[32m│[0m
|
||||
[7m[32m│[0m [7m[32m│[0m
|
||||
[7m[32m│[0m [7m[32m│[0m
|
||||
[7m[32m│[0m [7m[32m│[0m
|
||||
[7m[32m└────────────────────┘[0m
|
||||
|
||||
[7m[38;2;147;112;219m┌──────────────────┐[0m
|
||||
[7m[38;2;147;112;219m│[0m [7m[38;2;147;112;219m│[0m
|
||||
[7m[38;2;147;112;219m│[0m [7m[38;2;147;112;219m│[0m
|
||||
[7m[38;2;147;112;219m│[0m [7m[38;2;147;112;219m│[0m
|
||||
[7m[38;2;147;112;219m│[0m [7m[38;2;147;112;219m│[0m
|
||||
[7m[38;2;147;112;219m└──────────────────┘[0m
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
[7m[32m│[0m
|
||||
[7m[32m│[0m
|
||||
[7m[32m│[0m
|
||||
[7m[32m│[0m
|
||||
[7m[32m│[0m
|
||||
[7m[32m│[0m
|
||||
[7m[32m│[0m
|
||||
[7m[32m│[0m
|
||||
[7m[32m│[0m
|
||||
[7m[32m│[0m
|
||||
[7m[32m│[0m
|
||||
[7m[32m│[0m
|
||||
[7m[38;2;143;188;143m│[0m
|
||||
[7m[38;2;143;188;143m│[0m
|
||||
[7m[38;2;143;188;143m│[0m
|
||||
[7m[38;2;143;188;143m│[0m
|
||||
[7m[38;2;143;188;143m│[0m
|
||||
[7m[38;2;143;188;143m│[0m
|
||||
[7m[38;2;143;188;143m│[0m
|
||||
[7m[38;2;143;188;143m│[0m
|
||||
[7m[38;2;143;188;143m│[0m
|
||||
[7m[38;2;143;188;143m│[0m
|
||||
[7m[38;2;143;188;143m│[0m
|
||||
[7m[38;2;143;188;143m│[0m
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
[32m── 0:left ──────────[7m┬[39m──[0m 1:right ────────
|
||||
[7m[32m│[0m
|
||||
[7m[32m│[0m
|
||||
[7m[32m│[0m
|
||||
[7m[32m│[0m
|
||||
[7m[32m│[0m
|
||||
[7m[32m│[0m
|
||||
[7m[32m│[0m
|
||||
[7m[32m│[0m
|
||||
[7m[32m│[0m
|
||||
[7m[32m│[0m
|
||||
[7m[32m│[0m
|
||||
[38;2;143;188;143m── 0:left ──────────[7m┬[38;2;179;179;179m──[0m[38;2;179;179;179m 1:right ────────
|
||||
[39m [7m[38;2;143;188;143m│[0m
|
||||
[7m[38;2;143;188;143m│[0m
|
||||
[7m[38;2;143;188;143m│[0m
|
||||
[7m[38;2;143;188;143m│[0m
|
||||
[7m[38;2;143;188;143m│[0m
|
||||
[7m[38;2;143;188;143m│[0m
|
||||
[7m[38;2;143;188;143m│[0m
|
||||
[7m[38;2;143;188;143m│[0m
|
||||
[7m[38;2;143;188;143m│[0m
|
||||
[7m[38;2;143;188;143m│[0m
|
||||
[7m[38;2;143;188;143m│[0m
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
|
||||
|
||||
[7m[32m────────────────────────────────────────
|
||||
[7m[38;2;143;188;143m────────────────────────────────────────
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
[7m[32m│[0m [7m│[0m
|
||||
[7m[32m│[0m [7m│[0m
|
||||
[7m[32m│[0m [7m│[0m
|
||||
[7m[32m│[0m [7m│[0m
|
||||
[7m[32m│[0m [7m│[0m
|
||||
[7m[32m│[0m [7m│[0m
|
||||
[7m[32m│[0m [7m│[0m
|
||||
[7m[32m│[0m [7m│[0m
|
||||
[7m[32m│[0m [7m│[0m
|
||||
[7m[32m│[0m [7m│[0m
|
||||
[7m[32m│[0m [7m│[0m
|
||||
[7m[32m│[0m [7m│[0m
|
||||
[7m[38;2;143;188;143m│[0m [7m[38;2;179;179;179m│[0m
|
||||
[7m[38;2;143;188;143m│[0m [7m[38;2;179;179;179m│[0m
|
||||
[7m[38;2;143;188;143m│[0m [7m[38;2;179;179;179m│[0m
|
||||
[7m[38;2;143;188;143m│[0m [7m[38;2;179;179;179m│[0m
|
||||
[7m[38;2;143;188;143m│[0m [7m[38;2;179;179;179m│[0m
|
||||
[7m[38;2;143;188;143m│[0m [7m[38;2;179;179;179m│[0m
|
||||
[7m[38;2;143;188;143m│[0m [7m[38;2;179;179;179m│[0m
|
||||
[7m[38;2;143;188;143m│[0m [7m[38;2;179;179;179m│[0m
|
||||
[7m[38;2;143;188;143m│[0m [7m[38;2;179;179;179m│[0m
|
||||
[7m[38;2;143;188;143m│[0m [7m[38;2;179;179;179m│[0m
|
||||
[7m[38;2;143;188;143m│[0m [7m[38;2;179;179;179m│[0m
|
||||
[7m[38;2;143;188;143m│[0m [7m[38;2;179;179;179m│[0m
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
SB00 abcdefghij [30m[47m
|
||||
[39m[49mSB01 abcdefghij [30m[47m
|
||||
[39m[49mSB02 ab[32m┌────────────────────┐[39m [30m[47m
|
||||
[39m[49mSB03 ab[32m│[39mFLOAT00 abcdef [30m[47m [32m[49m│[39m [30m[47m
|
||||
[39m[49mSB04 ab[32m│[39mFLOAT01 abcdef [30m[47m [32m[49m│[39m [30m[47m
|
||||
[39m[49mSB05 ab[32m│[39mFLOAT02 abcdef [30m[47m [32m[49m│[39m [30m[47m
|
||||
[39m[49mSB06 ab[32m│[39mFLOAT03 abcdef [30m[47m [32m[49m│[39m [30m[47m
|
||||
[39m[49mSB07 ab[32m│[39mFLOAT04 abcdef [30m[47m [32m[49m│[39m [30m[47m
|
||||
[39m[49mSB08 ab[32m│[39m [30m[47m [32m[49m│[39m [30m[47m
|
||||
[39m[49mSB09 ab[32m└────────────────────┘[39m [30m[47m
|
||||
[39m[49mSB02 abcdefghij [30m[47m
|
||||
[39m[49mSB03 abc[38;2;143;188;143m┌──────────────────┐[39m [30m[47m
|
||||
[39m[49mSB04 abc[38;2;143;188;143m│[39mFLOAT02 abcdef [37m[40m [38;2;143;188;143m[49m│[39m [30m[47m
|
||||
[39m[49mSB05 abc[38;2;143;188;143m│[39mFLOAT03 abcdef [37m[40m [38;2;143;188;143m[49m│[39m [30m[47m
|
||||
[39m[49mSB06 abc[38;2;143;188;143m│[39mFLOAT04 abcdef [30m[47m [38;2;143;188;143m[49m│[39m [30m[47m
|
||||
[39m[49mSB07 abc[38;2;143;188;143m│[39m [30m[47m [38;2;143;188;143m[49m│[39m [30m[47m
|
||||
[39m[49mSB08 abc[38;2;143;188;143m└──────────────────┘[39m [30m[47m
|
||||
[39m[49mSB09 abcdefghij [30m[47m
|
||||
[39m[49mSB10 abcdefghij [30m[47m
|
||||
[39m[49m [30m[47m
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
[30m[47m [39m[49mSB00 abcdefghij [32m│[30m[47m [39m[49mSBL00 abcdefghij
|
||||
[30m[47m [39m[49mSB01 abcdefghij [32m│[30m[47m [39m[49mSBL01 abcdefghij
|
||||
[30m[47m [39m[49mSB02 abcdefghij [32m│[30m[47m [39m[49mSBL02 abcdefghij
|
||||
[30m[47m [39m[49mSB03 abcdefghij [32m│[30m[47m [39m[49mSBL03 abcdefghij
|
||||
[30m[47m [39m[49mSB04 abcdefghij [32m│[30m[47m [39m[49mSBL04 abcdefghij
|
||||
[30m[47m [39m[49mSB05 abcdefghij [32m│[30m[47m [39m[49mSBL05 abcdefghij
|
||||
[30m[47m [39m[49mSB06 abcdefghij [32m│[30m[47m [39m[49mSBL06 abcdefghij
|
||||
[30m[47m [39m[49mSB07 abcdefghij │[30m[47m [39m[49mSBL07 abcdefghij
|
||||
[30m[47m [39m[49mSB08 abcdefghij │[30m[47m [39m[49mSBL08 abcdefghij
|
||||
[30m[47m [39m[49mSB09 abcdefghij │[30m[47m [39m[49mSBL09 abcdefghij
|
||||
[30m[47m [39m[49mSB10 abcdefghij │[30m[47m [39m[49mSBL10 abcdefghij
|
||||
[30m[47m [39m[49m │[30m[47m [39m[49m
|
||||
[30m[47m [39m[49mSB00 abcdefghij [38;2;143;188;143m│[30m[47m [39m[49mSBL00 abcdefghij
|
||||
[30m[47m [39m[49mSB01 abcdefghij [38;2;143;188;143m│[30m[47m [39m[49mSBL01 abcdefghij
|
||||
[30m[47m [39m[49mSB02 abcdefghij [38;2;143;188;143m│[30m[47m [39m[49mSBL02 abcdefghij
|
||||
[30m[47m [39m[49mSB03 abcdefghij [38;2;143;188;143m│[30m[47m [39m[49mSBL03 abcdefghij
|
||||
[30m[47m [39m[49mSB04 abcdefghij [38;2;143;188;143m│[30m[47m [39m[49mSBL04 abcdefghij
|
||||
[30m[47m [39m[49mSB05 abcdefghij [38;2;143;188;143m│[30m[47m [39m[49mSBL05 abcdefghij
|
||||
[30m[47m [39m[49mSB06 abcdefghij [38;2;143;188;143m│[30m[47m [39m[49mSBL06 abcdefghij
|
||||
[30m[47m [39m[49mSB07 abcdefghij [38;2;179;179;179m│[30m[47m [39m[49mSBL07 abcdefghij
|
||||
[30m[47m [39m[49mSB08 abcdefghij [38;2;179;179;179m│[30m[47m [39m[49mSBL08 abcdefghij
|
||||
[30m[47m [39m[49mSB09 abcdefghij [38;2;179;179;179m│[30m[47m [39m[49mSBL09 abcdefghij
|
||||
[30m[47m [39m[49mSB10 abcdefghij [38;2;179;179;179m│[30m[47m [39m[49mSBL10 abcdefghij
|
||||
[30m[47m [39m[49m [38;2;179;179;179m│[30m[47m [39m[49m
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
SB00 abcdefghij [30m[47m [32m[49m│[39mSBR00 abcdefghij [30m[47m
|
||||
[39m[49mSB01 abcdefghij [30m[47m [32m[49m│[39mSBR01 abcdefghij [30m[47m
|
||||
[39m[49mSB02 abcdefghij [30m[47m [32m[49m│[39mSBR02 abcdefghij [30m[47m
|
||||
[39m[49mSB03 abcdefghij [30m[47m [32m[49m│[39mSBR03 abcdefghij [30m[47m
|
||||
[39m[49mSB04 abcdefghij [30m[47m [32m[49m│[39mSBR04 abcdefghij [30m[47m
|
||||
[39m[49mSB05 abcdefghij [30m[47m [32m[49m│[39mSBR05 abcdefghij [30m[47m
|
||||
[39m[49mSB06 abcdefghij [30m[47m [32m[49m│[39mSBR06 abcdefghij [30m[47m
|
||||
[39m[49mSB07 abcdefghij [30m[47m [39m[49m│SBR07 abcdefghij [30m[47m
|
||||
[39m[49mSB08 abcdefghij [30m[47m [39m[49m│SBR08 abcdefghij [30m[47m
|
||||
[39m[49mSB09 abcdefghij [30m[47m [39m[49m│SBR09 abcdefghij [30m[47m
|
||||
[39m[49mSB10 abcdefghij [30m[47m [39m[49m│SBR10 abcdefghij [30m[47m
|
||||
[39m[49m [30m[47m [39m[49m│ [30m[47m
|
||||
SB00 abcdefghij [30m[47m [38;2;143;188;143m[49m│[39mSBR00 abcdefghij [30m[47m
|
||||
[39m[49mSB01 abcdefghij [30m[47m [38;2;143;188;143m[49m│[39mSBR01 abcdefghij [30m[47m
|
||||
[39m[49mSB02 abcdefghij [30m[47m [38;2;143;188;143m[49m│[39mSBR02 abcdefghij [30m[47m
|
||||
[39m[49mSB03 abcdefghij [30m[47m [38;2;143;188;143m[49m│[39mSBR03 abcdefghij [30m[47m
|
||||
[39m[49mSB04 abcdefghij [30m[47m [38;2;143;188;143m[49m│[39mSBR04 abcdefghij [30m[47m
|
||||
[39m[49mSB05 abcdefghij [30m[47m [38;2;143;188;143m[49m│[39mSBR05 abcdefghij [30m[47m
|
||||
[39m[49mSB06 abcdefghij [30m[47m [38;2;143;188;143m[49m│[39mSBR06 abcdefghij [30m[47m
|
||||
[39m[49mSB07 abcdefghij [30m[47m [38;2;179;179;179m[49m│[39mSBR07 abcdefghij [30m[47m
|
||||
[39m[49mSB08 abcdefghij [30m[47m [38;2;179;179;179m[49m│[39mSBR08 abcdefghij [30m[47m
|
||||
[39m[49mSB09 abcdefghij [30m[47m [38;2;179;179;179m[49m│[39mSBR09 abcdefghij [30m[47m
|
||||
[39m[49mSB10 abcdefghij [30m[47m [38;2;179;179;179m[49m│[39mSBR10 abcdefghij [30m[47m
|
||||
[39m[49m [30m[47m [38;2;179;179;179m[49m│[39m [30m[47m
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
[41mSTYLE00 abcdefghij [32m[49m│[39m[44mSTYLE00 abcdefghij
|
||||
[41mSTYLE01 abcdefghij [32m[49m│[39m[44mSTYLE01 abcdefghij
|
||||
[41mSTYLE02 abcdefghij [32m[49m│[39m[44mSTYLE02 abcdefghij
|
||||
[41mSTYLE03 abcdefghij [32m[49m│[39m[44mSTYLE03 abcdefghij
|
||||
[41mSTYLE04 abcdefghij [32m[49m│[39m[44mSTYLE04 abcdefghij
|
||||
[41mSTYLE05 abcdefghij [49m│[44mSTYLE05 abcdefghij
|
||||
[41mSTYLE06 abcdefghij [49m│[44mSTYLE06 abcdefghij
|
||||
[41m [49m│[44m
|
||||
[41mSTYLE00 abcdefghij [38;2;143;188;143m[49m│[39m[44mSTYLE00 abcdefghij
|
||||
[41mSTYLE01 abcdefghij [38;2;143;188;143m[49m│[39m[44mSTYLE01 abcdefghij
|
||||
[41mSTYLE02 abcdefghij [38;2;143;188;143m[49m│[39m[44mSTYLE02 abcdefghij
|
||||
[41mSTYLE03 abcdefghij [38;2;143;188;143m[49m│[39m[44mSTYLE03 abcdefghij
|
||||
[41mSTYLE04 abcdefghij [38;2;143;188;143m[49m│[39m[44mSTYLE04 abcdefghij
|
||||
[41mSTYLE05 abcdefghij [38;2;179;179;179m[49m│[39m[44mSTYLE05 abcdefghij
|
||||
[41mSTYLE06 abcdefghij [38;2;179;179;179m[49m│[39m[44mSTYLE06 abcdefghij
|
||||
[41m [38;2;179;179;179m[49m│[39m[44m
|
||||
|
||||
3
regsub.c
3
regsub.c
@@ -24,7 +24,8 @@
|
||||
#include "tmux.h"
|
||||
|
||||
static void
|
||||
regsub_copy(char **buf, ssize_t *len, const char *text, size_t start, size_t end)
|
||||
regsub_copy(char **buf, ssize_t *len, const char *text, size_t start,
|
||||
size_t end)
|
||||
{
|
||||
size_t add = end - start;
|
||||
|
||||
|
||||
2895
screen-redraw.c
2895
screen-redraw.c
File diff suppressed because it is too large
Load Diff
@@ -732,19 +732,19 @@ screen_write_hline(struct screen_write_ctx *ctx, u_int nx, int left, int right,
|
||||
gc.attr |= GRID_ATTR_CHARSET;
|
||||
|
||||
if (left)
|
||||
screen_write_box_border_set(lines, CELL_LEFTJOIN, &gc);
|
||||
screen_write_box_border_set(lines, CELL_URD, &gc);
|
||||
else
|
||||
screen_write_box_border_set(lines, CELL_LEFTRIGHT, &gc);
|
||||
screen_write_box_border_set(lines, CELL_LR, &gc);
|
||||
screen_write_cell(ctx, &gc);
|
||||
|
||||
screen_write_box_border_set(lines, CELL_LEFTRIGHT, &gc);
|
||||
screen_write_box_border_set(lines, CELL_LR, &gc);
|
||||
for (i = 1; i < nx - 1; i++)
|
||||
screen_write_cell(ctx, &gc);
|
||||
|
||||
if (right)
|
||||
screen_write_box_border_set(lines, CELL_RIGHTJOIN, &gc);
|
||||
screen_write_box_border_set(lines, CELL_ULD, &gc);
|
||||
else
|
||||
screen_write_box_border_set(lines, CELL_LEFTRIGHT, &gc);
|
||||
screen_write_box_border_set(lines, CELL_LR, &gc);
|
||||
screen_write_cell(ctx, &gc);
|
||||
|
||||
screen_write_set_cursor(ctx, cx, cy);
|
||||
@@ -752,7 +752,8 @@ screen_write_hline(struct screen_write_ctx *ctx, u_int nx, int left, int right,
|
||||
|
||||
/* Draw a vertical line on screen. */
|
||||
void
|
||||
screen_write_vline(struct screen_write_ctx *ctx, u_int ny, int top, int bottom)
|
||||
screen_write_vline(struct screen_write_ctx *ctx, u_int ny, int top, int bottom,
|
||||
const struct grid_cell *gcp)
|
||||
{
|
||||
struct screen *s = ctx->s;
|
||||
struct grid_cell gc;
|
||||
@@ -761,7 +762,10 @@ screen_write_vline(struct screen_write_ctx *ctx, u_int ny, int top, int bottom)
|
||||
cx = s->cx;
|
||||
cy = s->cy;
|
||||
|
||||
memcpy(&gc, &grid_default_cell, sizeof gc);
|
||||
if (gcp != NULL)
|
||||
memcpy(&gc, gcp, sizeof gc);
|
||||
else
|
||||
memcpy(&gc, &grid_default_cell, sizeof gc);
|
||||
gc.attr |= GRID_ATTR_CHARSET;
|
||||
|
||||
screen_write_putc(ctx, &gc, top ? 'w' : 'x');
|
||||
@@ -847,26 +851,26 @@ screen_write_box(struct screen_write_ctx *ctx, u_int nx, u_int ny,
|
||||
gc.flags |= GRID_FLAG_NOPALETTE;
|
||||
|
||||
/* Draw top border */
|
||||
screen_write_box_border_set(lines, CELL_TOPLEFT, &gc);
|
||||
screen_write_box_border_set(lines, CELL_RD, &gc);
|
||||
screen_write_cell(ctx, &gc);
|
||||
screen_write_box_border_set(lines, CELL_LEFTRIGHT, &gc);
|
||||
screen_write_box_border_set(lines, CELL_LR, &gc);
|
||||
for (i = 1; i < nx - 1; i++)
|
||||
screen_write_cell(ctx, &gc);
|
||||
screen_write_box_border_set(lines, CELL_TOPRIGHT, &gc);
|
||||
screen_write_box_border_set(lines, CELL_LD, &gc);
|
||||
screen_write_cell(ctx, &gc);
|
||||
|
||||
/* Draw bottom border */
|
||||
screen_write_set_cursor(ctx, cx, cy + ny - 1);
|
||||
screen_write_box_border_set(lines, CELL_BOTTOMLEFT, &gc);
|
||||
screen_write_box_border_set(lines, CELL_RU, &gc);
|
||||
screen_write_cell(ctx, &gc);
|
||||
screen_write_box_border_set(lines, CELL_LEFTRIGHT, &gc);
|
||||
screen_write_box_border_set(lines, CELL_LR, &gc);
|
||||
for (i = 1; i < nx - 1; i++)
|
||||
screen_write_cell(ctx, &gc);
|
||||
screen_write_box_border_set(lines, CELL_BOTTOMRIGHT, &gc);
|
||||
screen_write_box_border_set(lines, CELL_LU, &gc);
|
||||
screen_write_cell(ctx, &gc);
|
||||
|
||||
/* Draw sides */
|
||||
screen_write_box_border_set(lines, CELL_TOPBOTTOM, &gc);
|
||||
screen_write_box_border_set(lines, CELL_UD, &gc);
|
||||
for (i = 1; i < ny - 1; i++) {
|
||||
/* left side */
|
||||
screen_write_set_cursor(ctx, cx, cy + i);
|
||||
@@ -1523,6 +1527,7 @@ screen_write_clearline(struct screen_write_ctx *ctx, u_int bg)
|
||||
struct grid_line *gl;
|
||||
u_int sx = screen_size_x(s);
|
||||
struct screen_write_citem *ci = ctx->item;
|
||||
u_int flags;
|
||||
|
||||
gl = grid_get_line(s->grid, s->grid->hsize + s->cy);
|
||||
if (gl->cellsize == 0 && COLOUR_DEFAULT(bg))
|
||||
@@ -1533,7 +1538,10 @@ screen_write_clearline(struct screen_write_ctx *ctx, u_int bg)
|
||||
ctx->wp->flags |= PANE_REDRAW;
|
||||
#endif
|
||||
|
||||
flags = gl->flags & (GRID_LINE_START_PROMPT|GRID_LINE_START_OUTPUT);
|
||||
grid_view_clear(s->grid, 0, s->cy, sx, 1, bg);
|
||||
gl = grid_get_line(s->grid, s->grid->hsize + s->cy);
|
||||
gl->flags |= flags;
|
||||
|
||||
screen_write_collect_clear(ctx, s->cy, 1);
|
||||
ci->x = 0;
|
||||
@@ -2180,6 +2188,10 @@ screen_write_collect_flush_scrolled(struct screen_write_ctx *ctx)
|
||||
screen_write_redraw_pane(ctx, &ttyctx);
|
||||
return 0;
|
||||
}
|
||||
if (wp != NULL && window_pane_scrollbar_overlay_visible(wp)) {
|
||||
wp->flags |= PANE_REDRAW;
|
||||
return 0;
|
||||
}
|
||||
|
||||
log_debug("%s: scrolled %u (region %u-%u)", __func__, ctx->scrolled,
|
||||
s->rupper, s->rlower);
|
||||
@@ -2193,7 +2205,7 @@ screen_write_collect_flush_scrolled(struct screen_write_ctx *ctx)
|
||||
tty_write(tty_cmd_scrollup, &ttyctx);
|
||||
|
||||
if (wp != NULL)
|
||||
wp->flags |= PANE_REDRAWSCROLLBAR;
|
||||
window_pane_scrollbar_redraw(wp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
17
screen.c
17
screen.c
@@ -190,10 +190,11 @@ screen_reset_tabs(struct screen *s)
|
||||
void
|
||||
screen_set_default_cursor(struct screen *s, struct options *oo)
|
||||
{
|
||||
int c;
|
||||
struct grid_cell gc;
|
||||
int c;
|
||||
|
||||
c = options_get_number(oo, "cursor-colour");
|
||||
s->default_ccolour = c;
|
||||
style_apply(&gc, oo, "cursor-colour", NULL);
|
||||
s->default_ccolour = gc.fg;
|
||||
|
||||
c = options_get_number(oo, "cursor-style");
|
||||
s->default_mode = 0;
|
||||
@@ -249,10 +250,7 @@ screen_set_title(struct screen *s, const char *title, int untrusted)
|
||||
{
|
||||
char *new_title;
|
||||
|
||||
if (untrusted)
|
||||
new_title = clean_name(title, "#");
|
||||
else
|
||||
new_title = clean_name(title, "");
|
||||
new_title = clean_name(title, untrusted);
|
||||
if (new_title == NULL)
|
||||
return (0);
|
||||
free(s->title);
|
||||
@@ -266,10 +264,7 @@ screen_set_path(struct screen *s, const char *path, int untrusted)
|
||||
{
|
||||
char *new_path;
|
||||
|
||||
if (untrusted)
|
||||
new_path = clean_name(path, "#");
|
||||
else
|
||||
new_path = clean_name(path, "");
|
||||
new_path = clean_name(path, untrusted);
|
||||
if (new_path == NULL)
|
||||
return (0);
|
||||
free(s->path);
|
||||
|
||||
341
server-client.c
341
server-client.c
@@ -48,6 +48,8 @@ static void server_client_dispatch(struct imsg *, void *);
|
||||
static int server_client_dispatch_command(struct client *, struct imsg *);
|
||||
static int server_client_dispatch_identify(struct client *, struct imsg *);
|
||||
static int server_client_dispatch_shell(struct client *);
|
||||
static void server_client_update_scrollbar_hover(struct client *, int, int,
|
||||
int);
|
||||
static void server_client_report_theme(struct client *, enum client_theme);
|
||||
|
||||
/* Compare client windows. */
|
||||
@@ -287,6 +289,7 @@ struct client *
|
||||
server_client_create(int fd)
|
||||
{
|
||||
struct client *c;
|
||||
u_int i;
|
||||
|
||||
setblocking(fd, 0);
|
||||
|
||||
@@ -309,6 +312,9 @@ server_client_create(int fd)
|
||||
|
||||
c->tty.sx = 80;
|
||||
c->tty.sy = 24;
|
||||
|
||||
for (i = 0; i < COLOUR_THEME_COUNT; i++)
|
||||
c->theme_colours[i] = 8;
|
||||
c->theme = THEME_UNKNOWN;
|
||||
|
||||
status_init(c);
|
||||
@@ -360,6 +366,7 @@ server_client_open(struct client *c, char **cause)
|
||||
if (tty_open(&c->tty, cause) != 0)
|
||||
return (-1);
|
||||
|
||||
server_client_update_theme_colours(c);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -485,10 +492,7 @@ server_client_lost(struct client *c)
|
||||
free(c->message_string);
|
||||
if (event_initialized(&c->message_timer))
|
||||
evtimer_del(&c->message_timer);
|
||||
|
||||
free(c->prompt_saved);
|
||||
free(c->prompt_string);
|
||||
free(c->prompt_buffer);
|
||||
prompt_free(c->prompt);
|
||||
|
||||
format_lost_client(c);
|
||||
environ_free(c->environ);
|
||||
@@ -530,6 +534,7 @@ server_client_free(__unused int fd, __unused short events, void *arg)
|
||||
|
||||
log_debug("free client %p (%d references)", c, c->references);
|
||||
|
||||
redraw_free_scene(c->redraw_scene);
|
||||
cmdq_free(c->queue);
|
||||
|
||||
if (c->references == 0) {
|
||||
@@ -598,6 +603,58 @@ server_client_exec(struct client *c, const char *cmd)
|
||||
free(msg);
|
||||
}
|
||||
|
||||
/* Is this point inside the auto-hide scrollbar interaction area? */
|
||||
static int
|
||||
server_client_in_scrollbar_area(struct window_pane *wp, int px, int py)
|
||||
{
|
||||
struct window *w = wp->window;
|
||||
u_int width, pad, total;
|
||||
int start, end;
|
||||
|
||||
if (!window_pane_scrollbar_overlay(wp))
|
||||
return (0);
|
||||
if (py < wp->yoff || py >= wp->yoff + (int)wp->sy)
|
||||
return (0);
|
||||
|
||||
width = wp->scrollbar_style.width;
|
||||
pad = wp->scrollbar_style.pad;
|
||||
total = width + pad;
|
||||
if (total == 0 || total > wp->sx)
|
||||
total = wp->sx;
|
||||
|
||||
if (w->sb_pos == PANE_SCROLLBARS_LEFT) {
|
||||
start = wp->xoff;
|
||||
end = wp->xoff + (int)total - 1;
|
||||
} else {
|
||||
end = wp->xoff + (int)wp->sx - 1;
|
||||
start = end - (int)total + 1;
|
||||
}
|
||||
return (px >= start && px <= end);
|
||||
}
|
||||
|
||||
/* Update auto-hide scrollbars for a mouse movement. */
|
||||
static void
|
||||
server_client_update_scrollbar_hover(struct client *c, int type, int px, int py)
|
||||
{
|
||||
struct window *w = c->session->curw->window;
|
||||
struct window_pane *wp;
|
||||
|
||||
if (type != KEYC_TYPE_MOUSEMOVE)
|
||||
return;
|
||||
|
||||
TAILQ_FOREACH(wp, &w->panes, entry) {
|
||||
if (!window_pane_is_visible(wp))
|
||||
continue;
|
||||
if (server_client_in_scrollbar_area(wp, px, py)) {
|
||||
wp->sb_auto_hover = 1;
|
||||
window_pane_scrollbar_show(wp, 1);
|
||||
} else {
|
||||
wp->sb_auto_hover = 0;
|
||||
window_pane_scrollbar_start_timer(wp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Is the mouse inside a pane? */
|
||||
static enum key_code_mouse_location
|
||||
server_client_check_mouse_in_pane(struct window_pane *wp, int px, int py,
|
||||
@@ -605,17 +662,19 @@ server_client_check_mouse_in_pane(struct window_pane *wp, int px, int py,
|
||||
{
|
||||
struct window *w = wp->window;
|
||||
struct window_pane *fwp;
|
||||
int pane_status, sb, sb_pos, sb_w, sb_pad;
|
||||
int pane_status, sb_w, sb_pad;
|
||||
int pane_status_line, sl_top, sl_bottom;
|
||||
int bdr_bottom, bdr_top, bdr_left, bdr_right;
|
||||
int sb_start, sb_end, sb_overlay;
|
||||
|
||||
sb = options_get_number(w->options, "pane-scrollbars");
|
||||
sb_pos = options_get_number(w->options, "pane-scrollbars-position");
|
||||
pane_status = window_pane_get_pane_status(wp);
|
||||
sb_overlay = window_pane_scrollbar_overlay(wp);
|
||||
|
||||
if (window_pane_show_scrollbar(wp, sb)) {
|
||||
if (window_pane_scrollbar_visible(wp)) {
|
||||
sb_w = wp->scrollbar_style.width;
|
||||
sb_pad = wp->scrollbar_style.pad;
|
||||
if (sb_overlay && sb_w > (int)wp->sx)
|
||||
sb_w = wp->sx;
|
||||
} else {
|
||||
sb_w = 0;
|
||||
sb_pad = 0;
|
||||
@@ -628,23 +687,48 @@ server_client_check_mouse_in_pane(struct window_pane *wp, int px, int py,
|
||||
else
|
||||
pane_status_line = -1; /* not used */
|
||||
bdr_left = wp->xoff - 1;
|
||||
if (sb_pos == PANE_SCROLLBARS_LEFT)
|
||||
if (!sb_overlay && w->sb_pos == PANE_SCROLLBARS_LEFT)
|
||||
bdr_left -= sb_pad + sb_w;
|
||||
|
||||
if (sb_overlay && sb_w != 0 &&
|
||||
py >= wp->yoff && py < wp->yoff + (int)wp->sy &&
|
||||
px >= wp->xoff && px < wp->xoff + (int)wp->sx) {
|
||||
if (w->sb_pos == PANE_SCROLLBARS_LEFT) {
|
||||
sb_start = wp->xoff;
|
||||
sb_end = sb_start + sb_w - 1;
|
||||
} else {
|
||||
sb_end = wp->xoff + (int)wp->sx - 1;
|
||||
sb_start = sb_end - sb_w + 1;
|
||||
}
|
||||
if (px >= sb_start && px <= sb_end) {
|
||||
sl_top = wp->yoff + wp->sb_slider_y;
|
||||
sl_bottom = (wp->yoff + wp->sb_slider_y +
|
||||
wp->sb_slider_h - 1);
|
||||
if (py < sl_top)
|
||||
return (KEYC_MOUSE_LOCATION_SCROLLBAR_UP);
|
||||
else if (py >= sl_top && py <= sl_bottom) {
|
||||
*sl_mpos = (py - wp->sb_slider_y - wp->yoff);
|
||||
return (KEYC_MOUSE_LOCATION_SCROLLBAR_SLIDER);
|
||||
} else
|
||||
return (KEYC_MOUSE_LOCATION_SCROLLBAR_DOWN);
|
||||
}
|
||||
return (KEYC_MOUSE_LOCATION_PANE);
|
||||
}
|
||||
|
||||
/* Check if point is within the pane or scrollbar. */
|
||||
if (((pane_status != PANE_STATUS_OFF &&
|
||||
py != pane_status_line && py != wp->yoff + (int)wp->sy) ||
|
||||
(wp->yoff == 0 && py < (int)wp->sy) ||
|
||||
(py >= wp->yoff && py < wp->yoff + (int)wp->sy)) &&
|
||||
((sb_pos == PANE_SCROLLBARS_RIGHT &&
|
||||
((w->sb_pos == PANE_SCROLLBARS_RIGHT &&
|
||||
px < wp->xoff + (int)wp->sx + sb_pad + sb_w) ||
|
||||
(sb_pos == PANE_SCROLLBARS_LEFT &&
|
||||
(w->sb_pos == PANE_SCROLLBARS_LEFT &&
|
||||
px < wp->xoff + (int)wp->sx - sb_pad - sb_w))) {
|
||||
/* Check if in the scrollbar. */
|
||||
if ((sb_pos == PANE_SCROLLBARS_RIGHT &&
|
||||
if ((w->sb_pos == PANE_SCROLLBARS_RIGHT &&
|
||||
(px >= wp->xoff + (int)wp->sx + sb_pad &&
|
||||
px < wp->xoff + (int)wp->sx + sb_pad + sb_w)) ||
|
||||
(sb_pos == PANE_SCROLLBARS_LEFT &&
|
||||
(w->sb_pos == PANE_SCROLLBARS_LEFT &&
|
||||
(px >= wp->xoff - sb_pad - sb_w &&
|
||||
px < wp->xoff - sb_pad))) {
|
||||
/* Check where inside the scrollbar. */
|
||||
@@ -678,7 +762,7 @@ server_client_check_mouse_in_pane(struct window_pane *wp, int px, int py,
|
||||
if (window_pane_is_floating(fwp) &&
|
||||
window_pane_get_pane_lines(fwp) == PANE_LINES_NONE)
|
||||
continue;
|
||||
if (window_pane_show_scrollbar(fwp, sb)) {
|
||||
if (window_pane_scrollbar_reserve(fwp)) {
|
||||
sb_w = fwp->scrollbar_style.width;
|
||||
sb_pad = fwp->scrollbar_style.pad;
|
||||
} else {
|
||||
@@ -688,7 +772,7 @@ server_client_check_mouse_in_pane(struct window_pane *wp, int px, int py,
|
||||
bdr_top = fwp->yoff - 1;
|
||||
bdr_bottom = fwp->yoff + fwp->sy;
|
||||
bdr_left = fwp->xoff - 1;
|
||||
if (sb_pos == PANE_SCROLLBARS_LEFT) {
|
||||
if (w->sb_pos == PANE_SCROLLBARS_LEFT) {
|
||||
bdr_left -= sb_pad + sb_w;
|
||||
bdr_right = fwp->xoff + fwp->sx;
|
||||
} else {
|
||||
@@ -908,10 +992,14 @@ have_event:
|
||||
tty_window_offset(&c->tty, &m->ox, &m->oy, &sx, &sy);
|
||||
log_debug("mouse window @%u at %u,%u (%ux%u)",
|
||||
w->id, m->ox, m->oy, sx, sy);
|
||||
if (px > sx || py > sy)
|
||||
if (px > sx || py > sy) {
|
||||
server_client_update_scrollbar_hover(c, type,
|
||||
-1, -1);
|
||||
return (KEYC_UNKNOWN);
|
||||
}
|
||||
px = px + m->ox;
|
||||
py = py + m->oy;
|
||||
server_client_update_scrollbar_hover(c, type, px, py);
|
||||
|
||||
if (type == KEYC_TYPE_MOUSEDRAG && lwp != NULL) {
|
||||
/* Use pane from last mouse event. */
|
||||
@@ -944,7 +1032,8 @@ have_event:
|
||||
m->wp = wp->id;
|
||||
m->w = wp->window->id;
|
||||
}
|
||||
}
|
||||
} else
|
||||
server_client_update_scrollbar_hover(c, type, -1, -1);
|
||||
|
||||
/* Reset click type or add a click timer if needed. */
|
||||
if (type == KEYC_TYPE_MOUSEDOWN ||
|
||||
@@ -1079,6 +1168,52 @@ have_event:
|
||||
return (key);
|
||||
}
|
||||
|
||||
/* Update client theme colours from server options. */
|
||||
void
|
||||
server_client_update_theme_colours(struct client *c)
|
||||
{
|
||||
struct format_tree *ft;
|
||||
const char *name, *value;
|
||||
enum client_theme theme;
|
||||
char *expanded;
|
||||
u_int i;
|
||||
int colour, option;
|
||||
|
||||
if (c == NULL)
|
||||
return;
|
||||
|
||||
option = options_get_number(global_options, "theme");
|
||||
if (option == 1) {
|
||||
for (i = 0; i < COLOUR_THEME_COUNT; i++)
|
||||
c->theme_colours[i] = colour_theme_terminal_colour(i);
|
||||
return;
|
||||
}
|
||||
|
||||
ft = format_create(c, NULL, FORMAT_NONE, FORMAT_NOJOBS);
|
||||
format_defaults(ft, c, NULL, NULL, NULL);
|
||||
|
||||
theme = c->theme;
|
||||
if (option == 2)
|
||||
theme = THEME_LIGHT;
|
||||
else if (option == 3)
|
||||
theme = THEME_DARK;
|
||||
for (i = 0; i < COLOUR_THEME_COUNT; i++) {
|
||||
c->theme_colours[i] = 8;
|
||||
name = colour_theme_option(i, theme);
|
||||
if (name == NULL)
|
||||
continue;
|
||||
value = options_get_string(global_options, name);
|
||||
expanded = format_expand(ft, value);
|
||||
colour = colour_fromstring(expanded);
|
||||
free(expanded);
|
||||
if (colour == -1 || (colour & COLOUR_FLAG_THEME))
|
||||
continue;
|
||||
c->theme_colours[i] = colour;
|
||||
}
|
||||
|
||||
format_free(ft);
|
||||
}
|
||||
|
||||
/* Is this a bracket paste key? */
|
||||
static int
|
||||
server_client_is_bracket_paste(struct client *c, key_code key)
|
||||
@@ -1459,6 +1594,7 @@ server_client_handle_key0(struct client *c, struct key_event *event,
|
||||
{
|
||||
struct session *s = c->session;
|
||||
struct cmdq_item *item;
|
||||
struct window_pane *wp;
|
||||
|
||||
/* Check the client is good to accept input. */
|
||||
if (s == NULL || (c->flags & CLIENT_UNATTACHEDFLAGS))
|
||||
@@ -1488,6 +1624,7 @@ server_client_handle_key0(struct client *c, struct key_event *event,
|
||||
return (0);
|
||||
status_message_clear(c);
|
||||
}
|
||||
|
||||
if (c->overlay_key != NULL) {
|
||||
switch (c->overlay_key(c, c->overlay_data, event)) {
|
||||
case 0:
|
||||
@@ -1497,10 +1634,40 @@ server_client_handle_key0(struct client *c, struct key_event *event,
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
|
||||
server_client_clear_overlay(c);
|
||||
if (c->prompt_string != NULL) {
|
||||
if (status_prompt_key(c, event->key) == 0)
|
||||
if (c->prompt != NULL) {
|
||||
switch (status_prompt_key(c, event->key, &event->m)) {
|
||||
case PROMPT_KEY_HANDLED:
|
||||
case PROMPT_KEY_CLOSE:
|
||||
return (0);
|
||||
case PROMPT_KEY_NOT_HANDLED:
|
||||
case PROMPT_KEY_MOVE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
wp = s->curw->window->active;
|
||||
if (wp == NULL || !window_pane_has_prompt(wp)) {
|
||||
TAILQ_FOREACH(wp, &s->curw->window->panes, entry) {
|
||||
if (window_pane_has_prompt(wp) &&
|
||||
window_pane_is_visible(wp))
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (wp != NULL &&
|
||||
window_pane_has_prompt(wp) &&
|
||||
window_pane_is_visible(wp)) {
|
||||
switch (window_pane_prompt_key(wp, c, event->key, &event->m)) {
|
||||
case PROMPT_KEY_HANDLED:
|
||||
case PROMPT_KEY_CLOSE:
|
||||
case PROMPT_KEY_MOVE:
|
||||
return (0);
|
||||
case PROMPT_KEY_NOT_HANDLED:
|
||||
if (KEYC_IS_MOUSE(event->key))
|
||||
return (0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1773,6 +1940,42 @@ out:
|
||||
bufferevent_enable(wp->event, EV_READ);
|
||||
}
|
||||
|
||||
/* Move cursor for pane prompt. */
|
||||
static int
|
||||
server_client_prompt_cursor(struct client *c, struct window_pane *wp, int *mode,
|
||||
u_int *cx, u_int *cy)
|
||||
{
|
||||
struct tty *tty = &c->tty;
|
||||
struct visible_ranges *r;
|
||||
u_int ox, oy, sx, sy;
|
||||
int px, py;
|
||||
|
||||
if (!window_pane_has_prompt(wp))
|
||||
return (0);
|
||||
*mode &= ~MODE_CURSOR;
|
||||
|
||||
tty_window_offset(tty, &ox, &oy, &sx, &sy);
|
||||
if (status_at_line(c) == 0)
|
||||
py = wp->yoff;
|
||||
else
|
||||
py = wp->yoff + wp->sy - 1;
|
||||
px = wp->xoff + wp->prompt_cx;
|
||||
if (px < (int)ox || px > (int)(ox + sx) ||
|
||||
py < (int)oy || py > (int)(oy + sy))
|
||||
return (1);
|
||||
|
||||
*cx = px - ox;
|
||||
*cy = py - oy;
|
||||
|
||||
r = window_visible_ranges(wp, *cx, *cy, 1, NULL);
|
||||
if (window_position_is_visible(r, *cx)) {
|
||||
if (status_at_line(c) == 0)
|
||||
*cy += status_line_size(c);
|
||||
*mode |= MODE_CURSOR;
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Update cursor position and mode settings. The scroll region and attributes
|
||||
* are cleared when idle (waiting for an event) as this is the most likely time
|
||||
@@ -1791,7 +1994,8 @@ server_client_reset_state(struct client *c)
|
||||
struct screen *s = NULL;
|
||||
struct options *oo = c->session->options;
|
||||
int mode = 0, cursor, flags, pane_mode = 0;
|
||||
u_int cx = 0, cy = 0, ox, oy, sx, sy, n;
|
||||
u_int cx = 0, cy = 0, ox, oy, sx, sy, prompt = 0;
|
||||
u_int sb_w;
|
||||
struct visible_ranges *r;
|
||||
|
||||
if (c->flags & (CLIENT_CONTROL|CLIENT_SUSPENDED))
|
||||
@@ -1805,7 +2009,7 @@ server_client_reset_state(struct client *c)
|
||||
if (c->overlay_draw != NULL) {
|
||||
if (c->overlay_mode != NULL)
|
||||
s = c->overlay_mode(c, c->overlay_data, &cx, &cy);
|
||||
} else if (wp != NULL && c->prompt_string == NULL)
|
||||
} else if (wp != NULL && c->prompt == NULL)
|
||||
s = wp->screen;
|
||||
else
|
||||
s = c->status.active;
|
||||
@@ -1821,42 +2025,50 @@ server_client_reset_state(struct client *c)
|
||||
tty_margin_off(tty);
|
||||
|
||||
/* Move cursor to pane cursor and offset. */
|
||||
if (c->prompt_string != NULL) {
|
||||
n = options_get_number(oo, "status-position");
|
||||
if (n == 0)
|
||||
cy = status_prompt_line_at(c);
|
||||
else {
|
||||
n = status_line_size(c) - status_prompt_line_at(c);
|
||||
if (n <= tty->sy)
|
||||
cy = tty->sy - n;
|
||||
else
|
||||
cy = tty->sy - 1;
|
||||
}
|
||||
cx = c->prompt_cursor;
|
||||
if (c->prompt != NULL) {
|
||||
prompt = 1;
|
||||
status_prompt_cursor(c, &cx, &cy);
|
||||
} else if (wp != NULL && c->overlay_draw == NULL) {
|
||||
cursor = 0;
|
||||
pane_mode = wp->base.mode;
|
||||
prompt = server_client_prompt_cursor(c, wp, &mode, &cx, &cy);
|
||||
if (!prompt) {
|
||||
cursor = 0;
|
||||
pane_mode = wp->base.mode;
|
||||
|
||||
tty_window_offset(tty, &ox, &oy, &sx, &sy);
|
||||
if (wp->xoff + (int)s->cx >= (int)ox &&
|
||||
wp->xoff + (int)s->cx <= (int)ox + (int)sx &&
|
||||
wp->yoff + (int)s->cy >= (int)oy &&
|
||||
wp->yoff + (int)s->cy <= (int)oy + (int)sy) {
|
||||
cursor = 1;
|
||||
tty_window_offset(tty, &ox, &oy, &sx, &sy);
|
||||
if (wp->xoff + (int)s->cx >= (int)ox &&
|
||||
wp->xoff + (int)s->cx <= (int)ox + (int)sx &&
|
||||
wp->yoff + (int)s->cy >= (int)oy &&
|
||||
wp->yoff + (int)s->cy <= (int)oy + (int)sy) {
|
||||
cursor = 1;
|
||||
|
||||
cx = wp->xoff + (int)s->cx - (int)ox;
|
||||
cy = wp->yoff + (int)s->cy - (int)oy;
|
||||
cx = wp->xoff + (int)s->cx - (int)ox;
|
||||
cy = wp->yoff + (int)s->cy - (int)oy;
|
||||
|
||||
r = window_visible_ranges(wp, cx, cy, 1, NULL);
|
||||
if (!window_position_is_visible(r, cx))
|
||||
cursor = 0;
|
||||
r = window_visible_ranges(wp, cx, cy, 1, NULL);
|
||||
if (!window_position_is_visible(r, cx))
|
||||
cursor = 0;
|
||||
|
||||
if (status_at_line(c) == 0)
|
||||
cy += status_line_size(c);
|
||||
if (window_pane_scrollbar_overlay_visible(wp)) {
|
||||
sb_w = wp->scrollbar_style.width;
|
||||
if (sb_w > wp->sx)
|
||||
sb_w = wp->sx;
|
||||
if (sb_w != 0 &&
|
||||
w->sb_pos ==
|
||||
PANE_SCROLLBARS_LEFT) {
|
||||
if (s->cx < sb_w)
|
||||
cursor = 0;
|
||||
} else if (sb_w != 0 &&
|
||||
s->cx >= wp->sx - sb_w)
|
||||
cursor = 0;
|
||||
}
|
||||
|
||||
if (status_at_line(c) == 0)
|
||||
cy += status_line_size(c);
|
||||
}
|
||||
|
||||
if ((pane_mode & MODE_SYNC) || !cursor)
|
||||
mode &= ~MODE_CURSOR;
|
||||
}
|
||||
|
||||
if ((pane_mode & MODE_SYNC) || !cursor)
|
||||
mode &= ~MODE_CURSOR;
|
||||
} else if (c->overlay_mode == NULL || s == NULL)
|
||||
mode &= ~MODE_CURSOR;
|
||||
if (~pane_mode & MODE_SYNC) {
|
||||
@@ -1877,14 +2089,16 @@ server_client_reset_state(struct client *c)
|
||||
mode |= MODE_MOUSE_ALL;
|
||||
}
|
||||
}
|
||||
if (options_get_number(oo, "focus-follows-mouse"))
|
||||
mode |= MODE_MOUSE_ALL;
|
||||
if (options_get_number(oo, "focus-follows-mouse") ||
|
||||
w->sb == PANE_SCROLLBARS_MODAL ||
|
||||
w->sb == PANE_SCROLLBARS_AUTOHIDE)
|
||||
mode |= MODE_MOUSE_ALL;
|
||||
else if (~mode & MODE_MOUSE_ALL)
|
||||
mode |= MODE_MOUSE_BUTTON;
|
||||
}
|
||||
|
||||
/* Clear bracketed paste mode if at the prompt. */
|
||||
if (c->overlay_draw == NULL && c->prompt_string != NULL)
|
||||
if (c->overlay_draw == NULL && prompt)
|
||||
mode &= ~MODE_BRACKETPASTE;
|
||||
|
||||
/* Set the terminal mode and reset attributes. */
|
||||
@@ -2101,11 +2315,11 @@ server_client_check_redraw(struct client *c)
|
||||
if (wp->flags & PANE_REDRAW) {
|
||||
log_debug("%s: redraw pane %%%u", __func__,
|
||||
wp->id);
|
||||
screen_redraw_pane(c, wp, 0);
|
||||
redraw_pane(c, wp);
|
||||
} else if (wp->flags & PANE_REDRAWSCROLLBAR) {
|
||||
log_debug("%s: redraw scrollbar %%%u", __func__,
|
||||
wp->id);
|
||||
screen_redraw_pane(c, wp, 1);
|
||||
redraw_pane_scrollbar(c, wp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2120,7 +2334,7 @@ server_client_check_redraw(struct client *c)
|
||||
server_client_set_path(c);
|
||||
}
|
||||
server_client_set_progress_bar(c);
|
||||
screen_redraw_screen(c);
|
||||
redraw_screen(c);
|
||||
}
|
||||
|
||||
/* Put the tty back how it was. */
|
||||
@@ -2869,6 +3083,8 @@ out:
|
||||
static void
|
||||
server_client_report_theme(struct client *c, enum client_theme theme)
|
||||
{
|
||||
enum client_theme old = c->theme;
|
||||
|
||||
if (theme == THEME_LIGHT) {
|
||||
c->theme = THEME_LIGHT;
|
||||
notify_client("client-light-theme", c);
|
||||
@@ -2877,6 +3093,17 @@ server_client_report_theme(struct client *c, enum client_theme theme)
|
||||
notify_client("client-dark-theme", c);
|
||||
}
|
||||
|
||||
/*
|
||||
* If the theme has changed, update the theme colours and redraw the
|
||||
* client.
|
||||
*/
|
||||
if (c->theme != old) {
|
||||
server_client_update_theme_colours(c);
|
||||
if (c->tty.flags & TTY_OPENED)
|
||||
tty_invalidate(&c->tty);
|
||||
server_redraw_client(c);
|
||||
}
|
||||
|
||||
/*
|
||||
* Request foreground and background colour again. Don't forward 2031 to
|
||||
* panes until a response is received.
|
||||
|
||||
2
server.c
2
server.c
@@ -254,7 +254,7 @@ server_start(struct tmuxproc *client, uint64_t flags, struct event_base *base,
|
||||
proc_loop(server_proc, server_loop);
|
||||
|
||||
job_kill_all();
|
||||
status_prompt_save_history();
|
||||
prompt_save_history();
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
4
sort.c
4
sort.c
@@ -26,8 +26,8 @@
|
||||
static struct sort_criteria *sort_criteria;
|
||||
|
||||
static void
|
||||
sort_qsort(void *l, u_int len, u_int size, int (*cmp)(const void *, const void *),
|
||||
struct sort_criteria *sort_crit)
|
||||
sort_qsort(void *l, u_int len, u_int size, int (*cmp)(const void *,
|
||||
const void *), struct sort_criteria *sort_crit)
|
||||
{
|
||||
u_int i;
|
||||
void *tmp, **ll;
|
||||
|
||||
110
style.c
110
style.c
@@ -42,9 +42,17 @@ static struct style style_default = {
|
||||
|
||||
STYLE_WIDTH_DEFAULT, 0, STYLE_PAD_DEFAULT,
|
||||
|
||||
STYLE_DEFAULT_BASE
|
||||
STYLE_DEFAULT_BASE,
|
||||
|
||||
0
|
||||
};
|
||||
|
||||
/*
|
||||
* Global hyperlink set holding the URIs for #[link=...] styles, so a style
|
||||
* only needs to store a small ID rather than the URI itself.
|
||||
*/
|
||||
static struct hyperlinks *style_hyperlinks;
|
||||
|
||||
/* Set range string. */
|
||||
static void
|
||||
style_set_range_string(struct style *sy, const char *s)
|
||||
@@ -91,6 +99,7 @@ style_parse(struct style *sy, const struct grid_cell *base, const char *in)
|
||||
sy->gc.us = base->us;
|
||||
sy->gc.attr = base->attr;
|
||||
sy->gc.flags = base->flags;
|
||||
sy->link = 0;
|
||||
} else if (strcasecmp(tmp, "ignore") == 0)
|
||||
sy->ignore = 1;
|
||||
else if (strcasecmp(tmp, "noignore") == 0)
|
||||
@@ -234,7 +243,9 @@ style_parse(struct style *sy, const struct grid_cell *base, const char *in)
|
||||
} else if (strcasecmp(tmp, "none") == 0)
|
||||
sy->gc.attr = 0;
|
||||
else if (end > 2 && strncasecmp(tmp, "no", 2) == 0) {
|
||||
if (strcmp(tmp + 2, "attr") == 0)
|
||||
if (strcmp(tmp + 2, "link") == 0)
|
||||
sy->link = 0;
|
||||
else if (strcmp(tmp + 2, "attr") == 0)
|
||||
sy->gc.attr |= GRID_ATTR_NOATTR;
|
||||
else {
|
||||
value = attributes_fromstring(tmp + 2);
|
||||
@@ -262,6 +273,15 @@ style_parse(struct style *sy, const struct grid_cell *base, const char *in)
|
||||
if (errstr != NULL)
|
||||
goto error;
|
||||
sy->pad = (int)n;
|
||||
} else if (strncasecmp(tmp, "link=", 5) == 0) {
|
||||
if (tmp[5] == '\0')
|
||||
sy->link = 0;
|
||||
else {
|
||||
if (style_hyperlinks == NULL)
|
||||
style_hyperlinks = hyperlinks_init();
|
||||
sy->link = hyperlinks_put(style_hyperlinks,
|
||||
tmp + 5, tmp + 5);
|
||||
}
|
||||
} else {
|
||||
if ((value = attributes_fromstring(tmp)) == -1)
|
||||
goto error;
|
||||
@@ -284,8 +304,8 @@ style_tostring(struct style *sy)
|
||||
{
|
||||
struct grid_cell *gc = &sy->gc;
|
||||
int off = 0;
|
||||
const char *comma = "", *tmp = "";
|
||||
static char s[256];
|
||||
const char *comma = "", *tmp = "", *uri;
|
||||
static char s[2048];
|
||||
char b[21];
|
||||
|
||||
*s = '\0';
|
||||
@@ -389,15 +409,33 @@ style_tostring(struct style *sy)
|
||||
comma = ",";
|
||||
}
|
||||
if (sy->pad >= 0) {
|
||||
xsnprintf(s + off, sizeof s - off, "%spad=%u", comma,
|
||||
off += xsnprintf(s + off, sizeof s - off, "%spad=%u", comma,
|
||||
sy->pad);
|
||||
comma = ",";
|
||||
}
|
||||
uri = style_link(sy);
|
||||
if (uri != NULL) {
|
||||
xsnprintf(s + off, sizeof s - off, "%slink=%s", comma, uri);
|
||||
comma = ",";
|
||||
}
|
||||
if (*s == '\0')
|
||||
return ("default");
|
||||
return (s);
|
||||
}
|
||||
|
||||
/* Get the hyperlink URI for a style, or NULL if it has none. */
|
||||
const char *
|
||||
style_link(struct style *sy)
|
||||
{
|
||||
const char *uri;
|
||||
|
||||
if (sy->link == 0 || style_hyperlinks == NULL)
|
||||
return (NULL);
|
||||
if (!hyperlinks_get(style_hyperlinks, sy->link, &uri, NULL, NULL))
|
||||
return (NULL);
|
||||
return (uri);
|
||||
}
|
||||
|
||||
/* Apply a style on top of the given style. */
|
||||
struct style *
|
||||
style_add(struct grid_cell *gc, struct options *oo, const char *name,
|
||||
@@ -434,6 +472,29 @@ style_apply(struct grid_cell *gc, struct options *oo, const char *name,
|
||||
style_add(gc, oo, name, ft);
|
||||
}
|
||||
|
||||
/* Parse a single colour into a style */
|
||||
int
|
||||
style_parse_colour(struct style *sy, const struct grid_cell *base,
|
||||
const char *s)
|
||||
{
|
||||
int c;
|
||||
|
||||
style_set(sy, base);
|
||||
|
||||
if (*s == '\0') {
|
||||
sy->gc.fg = -1;
|
||||
return (0);
|
||||
}
|
||||
|
||||
if ((c = colour_fromstring(s)) == -1)
|
||||
return (-1);
|
||||
if (c == 8)
|
||||
sy->gc.fg = base->fg;
|
||||
else
|
||||
sy->gc.fg = c;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Initialize style from cell. */
|
||||
void
|
||||
style_set(struct style *sy, const struct grid_cell *gc)
|
||||
@@ -454,22 +515,33 @@ void
|
||||
style_set_scrollbar_style_from_option(struct style *sb_style,
|
||||
struct options *oo)
|
||||
{
|
||||
struct style *sy;
|
||||
const struct options_table_entry *oe;
|
||||
struct options_entry *o;
|
||||
const char *s;
|
||||
char *style, *expanded;
|
||||
|
||||
sy = options_string_to_style(oo, "pane-scrollbars-style", NULL);
|
||||
if (sy == NULL) {
|
||||
style_set(sb_style, &grid_default_cell);
|
||||
sb_style->width = PANE_SCROLLBARS_DEFAULT_WIDTH;
|
||||
sb_style->pad = PANE_SCROLLBARS_DEFAULT_PADDING;
|
||||
utf8_set(&sb_style->gc.data, PANE_SCROLLBARS_CHARACTER);
|
||||
} else {
|
||||
style_copy(sb_style, sy);
|
||||
if (sb_style->width < 1)
|
||||
sb_style->width = PANE_SCROLLBARS_DEFAULT_WIDTH;
|
||||
if (sb_style->pad < 0)
|
||||
sb_style->pad = PANE_SCROLLBARS_DEFAULT_PADDING;
|
||||
utf8_set(&sb_style->gc.data, PANE_SCROLLBARS_CHARACTER);
|
||||
style_set(sb_style, &grid_default_cell);
|
||||
o = options_get(oo, "pane-scrollbars-style");
|
||||
if (o == NULL)
|
||||
fatalx("missing pane-scrollbars-style");
|
||||
oe = options_table_entry(o);
|
||||
style = format_single(NULL, oe->default_str, NULL, NULL, NULL, NULL);
|
||||
if (style_parse(sb_style, &grid_default_cell, style) != 0)
|
||||
fatalx("bad pane-scrollbars-style default");
|
||||
|
||||
s = options_get_string(oo, "pane-scrollbars-style");
|
||||
if (s != NULL) {
|
||||
expanded = format_single(NULL, s, NULL, NULL, NULL, NULL);
|
||||
if (style_parse(sb_style, &grid_default_cell, expanded) != 0)
|
||||
style_parse(sb_style, &grid_default_cell, style);
|
||||
free(expanded);
|
||||
}
|
||||
free(style);
|
||||
if (sb_style->width < 1)
|
||||
sb_style->width = PANE_SCROLLBARS_DEFAULT_WIDTH;
|
||||
if (sb_style->pad < 0)
|
||||
sb_style->pad = PANE_SCROLLBARS_DEFAULT_PADDING;
|
||||
utf8_set(&sb_style->gc.data, PANE_SCROLLBARS_CHARACTER);
|
||||
}
|
||||
|
||||
/* Initialize style ranges. */
|
||||
|
||||
449
tmux.1
449
tmux.1
@@ -364,6 +364,8 @@ Choose the current window interactively.
|
||||
Kill the current pane.
|
||||
.It z
|
||||
Toggle zoom state of the current pane.
|
||||
.It Tab
|
||||
Choose a new window and session by fuzzy matching.
|
||||
.It {
|
||||
Move floating pane to top-left corner.
|
||||
.It }
|
||||
@@ -2744,6 +2746,15 @@ and
|
||||
.Fl Y
|
||||
options set the position of the upper-left corner of the pane.
|
||||
If omitted, new floating panes are cascaded from the top-left of the window.
|
||||
The
|
||||
.Fl x ,
|
||||
.Fl y ,
|
||||
.Fl X ,
|
||||
and
|
||||
.Fl Y
|
||||
options may be followed by
|
||||
.Ql %
|
||||
to specify a percentage of the window size.
|
||||
.Pp
|
||||
If the pane had previously been floating, the position and sizes are restored
|
||||
from the saved values not specified by the
|
||||
@@ -2873,9 +2884,11 @@ The following keys may be used in client mode:
|
||||
.It Li "z" Ta "Suspend selected client"
|
||||
.It Li "Z" Ta "Suspend tagged clients"
|
||||
.It Li "f" Ta "Enter a format to filter items"
|
||||
.It Li "c" Ta "Clear the current filter"
|
||||
.It Li "O" Ta "Change sort order"
|
||||
.It Li "r" Ta "Reverse sort order"
|
||||
.It Li "v" Ta "Toggle preview"
|
||||
.It Li "i" Ta "Change view (preview and client information)"
|
||||
.It Li "F1 or C\-h" Ta "Display help"
|
||||
.It Li "q" Ta "Exit mode"
|
||||
.El
|
||||
@@ -2968,11 +2981,12 @@ The following keys may be used in tree mode:
|
||||
.It Li "C\-t" Ta "Tag all items"
|
||||
.It Li "\&:" Ta "Run a command for each tagged item"
|
||||
.It Li "f" Ta "Enter a format to filter items"
|
||||
.It Li "c" Ta "Clear the current filter"
|
||||
.It Li "H" Ta "Jump to the starting pane"
|
||||
.It Li "O" Ta "Change sort order"
|
||||
.It Li "r" Ta "Reverse sort order"
|
||||
.It Li "v" Ta "Toggle preview"
|
||||
.It Li "i" Ta "Change view (preview and client information)"
|
||||
.It Li "i" Ta "Change view (preview and session, window and pane information)"
|
||||
.It Li "F1 or C\-h" Ta "Display help"
|
||||
.It Li "q" Ta "Exit mode"
|
||||
.El
|
||||
@@ -3066,6 +3080,7 @@ The following keys may be used in customize mode:
|
||||
.It Li "T" Ta "Tag no items"
|
||||
.It Li "C\-t" Ta "Tag all items"
|
||||
.It Li "f" Ta "Enter a format to filter items"
|
||||
.It Li "c" Ta "Clear the current filter"
|
||||
.It Li "v" Ta "Toggle option information"
|
||||
.It Li "F1 or C\-h" Ta "Display help"
|
||||
.It Li "q" Ta "Exit mode"
|
||||
@@ -3087,6 +3102,51 @@ The
|
||||
.Ic customize-mode
|
||||
command works only if at least one client is attached.
|
||||
.It Xo
|
||||
.Ic switch\-mode
|
||||
.Op Fl kswZ
|
||||
.Op Fl F Ar format
|
||||
.Op Fl t Ar target\-pane
|
||||
.Op Ar command
|
||||
.Xc
|
||||
Put a pane into switch mode, where a session or window may be chosen
|
||||
interactively from a list.
|
||||
Each session or window is shown on one line and the list is narrowed by typing:
|
||||
the typed text is matched against each item with fuzzy
|
||||
matching and only matching items are shown, sorted by how well they match.
|
||||
.Fl s
|
||||
lists sessions (the default) and
|
||||
.Fl w
|
||||
lists windows.
|
||||
.Fl Z
|
||||
zooms the pane.
|
||||
The following keys may be used in switch mode:
|
||||
.Bl -column "KeyXXX" "Function" -offset indent
|
||||
.It Sy "Key" Ta Sy "Function"
|
||||
.It Li "Enter" Ta "Choose the selected item"
|
||||
.It Li "Up" Ta "Select the previous item"
|
||||
.It Li "Down" Ta "Select the next item"
|
||||
.It Li "Escape" Ta "Exit mode"
|
||||
.El
|
||||
.Pp
|
||||
After a session or window is chosen, the first instance of
|
||||
.Ql %%
|
||||
and all instances of
|
||||
.Ql %1
|
||||
are replaced by the target in
|
||||
.Ar command
|
||||
and the result executed as a command.
|
||||
If
|
||||
.Ar command
|
||||
is not given, "switch\-client \-Zt \[aq]%%\[aq]" is used.
|
||||
.Fl F
|
||||
specifies the format for each item in the list.
|
||||
.Fl k
|
||||
kills the pane when the mode is exited.
|
||||
.Pp
|
||||
The appearance of matched characters is controlled by the
|
||||
.Ic switch\-mode\-match\-style
|
||||
option.
|
||||
.It Xo
|
||||
.Tg displayp
|
||||
.Ic display\-panes
|
||||
.Op Fl bN
|
||||
@@ -3571,7 +3631,7 @@ but a different format may be specified with
|
||||
.Fl F .
|
||||
.Tg newp
|
||||
.It Xo Ic new\-pane
|
||||
.Op Fl bdefhIkPvWZ
|
||||
.Op Fl bdefhIkLPvWZ
|
||||
.Op Fl B Ar border\-lines
|
||||
.Op Fl c Ar start\-directory
|
||||
.Op Fl e Ar environment
|
||||
@@ -3584,101 +3644,49 @@ but a different format may be specified with
|
||||
.Op Fl S Ar active\-border\-style
|
||||
.Op Fl t Ar target\-pane
|
||||
.Op Fl T Ar title
|
||||
.Op Fl x Ar width
|
||||
.Op Fl y Ar height
|
||||
.Op Fl X Ar x-position
|
||||
.Op Fl Y Ar y-position
|
||||
.Op Ar shell\-command Op Ar argument ...
|
||||
.Xc
|
||||
.D1 Pq alias: Ic newp
|
||||
Create a new pane.
|
||||
The new pane is created by splitting
|
||||
.Ar target\-pane .
|
||||
If
|
||||
.Fl d
|
||||
is given, the session does not make the new pane the current pane.
|
||||
.Fl Z
|
||||
zooms if the window is not zoomed, or keeps it zoomed if already zoomed.
|
||||
.Fl s
|
||||
sets the style for the pane content.
|
||||
.Fl S
|
||||
sets the border style when the pane is active and
|
||||
.Fl R
|
||||
sets the border style when the pane is inactive (see
|
||||
.Sx STYLES ) .
|
||||
.Fl T
|
||||
sets the pane title.
|
||||
Creates a new floating pane.
|
||||
The
|
||||
.Fl x
|
||||
and
|
||||
.Fl y
|
||||
options set the width and height of the floating pane in columns and lines
|
||||
respectively.
|
||||
The default is half the window width and a quarter the window height.
|
||||
The
|
||||
.Fl X
|
||||
and
|
||||
.Fl Y
|
||||
options set the position of the upper-left corner of the pane.
|
||||
If omitted, new floating panes are cascaded from the top-left of the window.
|
||||
The
|
||||
.Fl x ,
|
||||
.Fl y ,
|
||||
.Fl X ,
|
||||
and
|
||||
.Fl Y
|
||||
options may be followed by
|
||||
.Ql %
|
||||
to specify a percentage of the window size.
|
||||
.Fl B
|
||||
sets the pane border lines for floating panes; see
|
||||
.Ic pane\-border\-lines .
|
||||
.Pp
|
||||
.Fl h
|
||||
does a horizontal split and
|
||||
.Fl v
|
||||
a vertical split; if neither is specified,
|
||||
.Fl v
|
||||
is assumed.
|
||||
The
|
||||
.Fl l
|
||||
option specifies the size of the new pane in lines (for vertical split) or in
|
||||
columns (for horizontal split);
|
||||
.Ar size
|
||||
may be followed by
|
||||
.Ql %
|
||||
to specify a percentage of the available space.
|
||||
.Fl p
|
||||
is a shorthand option for this.
|
||||
The
|
||||
.Fl b
|
||||
option causes the new pane to be created to the left of or above
|
||||
.Ar target\-pane .
|
||||
The
|
||||
.Fl f
|
||||
option creates a new pane spanning the full window height (with
|
||||
.Fl h )
|
||||
or full window width (with
|
||||
.Fl v ) ,
|
||||
instead of splitting the active pane.
|
||||
.Pp
|
||||
.Fl k
|
||||
keeps the pane open after the optional
|
||||
.Ar shell\-command
|
||||
exits and waits for a key to be pressed before closing it.
|
||||
The message shown is controlled by the
|
||||
.Ic remain\-on\-exit\-format
|
||||
option.
|
||||
.Fl m Ar message
|
||||
is equivalent to
|
||||
.Fl k
|
||||
but also sets the
|
||||
.Ic remain\-on\-exit\-format
|
||||
option for this pane to
|
||||
.Ar message .
|
||||
.Pp
|
||||
.Fl W
|
||||
Waits until
|
||||
.Ar shell\-command
|
||||
exits, then returns its exit status.
|
||||
For example:
|
||||
.Bd -literal -offset indent
|
||||
$ tmux new-pane -W 'vi afile'
|
||||
$ echo $?
|
||||
0
|
||||
.Ed
|
||||
.Pp
|
||||
.Fl E ,
|
||||
or an empty
|
||||
.Ar shell\-command ,
|
||||
(\[aq]\[aq]) will create an empty pane with no command running in it;
|
||||
.Ic display-message
|
||||
.Fl I
|
||||
can write to an empty pane.
|
||||
The
|
||||
.Fl I
|
||||
flag will create an empty pane and forward any output from stdin to it.
|
||||
For example:
|
||||
.Bd -literal -offset indent
|
||||
$ make 2>&1|tmux splitw \-dI &
|
||||
.Ed
|
||||
.Fl L
|
||||
option makes
|
||||
.Ic new\-pane
|
||||
behave like
|
||||
.Ic split\-window .
|
||||
.Pp
|
||||
All other options have the same meaning as for the
|
||||
.Ic new\-window
|
||||
.Ic split\-window
|
||||
command.
|
||||
.Tg nextl
|
||||
.It Ic next\-layout Op Fl t Ar target\-window
|
||||
@@ -4033,14 +4041,92 @@ the command behaves like
|
||||
.Op Ar shell\-command Op Ar argument ...
|
||||
.Xc
|
||||
.D1 Pq alias: Ic splitw
|
||||
Creates a new pane by splitting
|
||||
Create a new pane by splitting
|
||||
.Ar target\-pane .
|
||||
Shares behavior with
|
||||
.Ic new\-pane .
|
||||
If
|
||||
.Fl d
|
||||
is given, the session does not make the new pane the current pane.
|
||||
.Fl Z
|
||||
zooms if the window is not zoomed, or keeps it zoomed if already zoomed.
|
||||
.Fl s
|
||||
sets the style for the pane content.
|
||||
.Fl S
|
||||
sets the border style when the pane is active and
|
||||
.Fl R
|
||||
sets the border style when the pane is inactive (see
|
||||
.Sx STYLES ) .
|
||||
.Fl T
|
||||
sets the pane title.
|
||||
.Pp
|
||||
.Fl h
|
||||
does a horizontal split and
|
||||
.Fl v
|
||||
a vertical split; if neither is specified,
|
||||
.Fl v
|
||||
is assumed.
|
||||
The
|
||||
.Fl l
|
||||
option specifies the size of the new pane in lines (for vertical split) or in
|
||||
columns (for horizontal split);
|
||||
.Ar size
|
||||
may be followed by
|
||||
.Ql %
|
||||
to specify a percentage of the available space.
|
||||
.Fl p
|
||||
is a shorthand option for this.
|
||||
The
|
||||
.Fl b
|
||||
option causes the new pane to be created to the left of or above
|
||||
.Ar target\-pane .
|
||||
The
|
||||
.Fl f
|
||||
option creates a new pane spanning the full window height (with
|
||||
.Fl h )
|
||||
or full window width (with
|
||||
.Fl v ) ,
|
||||
instead of splitting the active pane.
|
||||
.Pp
|
||||
.Fl k
|
||||
keeps the pane open after the optional
|
||||
.Ar shell\-command
|
||||
exits and waits for a key to be pressed before closing it.
|
||||
The message shown is controlled by the
|
||||
.Ic remain\-on\-exit\-format
|
||||
option.
|
||||
.Fl m Ar message
|
||||
is equivalent to
|
||||
.Fl k
|
||||
but also sets the
|
||||
.Ic remain\-on\-exit\-format
|
||||
option for this pane to
|
||||
.Ar message .
|
||||
.Pp
|
||||
.Fl W
|
||||
Waits until
|
||||
.Ar shell\-command
|
||||
exits, then returns its exit status.
|
||||
For example:
|
||||
.Bd -literal -offset indent
|
||||
$ tmux new-pane -W 'vi afile'
|
||||
$ echo $?
|
||||
0
|
||||
.Ed
|
||||
.Pp
|
||||
.Fl E ,
|
||||
or an empty
|
||||
.Ar shell\-command ,
|
||||
(\[aq]\[aq]) will create an empty pane with no command running in it;
|
||||
.Ic display-message
|
||||
.Fl I
|
||||
can write to an empty pane.
|
||||
The
|
||||
.Fl I
|
||||
flag will create an empty pane and forward any output from stdin to it.
|
||||
For example:
|
||||
.Bd -literal -offset indent
|
||||
$ make 2>&1|tmux new\-pane \-dI &
|
||||
.Ed
|
||||
.Pp
|
||||
See
|
||||
.Ic new\-pane
|
||||
for more details.
|
||||
.Tg swapp
|
||||
.It Xo Ic swap\-pane
|
||||
.Op Fl dDUZ
|
||||
@@ -4653,6 +4739,57 @@ where the number is a hexadecimal number, or a range of the form
|
||||
Give the command to pipe to if the
|
||||
.Ic copy\-pipe
|
||||
copy mode command is used without arguments.
|
||||
.It Xo Ic theme
|
||||
.Op Ic detect | terminal | light | dark
|
||||
.Xc
|
||||
Whether tmux should use the detected client theme
|
||||
.Pq Ic detect ,
|
||||
use terminal ANSI colours
|
||||
.Pq Ic terminal ,
|
||||
or force the light or dark theme.
|
||||
.It Xo Ic dark\-theme\-black ,
|
||||
.Ic dark\-theme\-white ,
|
||||
.Ic dark\-theme\-light\-grey ,
|
||||
.Ic dark\-theme\-dark\-grey ,
|
||||
.Ic dark\-theme\-green ,
|
||||
.Ic dark\-theme\-yellow ,
|
||||
.Ic dark\-theme\-red ,
|
||||
.Ic dark\-theme\-blue ,
|
||||
.Ic dark\-theme\-cyan ,
|
||||
.Ic dark\-theme\-magenta ,
|
||||
.Ic light\-theme\-black ,
|
||||
.Ic light\-theme\-white ,
|
||||
.Ic light\-theme\-light\-grey ,
|
||||
.Ic light\-theme\-dark\-grey ,
|
||||
.Ic light\-theme\-green ,
|
||||
.Ic light\-theme\-yellow ,
|
||||
.Ic light\-theme\-red ,
|
||||
.Ic light\-theme\-blue ,
|
||||
.Ic light\-theme\-cyan
|
||||
.No and Ic light\-theme\-magenta Ar colour
|
||||
.Xc
|
||||
Set the theme colours.
|
||||
These are the named colours
|
||||
.Ic themeblack ,
|
||||
.Ic themewhite ,
|
||||
.Ic themelightgrey ,
|
||||
.Ic themedarkgrey ,
|
||||
.Ic themegreen ,
|
||||
.Ic themeyellow ,
|
||||
.Ic themered ,
|
||||
.Ic themeblue ,
|
||||
.Ic themecyan
|
||||
and
|
||||
.Ic thememagenta
|
||||
which may be used in styles and elsewhere a
|
||||
.Ar colour
|
||||
is accepted.
|
||||
The
|
||||
.Ic dark\-theme\-*
|
||||
set is used when the client reports a dark background and the
|
||||
.Ic light\-theme\-*
|
||||
set when it reports a light background;
|
||||
an unknown background is treated as dark.
|
||||
.It Ic default\-client\-command Ar command
|
||||
Set the default command to run when tmux is called without a command.
|
||||
The default is
|
||||
@@ -5242,14 +5379,19 @@ is input before dismissing it.
|
||||
Can be set to zero to disable any timeout.
|
||||
.It Ic prompt\-cursor\-colour Ar colour
|
||||
Set the colour of the cursor in the command prompt.
|
||||
.It Ic prompt\-command\-cursor\-colour Ar colour
|
||||
Set the colour of the cursor in the command prompt when
|
||||
.Xr vi 1
|
||||
keys are enabled and the prompt is in command mode.
|
||||
.It Ic prompt\-cursor\-style Ar style
|
||||
Set the style of the cursor in the command prompt.
|
||||
See the
|
||||
.Ic cursor\-style
|
||||
options for available styles.
|
||||
.It Ic prompt\-command\-cursor\-style Ar style
|
||||
Set the style of the cursor in the command prompt when vi keys are enabled and
|
||||
the prompt is in command mode.
|
||||
Set the style of the cursor in the command prompt when
|
||||
.Xr vi 1
|
||||
keys are enabled and the prompt is in command mode.
|
||||
See the
|
||||
.Ic cursor\-style
|
||||
options for available styles.
|
||||
@@ -5834,7 +5976,7 @@ and
|
||||
will fall back to standard ACS line drawing when UTF\-8 is not supported.
|
||||
.Pp
|
||||
.It Xo Ic pane\-scrollbars
|
||||
.Op Ic off | modal | on
|
||||
.Op Ic off | modal | on | auto\-hide
|
||||
.Xc
|
||||
When enabled, a character based scrollbar appears on the left or right
|
||||
of each pane.
|
||||
@@ -5844,19 +5986,29 @@ represents the position and size of the visible part of the pane content.
|
||||
.Pp
|
||||
If set to
|
||||
.Ic on
|
||||
the scrollbar is visible all the time.
|
||||
the scrollbar is visible all the time and the pane is narrowed by the width of
|
||||
the scrollbar.
|
||||
If set to
|
||||
.Ic modal
|
||||
the scrollbar only appears when the pane is in copy mode or view mode.
|
||||
When the scrollbar is visible, the pane is narrowed by the width of the
|
||||
scrollbar and the text in the pane is reflowed.
|
||||
the scrollbar only appears when the pane is in copy mode or view mode and
|
||||
auto-hides when not in use.
|
||||
If set to
|
||||
.Ic modal ,
|
||||
the pane is narrowed only when the scrollbar is visible.
|
||||
.Ic auto\-hide
|
||||
the scrollbar is available all the time but auto-hides when not in use.
|
||||
With
|
||||
.Ic modal
|
||||
and
|
||||
.Ic auto\-hide ,
|
||||
the scrollbar overlays the pane and does not narrow or reflow the pane.
|
||||
.Pp
|
||||
See also
|
||||
.Ic pane\-scrollbars\-style .
|
||||
.Pp
|
||||
.It Xo Ic pane\-scrollbars\-position
|
||||
.Op Ic left | right
|
||||
.Xc
|
||||
Sets which side of the pane to display pane scrollbars on.
|
||||
.Pp
|
||||
.It Ic pane\-scrollbars\-style Ar style
|
||||
Set the scrollbars style.
|
||||
For how to specify
|
||||
@@ -5873,10 +6025,13 @@ attribute sets the width of the scrollbar and the
|
||||
attribute the padding between the scrollbar and the pane.
|
||||
Other attributes are ignored.
|
||||
.Pp
|
||||
.It Xo Ic pane\-scrollbars\-position
|
||||
.Op Ic left | right
|
||||
.Xc
|
||||
Sets which side of the pane to display pane scrollbars on.
|
||||
.It Ic pane\-scrollbars\-timeout Ar time
|
||||
Set the time in milliseconds before scrollbars are hidden when
|
||||
.Ic pane\-scrollbars
|
||||
is
|
||||
.Ic modal
|
||||
or
|
||||
.Ic auto\-hide .
|
||||
.Pp
|
||||
.It Ic pane\-status\-current\-style Ar style
|
||||
Set status line style for the currently active pane.
|
||||
@@ -5918,6 +6073,14 @@ A value of 0 (the default) means no limit.
|
||||
When a limit is set, panes are arranged to not exceed this number of columns,
|
||||
with additional panes stacked in extra rows.
|
||||
.Pp
|
||||
.It Ic tree\-mode\-border\-style Ar style
|
||||
Set the style of borders in tree mode.
|
||||
For how to specify
|
||||
.Ar style ,
|
||||
see the
|
||||
.Sx STYLES
|
||||
section.
|
||||
.Pp
|
||||
.It Ic tree\-mode\-preview\-format Ar format
|
||||
Format of the preview indicator in tree mode.
|
||||
.Pp
|
||||
@@ -5929,6 +6092,14 @@ see the
|
||||
.Sx STYLES
|
||||
section.
|
||||
.Pp
|
||||
.It Ic tree\-mode\-selection\-style Ar style
|
||||
Set the style of the selected line in tree mode.
|
||||
For how to specify
|
||||
.Ar style ,
|
||||
see the
|
||||
.Sx STYLES
|
||||
section.
|
||||
.Pp
|
||||
.It Ic window\-status\-activity\-style Ar style
|
||||
Set status line style for windows with an activity alert.
|
||||
For how to specify
|
||||
@@ -6108,6 +6279,15 @@ is enabled.
|
||||
When the entire screen is cleared and this option is on, scroll the contents of
|
||||
the screen into history before clearing it.
|
||||
.Pp
|
||||
.It Ic switch\-mode\-match\-style Ar style
|
||||
Set the style of characters matched by the filter in
|
||||
.Ic switch\-mode .
|
||||
For how to specify
|
||||
.Ar style ,
|
||||
see the
|
||||
.Sx STYLES
|
||||
section.
|
||||
.Pp
|
||||
.It Xo Ic synchronize\-panes
|
||||
.Op Ic on | off
|
||||
.Xc
|
||||
@@ -6500,13 +6680,36 @@ An optional argument specifies flags:
|
||||
.Ql r
|
||||
means the pattern is a regular expression instead of the default
|
||||
.Xr glob 7
|
||||
pattern, and
|
||||
pattern;
|
||||
.Ql i
|
||||
means to ignore case.
|
||||
means to ignore case;
|
||||
.Ql z
|
||||
means to do a fuzzy match;
|
||||
.Ql p
|
||||
is like
|
||||
.Ql z
|
||||
but returns a list of matched positions.
|
||||
A fuzzy match matches plain terms as sequences where each character must appear
|
||||
in order but not necessarily consecutively; terms beginning with
|
||||
.Ql '
|
||||
are exact substring matches,
|
||||
.Ql ^
|
||||
anchors a term at the start,
|
||||
.Ql $
|
||||
anchors it at the end,
|
||||
.Ql !
|
||||
inverts a term and
|
||||
.Ql |
|
||||
separates alternative groups.
|
||||
For example:
|
||||
.Ql #{m:*foo*,#{host}}
|
||||
or
|
||||
.Ql #{m/ri:\[ha]A,MYVAR} .
|
||||
.Ql #{m/ri:\[ha]A,MYVAR}
|
||||
or
|
||||
.Ql #{m/z:dev bash,dev:1 bash}
|
||||
or
|
||||
.Ql #{m/z:^dev | ^prod,prod:1 ssh} .
|
||||
.Pp
|
||||
A
|
||||
.Ql C
|
||||
performs a search for a
|
||||
@@ -6831,6 +7034,7 @@ The following variables are available, where appropriate:
|
||||
.It Li "client_activity" Ta "" Ta "Time client last had activity"
|
||||
.It Li "client_cell_height" Ta "" Ta "Height of each client cell in pixels"
|
||||
.It Li "client_cell_width" Ta "" Ta "Width of each client cell in pixels"
|
||||
.It Li "client_colours" Ta "" Ta "Number of colours client supports"
|
||||
.It Li "client_control_mode" Ta "" Ta "1 if client is in control mode"
|
||||
.It Li "client_created" Ta "" Ta "Time client created"
|
||||
.It Li "client_discarded" Ta "" Ta "Bytes discarded when client behind"
|
||||
@@ -7146,6 +7350,28 @@ Set the width of the styled area.
|
||||
.Ar N
|
||||
may be a column count or a percentage (for example
|
||||
.Ql 50% ) .
|
||||
.It Xo Ic link=uri
|
||||
(or
|
||||
.Ic nolink )
|
||||
.Xc
|
||||
Make the styled text an OSC 8 hyperlink to
|
||||
.Ar uri ,
|
||||
for example
|
||||
.Ql #[link=https://example.com]text#[nolink] .
|
||||
This is emitted only to terminals with the
|
||||
.Ic hyperlinks
|
||||
feature (see
|
||||
.Ic terminal-features ) ;
|
||||
it works in the status line and in other formats drawn with styles.
|
||||
The link continues until
|
||||
.Ic nolink ,
|
||||
.Ic default ,
|
||||
or an empty
|
||||
.Ic link=
|
||||
is given.
|
||||
The
|
||||
.Ar uri
|
||||
may not contain spaces or commas and is limited in length.
|
||||
.It Xo Ic list=on ,
|
||||
.Ic list=focus ,
|
||||
.Ic list=left\-marker ,
|
||||
@@ -7478,7 +7704,7 @@ See
|
||||
for possible values for
|
||||
.Ar prompt\-type .
|
||||
.It Xo Ic command\-prompt
|
||||
.Op Fl 1bCeFiklN
|
||||
.Op Fl 1bCeFiklNP
|
||||
.Op Fl I Ar inputs
|
||||
.Op Fl p Ar prompts
|
||||
.Op Fl t Ar target\-client
|
||||
@@ -7558,6 +7784,8 @@ user exits the command prompt.
|
||||
makes
|
||||
.Em BSpace
|
||||
cancel an empty prompt.
|
||||
.Fl P
|
||||
opens a prompt inside a pane instead of on the status line.
|
||||
.Pp
|
||||
.Fl T
|
||||
tells
|
||||
@@ -8016,6 +8244,7 @@ The following keys may be used in buffer mode:
|
||||
.It Li "D" Ta "Delete tagged buffers"
|
||||
.It Li "e" Ta "Open the buffer in an editor"
|
||||
.It Li "f" Ta "Enter a format to filter items"
|
||||
.It Li "c" Ta "Clear the current filter"
|
||||
.It Li "O" Ta "Change sort order"
|
||||
.It Li "r" Ta "Reverse sort order"
|
||||
.It Li "v" Ta "Toggle preview"
|
||||
|
||||
21
tmux.c
21
tmux.c
@@ -282,15 +282,15 @@ get_timer(void)
|
||||
}
|
||||
|
||||
char *
|
||||
clean_name(const char *name, const char* forbid)
|
||||
clean_name(const char *name, int untrusted)
|
||||
{
|
||||
char *copy, *cp, *new_name;
|
||||
|
||||
if (*name == '\0' || !utf8_isvalid(name))
|
||||
if (!utf8_isvalid(name))
|
||||
return (NULL);
|
||||
copy = xstrdup(name);
|
||||
for (cp = copy; *cp != '\0'; cp++) {
|
||||
if (strchr(forbid, *cp) != NULL)
|
||||
if (untrusted && cp[0] == '#' && cp[1] == '(')
|
||||
*cp = '_';
|
||||
}
|
||||
utf8_stravis(&new_name, copy, VIS_OCTAL|VIS_CSTYLE|VIS_TAB|VIS_NL);
|
||||
@@ -298,22 +298,11 @@ clean_name(const char *name, const char* forbid)
|
||||
return (new_name);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check a name given by a command: reject it if it is empty, not valid UTF-8,
|
||||
* or contains a forbidden character. Other characters that clean_name would
|
||||
* change (for example with utf8_stravis) are allowed and fixed silently.
|
||||
*/
|
||||
int
|
||||
check_name(const char *name, const char *forbid)
|
||||
check_name(const char *name)
|
||||
{
|
||||
const char *cp;
|
||||
|
||||
if (*name == '\0' || !utf8_isvalid(name))
|
||||
if (!utf8_isvalid(name))
|
||||
return (0);
|
||||
for (cp = name; *cp != '\0'; cp++) {
|
||||
if (strchr(forbid, *cp) != NULL)
|
||||
return (0);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
|
||||
|
||||
358
tmux.h
358
tmux.h
@@ -63,6 +63,10 @@ struct mouse_event;
|
||||
struct options;
|
||||
struct options_array_item;
|
||||
struct options_entry;
|
||||
struct prompt;
|
||||
struct window_pane_prompt;
|
||||
struct redraw_scene;
|
||||
struct redraw_span;
|
||||
struct screen_write_citem;
|
||||
struct screen_write_cline;
|
||||
struct screen_write_ctx;
|
||||
@@ -96,12 +100,6 @@ struct winlink;
|
||||
#define TMUX_LOCK_CMD "lock -np"
|
||||
#endif
|
||||
|
||||
/* Forbidden characters in names. */
|
||||
#define WINDOW_NAME_FORBID ":."
|
||||
#define WINDOW_NAME_FORBID_EXT ":.#"
|
||||
#define SESSION_NAME_FORBID ":."
|
||||
#define SESSION_NAME_FORBID_EXT ":.#"
|
||||
|
||||
/* Minimum and maximum layout cell size, NOT including border lines. */
|
||||
#define PANE_MINIMUM 1
|
||||
#define PANE_MAXIMUM 10000
|
||||
@@ -733,10 +731,26 @@ enum hanguljamo_state {
|
||||
/* Colour flags. */
|
||||
#define COLOUR_FLAG_256 0x01000000
|
||||
#define COLOUR_FLAG_RGB 0x02000000
|
||||
#define COLOUR_FLAG_THEME 0x04000000
|
||||
|
||||
/* Special colours. */
|
||||
#define COLOUR_DEFAULT(c) ((c) == 8 || (c) == 9)
|
||||
|
||||
/* Theme colours. */
|
||||
enum colour_theme {
|
||||
COLOUR_THEME_BLACK,
|
||||
COLOUR_THEME_WHITE,
|
||||
COLOUR_THEME_LIGHT_GREY,
|
||||
COLOUR_THEME_DARK_GREY,
|
||||
COLOUR_THEME_GREEN,
|
||||
COLOUR_THEME_YELLOW,
|
||||
COLOUR_THEME_RED,
|
||||
COLOUR_THEME_BLUE,
|
||||
COLOUR_THEME_CYAN,
|
||||
COLOUR_THEME_MAGENTA
|
||||
};
|
||||
#define COLOUR_THEME_COUNT 10
|
||||
|
||||
/* Replacement palette. */
|
||||
struct colour_palette {
|
||||
int fg;
|
||||
@@ -796,20 +810,23 @@ struct colour_palette {
|
||||
#define GRID_STRING_USED_ONLY 0x8
|
||||
#define GRID_STRING_EMPTY_CELLS 0x10
|
||||
|
||||
/* Cell positions. */
|
||||
/*
|
||||
* Cell border characters. Border cells are named for the directions they
|
||||
* connect to: U for up, D for down, L for left and R for right.
|
||||
*/
|
||||
#define CELL_INSIDE 0
|
||||
#define CELL_TOPBOTTOM 1
|
||||
#define CELL_LEFTRIGHT 2
|
||||
#define CELL_TOPLEFT 3
|
||||
#define CELL_TOPRIGHT 4
|
||||
#define CELL_BOTTOMLEFT 5
|
||||
#define CELL_BOTTOMRIGHT 6
|
||||
#define CELL_TOPJOIN 7
|
||||
#define CELL_BOTTOMJOIN 8
|
||||
#define CELL_LEFTJOIN 9
|
||||
#define CELL_RIGHTJOIN 10
|
||||
#define CELL_JOIN 11
|
||||
#define CELL_OUTSIDE 12
|
||||
#define CELL_UD 1
|
||||
#define CELL_LR 2
|
||||
#define CELL_RD 3
|
||||
#define CELL_LD 4
|
||||
#define CELL_RU 5
|
||||
#define CELL_LU 6
|
||||
#define CELL_LRD 7
|
||||
#define CELL_LRU 8
|
||||
#define CELL_URD 9
|
||||
#define CELL_ULD 10
|
||||
#define CELL_LRUD 11
|
||||
#define CELL_NONE 12
|
||||
#define CELL_SCROLLBAR 13
|
||||
|
||||
/* Cell borders. */
|
||||
@@ -970,6 +987,8 @@ struct style {
|
||||
int pad;
|
||||
|
||||
enum style_default_type default_type;
|
||||
|
||||
u_int link;
|
||||
};
|
||||
|
||||
#ifdef ENABLE_SIXEL
|
||||
@@ -1113,27 +1132,6 @@ enum pane_lines {
|
||||
#define WINDOW_PANE_COPY_MODE 1
|
||||
#define WINDOW_PANE_VIEW_MODE 2
|
||||
|
||||
/* Screen redraw context. */
|
||||
struct screen_redraw_ctx {
|
||||
struct client *c;
|
||||
|
||||
u_int statuslines;
|
||||
int statustop;
|
||||
|
||||
enum pane_lines pane_lines;
|
||||
|
||||
int pane_scrollbars;
|
||||
int pane_scrollbars_pos;
|
||||
|
||||
struct grid_cell no_pane_gc;
|
||||
int no_pane_gc_set;
|
||||
|
||||
u_int sx;
|
||||
u_int sy;
|
||||
int ox;
|
||||
int oy;
|
||||
};
|
||||
|
||||
/* Screen size. */
|
||||
#define screen_size_x(s) ((s)->grid->sx)
|
||||
#define screen_size_y(s) ((s)->grid->sy)
|
||||
@@ -1285,7 +1283,7 @@ struct window_pane {
|
||||
#define PANE_FOCUSED 0x4
|
||||
#define PANE_VISITED 0x8
|
||||
#define PANE_ZOOMED 0x10
|
||||
/* 0x20 unused */
|
||||
#define PANE_NEWSTATUS 0x20
|
||||
#define PANE_INPUTOFF 0x40
|
||||
#define PANE_CHANGED 0x80
|
||||
#define PANE_EXITED 0x100
|
||||
@@ -1305,6 +1303,9 @@ struct window_pane {
|
||||
|
||||
u_int sb_slider_y;
|
||||
u_int sb_slider_h;
|
||||
int sb_auto_visible;
|
||||
int sb_auto_hover;
|
||||
struct event sb_auto_timer;
|
||||
|
||||
int argc;
|
||||
char **argv;
|
||||
@@ -1347,13 +1348,16 @@ struct window_pane {
|
||||
struct screen base;
|
||||
|
||||
struct screen status_screen;
|
||||
size_t status_size;
|
||||
|
||||
TAILQ_HEAD(, window_mode_entry) modes;
|
||||
|
||||
char *searchstr;
|
||||
int searchregex;
|
||||
|
||||
struct prompt *prompt;
|
||||
struct window_pane_prompt *prompt_data;
|
||||
u_int prompt_cx;
|
||||
|
||||
int border_gc_set;
|
||||
struct grid_cell border_gc;
|
||||
int active_border_gc_set;
|
||||
@@ -1412,9 +1416,14 @@ struct window {
|
||||
u_int new_xpixel;
|
||||
u_int new_ypixel;
|
||||
|
||||
uint64_t redraw_scene_generation;
|
||||
|
||||
u_int last_new_pane_x;
|
||||
u_int last_new_pane_y;
|
||||
|
||||
int sb;
|
||||
int sb_pos;
|
||||
|
||||
struct utf8_data *fill_character;
|
||||
int flags;
|
||||
#define WINDOW_BELL 0x1
|
||||
@@ -1474,6 +1483,7 @@ TAILQ_HEAD(winlink_stack, winlink);
|
||||
#define PANE_SCROLLBARS_OFF 0
|
||||
#define PANE_SCROLLBARS_MODAL 1
|
||||
#define PANE_SCROLLBARS_ALWAYS 2
|
||||
#define PANE_SCROLLBARS_AUTOHIDE 3
|
||||
|
||||
/* Pane scrollbars position option. */
|
||||
#define PANE_SCROLLBARS_RIGHT 0
|
||||
@@ -1513,6 +1523,12 @@ struct layout_cell {
|
||||
int xoff, saved_xoff;
|
||||
int yoff, saved_yoff;
|
||||
|
||||
u_int saved_sx;
|
||||
u_int saved_sy;
|
||||
|
||||
int saved_xoff;
|
||||
int saved_yoff;
|
||||
|
||||
struct window_pane *wp;
|
||||
struct layout_cells cells;
|
||||
|
||||
@@ -2000,20 +2016,12 @@ struct status_line {
|
||||
struct screen *active;
|
||||
int references;
|
||||
|
||||
u_int prompt_cx;
|
||||
|
||||
struct grid_cell style;
|
||||
struct style_line_entry entries[STATUS_LINES_LIMIT];
|
||||
};
|
||||
|
||||
/* Prompt type. */
|
||||
#define PROMPT_NTYPES 4
|
||||
enum prompt_type {
|
||||
PROMPT_TYPE_COMMAND,
|
||||
PROMPT_TYPE_SEARCH,
|
||||
PROMPT_TYPE_TARGET,
|
||||
PROMPT_TYPE_WINDOW_TARGET,
|
||||
PROMPT_TYPE_INVALID = 0xff
|
||||
};
|
||||
|
||||
/* File in client. */
|
||||
typedef void (*client_file_cb) (struct client *, const char *, int, int,
|
||||
struct evbuffer *, void *);
|
||||
@@ -2054,18 +2062,98 @@ RB_HEAD(client_windows, client_window);
|
||||
/* Maximum time to be pasting. */
|
||||
#define CLIENT_PASTE_TIME_LIMIT 5
|
||||
|
||||
/* Client connection. */
|
||||
typedef int (*prompt_input_cb)(struct client *, void *, const char *, int);
|
||||
/* Prompt type. */
|
||||
#define PROMPT_NTYPES 2
|
||||
enum prompt_type {
|
||||
PROMPT_TYPE_COMMAND,
|
||||
PROMPT_TYPE_SEARCH,
|
||||
PROMPT_TYPE_INVALID = 0xff
|
||||
};
|
||||
|
||||
/* Prompt result. */
|
||||
enum prompt_result {
|
||||
PROMPT_CONTINUE,
|
||||
PROMPT_CLOSE
|
||||
};
|
||||
|
||||
/* Prompt key result. */
|
||||
enum prompt_key_result {
|
||||
PROMPT_KEY_NOT_HANDLED,
|
||||
PROMPT_KEY_HANDLED,
|
||||
PROMPT_KEY_CLOSE,
|
||||
PROMPT_KEY_MOVE
|
||||
};
|
||||
|
||||
/* Prompt callbacks. */
|
||||
typedef enum prompt_result (*prompt_input_cb)(void *, const char *,
|
||||
enum prompt_key_result);
|
||||
typedef enum prompt_result (*status_prompt_input_cb)(struct client *, void *,
|
||||
const char *, enum prompt_key_result);
|
||||
typedef enum prompt_result (*mode_tree_prompt_input_cb)(struct client *, void *,
|
||||
const char *, enum prompt_key_result);
|
||||
typedef void (*prompt_free_cb)(void *);
|
||||
typedef struct visible_ranges *(*overlay_check_cb)(struct client*, void *,
|
||||
|
||||
/* Prompt flags. */
|
||||
#define PROMPT_SINGLE 0x1
|
||||
#define PROMPT_NUMERIC 0x2
|
||||
#define PROMPT_INCREMENTAL 0x4
|
||||
#define PROMPT_NOFORMAT 0x8
|
||||
#define PROMPT_KEY 0x10
|
||||
#define PROMPT_ACCEPT 0x20
|
||||
#define PROMPT_QUOTENEXT 0x40
|
||||
#define PROMPT_BSPACE_EXIT 0x80
|
||||
#define PROMPT_NOFREEZE 0x100
|
||||
#define PROMPT_COMMANDMODE 0x200
|
||||
#define PROMPT_ISPANE 0x400
|
||||
#define PROMPT_ISMODE 0x800
|
||||
#define PROMPT_EDITARROWS 0x1000
|
||||
|
||||
/* Prompt create data. */
|
||||
struct prompt_create_data {
|
||||
struct cmd_find_state *fs;
|
||||
const char *prompt;
|
||||
const char *input;
|
||||
enum prompt_type type;
|
||||
int flags;
|
||||
|
||||
struct grid_cell style;
|
||||
struct grid_cell command_style;
|
||||
enum screen_cursor_style cstyle;
|
||||
enum screen_cursor_style command_cstyle;
|
||||
int ccolour;
|
||||
int command_ccolour;
|
||||
int cmode;
|
||||
int command_cmode;
|
||||
const char *message_format;
|
||||
int keys;
|
||||
const char *word_separators;
|
||||
|
||||
prompt_input_cb inputcb;
|
||||
prompt_free_cb freecb;
|
||||
void *data;
|
||||
};
|
||||
|
||||
/* Prompt draw data. */
|
||||
struct prompt_draw_data {
|
||||
struct screen_write_ctx *ctx;
|
||||
u_int *cursor_x;
|
||||
|
||||
u_int area_x;
|
||||
u_int area_width;
|
||||
u_int prompt_line;
|
||||
};
|
||||
|
||||
/* Overlay callbacks */
|
||||
typedef struct visible_ranges *(*overlay_check_cb)(struct client *, void *,
|
||||
u_int, u_int, u_int);
|
||||
typedef struct screen *(*overlay_mode_cb)(struct client *, void *, u_int *,
|
||||
u_int *);
|
||||
typedef void (*overlay_draw_cb)(struct client *, void *,
|
||||
struct screen_redraw_ctx *);
|
||||
typedef void (*overlay_draw_cb)(struct client *, void *);
|
||||
typedef int (*overlay_key_cb)(struct client *, void *, struct key_event *);
|
||||
typedef void (*overlay_free_cb)(struct client *, void *);
|
||||
typedef void (*overlay_resize_cb)(struct client *, void *);
|
||||
|
||||
/* Client connection. */
|
||||
struct client {
|
||||
const char *name;
|
||||
struct tmuxpeer *peer;
|
||||
@@ -2108,6 +2196,8 @@ struct client {
|
||||
size_t discarded;
|
||||
size_t redraw;
|
||||
|
||||
struct redraw_scene *redraw_scene;
|
||||
|
||||
struct event repeat_timer;
|
||||
|
||||
struct event click_timer;
|
||||
@@ -2198,38 +2288,15 @@ struct client {
|
||||
char *message_string;
|
||||
struct event message_timer;
|
||||
|
||||
char *prompt_string;
|
||||
struct utf8_data *prompt_buffer;
|
||||
struct cmd_find_state prompt_state;
|
||||
char *prompt_last;
|
||||
size_t prompt_index;
|
||||
prompt_input_cb prompt_inputcb;
|
||||
prompt_free_cb prompt_freecb;
|
||||
void *prompt_data;
|
||||
u_int prompt_hindex[PROMPT_NTYPES];
|
||||
enum {
|
||||
PROMPT_ENTRY,
|
||||
PROMPT_COMMAND
|
||||
} prompt_mode;
|
||||
struct utf8_data *prompt_saved;
|
||||
#define PROMPT_SINGLE 0x1
|
||||
#define PROMPT_NUMERIC 0x2
|
||||
#define PROMPT_INCREMENTAL 0x4
|
||||
#define PROMPT_NOFORMAT 0x8
|
||||
#define PROMPT_KEY 0x10
|
||||
#define PROMPT_ACCEPT 0x20
|
||||
#define PROMPT_QUOTENEXT 0x40
|
||||
#define PROMPT_BSPACE_EXIT 0x80
|
||||
#define PROMPT_NOFREEZE 0x100
|
||||
int prompt_flags;
|
||||
enum prompt_type prompt_type;
|
||||
int prompt_cursor;
|
||||
struct prompt *prompt;
|
||||
|
||||
struct session *session;
|
||||
struct session *last_session;
|
||||
|
||||
int references;
|
||||
|
||||
int theme_colours[COLOUR_THEME_COUNT];
|
||||
|
||||
void *pan_window;
|
||||
u_int pan_ox;
|
||||
u_int pan_oy;
|
||||
@@ -2318,6 +2385,7 @@ enum options_table_type {
|
||||
#define OPTIONS_TABLE_IS_ARRAY 0x1
|
||||
#define OPTIONS_TABLE_IS_HOOK 0x2
|
||||
#define OPTIONS_TABLE_IS_STYLE 0x4
|
||||
#define OPTIONS_TABLE_IS_COLOUR 0x8
|
||||
|
||||
struct options_table_entry {
|
||||
const char *name;
|
||||
@@ -2436,8 +2504,8 @@ int checkshell(const char *);
|
||||
void setblocking(int, int);
|
||||
char *shell_argv0(const char *, int);
|
||||
uint64_t get_timer(void);
|
||||
char *clean_name(const char *, const char *);
|
||||
int check_name(const char *, const char *);
|
||||
char *clean_name(const char *, int);
|
||||
int check_name(const char *);
|
||||
const char *sig2name(int);
|
||||
const char *find_cwd(void);
|
||||
const char *find_home(void);
|
||||
@@ -2621,6 +2689,7 @@ char *options_to_string(struct options_entry *, int, int);
|
||||
char *options_parse(const char *, int *);
|
||||
struct options_entry *options_parse_get(struct options *, const char *, int *,
|
||||
int);
|
||||
const struct options_table_entry *options_search(const char *);
|
||||
char *options_match(const char *, int *, int *);
|
||||
struct options_entry *options_match_get(struct options *, const char *, int *,
|
||||
int, int *);
|
||||
@@ -2775,7 +2844,7 @@ void tty_cmd_setselection(struct tty *, const struct tty_ctx *);
|
||||
void tty_cmd_rawstring(struct tty *, const struct tty_ctx *);
|
||||
#ifdef ENABLE_SIXEL
|
||||
void tty_cmd_sixelimage(struct tty *, const struct tty_ctx *);
|
||||
void tty_draw_images(struct client *, struct window_pane *, struct screen *);
|
||||
void tty_draw_images(struct client *, struct window_pane *);
|
||||
#endif
|
||||
void tty_cmd_syncstart(struct tty *, const struct tty_ctx *);
|
||||
void tty_default_colours(struct grid_cell *, struct window_pane *, u_int *);
|
||||
@@ -3126,6 +3195,7 @@ void server_client_print(struct client *, int, struct evbuffer *);
|
||||
|
||||
/* server-fn.c */
|
||||
void server_redraw_client(struct client *);
|
||||
void server_client_update_theme_colours(struct client *);
|
||||
void server_status_client(struct client *);
|
||||
void server_redraw_session(struct session *);
|
||||
void server_redraw_session_group(struct session *);
|
||||
@@ -3150,8 +3220,6 @@ void server_check_unattached(void);
|
||||
void server_unzoom_window(struct window *);
|
||||
|
||||
/* status.c */
|
||||
extern char **status_prompt_hlist[];
|
||||
extern u_int status_prompt_hsize[];
|
||||
void status_timer_start(struct client *);
|
||||
void status_timer_start_all(void);
|
||||
void status_update_cache(struct session *);
|
||||
@@ -3167,16 +3235,38 @@ void printflike(6, 7) status_message_set(struct client *, int, int, int, int,
|
||||
void status_message_clear(struct client *);
|
||||
int status_message_redraw(struct client *);
|
||||
void status_prompt_set(struct client *, struct cmd_find_state *,
|
||||
const char *, const char *, prompt_input_cb, prompt_free_cb,
|
||||
const char *, const char *, status_prompt_input_cb, prompt_free_cb,
|
||||
void *, int, enum prompt_type);
|
||||
void status_prompt_clear(struct client *);
|
||||
int status_prompt_redraw(struct client *);
|
||||
int status_prompt_key(struct client *, key_code);
|
||||
void status_prompt_cursor(struct client *, u_int *, u_int *);
|
||||
enum prompt_key_result status_prompt_key(struct client *, key_code,
|
||||
struct mouse_event *);
|
||||
void status_prompt_update(struct client *, const char *, const char *);
|
||||
void status_prompt_load_history(void);
|
||||
void status_prompt_save_history(void);
|
||||
const char *status_prompt_type_string(u_int);
|
||||
enum prompt_type status_prompt_type(const char *type);
|
||||
|
||||
/* prompt.c */
|
||||
void prompt_set_options(struct prompt_create_data *, struct session *);
|
||||
struct prompt *prompt_create(const struct prompt_create_data *);
|
||||
void prompt_free(struct prompt *);
|
||||
void prompt_incremental_start(struct prompt *);
|
||||
void prompt_draw(struct prompt *, struct prompt_draw_data *);
|
||||
enum prompt_key_result prompt_key(struct prompt *, key_code, int *);
|
||||
enum prompt_key_result prompt_mouse(struct prompt *, u_int, u_int, u_int,
|
||||
int *);
|
||||
void prompt_update(struct prompt *, const char *, const char *);
|
||||
int prompt_closed(struct prompt *);
|
||||
enum prompt_type prompt_type(const char *);
|
||||
const char *prompt_type_string(enum prompt_type);
|
||||
|
||||
/* prompt-history.c */
|
||||
const char *prompt_up_history(u_int *, u_int);
|
||||
const char *prompt_down_history(u_int *, u_int);
|
||||
void prompt_add_history(const char *, u_int);
|
||||
u_int prompt_history_size(enum prompt_type);
|
||||
const char *prompt_history_get(enum prompt_type, u_int);
|
||||
void prompt_history_clear(enum prompt_type);
|
||||
void prompt_load_history(void);
|
||||
void prompt_save_history(void);
|
||||
|
||||
/* resize.c */
|
||||
void resize_window(struct window *, u_int, u_int, int, int);
|
||||
@@ -3219,6 +3309,8 @@ int colour_dim(int, u_int);
|
||||
const char *colour_tostring(int);
|
||||
enum client_theme colour_totheme(int);
|
||||
int colour_fromstring(const char *);
|
||||
const char *colour_theme_option(u_int, enum client_theme);
|
||||
int colour_theme_terminal_colour(u_int);
|
||||
int colour_256toRGB(int);
|
||||
int colour_256to16(int);
|
||||
int colour_byname(const char *);
|
||||
@@ -3234,6 +3326,9 @@ void colour_palette_from_option(struct colour_palette *, struct options *);
|
||||
const char *attributes_tostring(int);
|
||||
int attributes_fromstring(const char *);
|
||||
|
||||
/* fuzzy.c */
|
||||
bitstr_t *fuzzy_match(const char *, const char *, u_int, u_int *);
|
||||
|
||||
/* grid.c */
|
||||
extern const struct grid_cell grid_default_cell;
|
||||
void grid_empty_line(struct grid *, u_int, u_int);
|
||||
@@ -3339,7 +3434,8 @@ void screen_write_fast_copy(struct screen_write_ctx *, struct screen *,
|
||||
u_int, u_int, u_int, u_int);
|
||||
void screen_write_hline(struct screen_write_ctx *, u_int, int, int,
|
||||
enum box_lines, const struct grid_cell *);
|
||||
void screen_write_vline(struct screen_write_ctx *, u_int, int, int);
|
||||
void screen_write_vline(struct screen_write_ctx *, u_int, int, int,
|
||||
const struct grid_cell *);
|
||||
void screen_write_menu(struct screen_write_ctx *, struct menu *, int,
|
||||
enum box_lines, const struct grid_cell *, const struct grid_cell *,
|
||||
const struct grid_cell *);
|
||||
@@ -3395,8 +3491,13 @@ void screen_write_alternateoff(struct screen_write_ctx *,
|
||||
struct grid_cell *, int);
|
||||
|
||||
/* screen-redraw.c */
|
||||
void screen_redraw_screen(struct client *);
|
||||
void screen_redraw_pane(struct client *, struct window_pane *, int);
|
||||
void redraw_screen(struct client *);
|
||||
void redraw_pane(struct client *, struct window_pane *);
|
||||
void redraw_pane_scrollbar(struct client *, struct window_pane *);
|
||||
void redraw_free_scene(struct redraw_scene *);
|
||||
void redraw_invalidate_scene(struct window *);
|
||||
void redraw_invalidate_all_scenes(void);
|
||||
int redraw_get_status_border_cell_type(struct redraw_span **, u_int);
|
||||
|
||||
/* screen.c */
|
||||
void screen_init(struct screen *, u_int, u_int, u_int);
|
||||
@@ -3501,6 +3602,16 @@ int window_pane_key(struct window_pane *, struct client *,
|
||||
struct mouse_event *);
|
||||
void window_pane_paste(struct window_pane *, key_code, char *,
|
||||
size_t);
|
||||
void window_pane_set_prompt(struct window_pane *, struct client *,
|
||||
struct cmd_find_state *, const char *, const char *,
|
||||
status_prompt_input_cb, prompt_free_cb, void *, int,
|
||||
enum prompt_type);
|
||||
void window_pane_clear_prompt(struct window_pane *);
|
||||
int window_pane_has_prompt(struct window_pane *);
|
||||
void window_pane_update_prompt(struct window_pane *, const char *,
|
||||
const char *);
|
||||
enum prompt_key_result window_pane_prompt_key(struct window_pane *,
|
||||
struct client *, key_code, struct mouse_event *);
|
||||
int window_pane_is_visible(struct window_pane *);
|
||||
int window_pane_exited(struct window_pane *);
|
||||
u_int window_pane_search(struct window_pane *, const char *, int,
|
||||
@@ -3515,7 +3626,7 @@ void window_pane_stack_push(struct window_panes *,
|
||||
struct window_pane *);
|
||||
void window_pane_stack_remove(struct window_panes *,
|
||||
struct window_pane *);
|
||||
void window_set_name(struct window *, const char *, const char *);
|
||||
void window_set_name(struct window *, const char *, int);
|
||||
void window_add_ref(struct window *, const char *);
|
||||
void window_remove_ref(struct window *, const char *);
|
||||
void winlink_clear_flags(struct winlink *);
|
||||
@@ -3529,7 +3640,15 @@ void window_pane_update_used_data(struct window_pane *,
|
||||
void window_set_fill_character(struct window *);
|
||||
void window_pane_default_cursor(struct window_pane *);
|
||||
int window_pane_mode(struct window_pane *);
|
||||
int window_pane_show_scrollbar(struct window_pane *, int);
|
||||
int window_pane_show_scrollbar(struct window_pane *);
|
||||
int window_pane_scrollbar_reserve(struct window_pane *);
|
||||
int window_pane_scrollbar_visible(struct window_pane *);
|
||||
int window_pane_scrollbar_overlay(struct window_pane *);
|
||||
int window_pane_scrollbar_overlay_visible(struct window_pane *);
|
||||
void window_pane_scrollbar_show(struct window_pane *, int);
|
||||
void window_pane_scrollbar_hide(struct window_pane *);
|
||||
void window_pane_scrollbar_start_timer(struct window_pane *);
|
||||
void window_pane_scrollbar_redraw(struct window_pane *);
|
||||
int window_pane_get_bg(struct window_pane *);
|
||||
int window_pane_get_fg(struct window_pane *);
|
||||
int window_pane_get_fg_control_client(struct window_pane *);
|
||||
@@ -3538,6 +3657,7 @@ int window_get_bg_client(struct window_pane *);
|
||||
enum client_theme window_pane_get_theme(struct window_pane *);
|
||||
void window_pane_send_theme_update(struct window_pane *);
|
||||
enum pane_lines window_pane_get_pane_lines(struct window_pane *);
|
||||
enum pane_lines window_get_pane_lines(struct window *);
|
||||
int window_get_pane_status(struct window *);
|
||||
int window_pane_get_pane_status(struct window_pane *);
|
||||
struct style_range *window_pane_status_get_range(struct window_pane *, u_int,
|
||||
@@ -3545,6 +3665,16 @@ struct style_range *window_pane_status_get_range(struct window_pane *, u_int,
|
||||
int window_pane_is_floating(struct window_pane *);
|
||||
int window_pane_is_hidden(struct window_pane *);
|
||||
|
||||
/* window-border.c */
|
||||
void window_get_border_cell(struct window *, struct window_pane *,
|
||||
enum pane_lines, int, struct grid_cell *);
|
||||
void window_pane_get_border_cell(struct window_pane *, int,
|
||||
struct grid_cell *);
|
||||
void window_pane_get_border_style(struct window_pane *,
|
||||
struct client *, struct grid_cell *);
|
||||
int window_make_pane_status(struct window_pane *, struct client *,
|
||||
u_int, struct redraw_span *);
|
||||
|
||||
/* window-visible.c */
|
||||
int window_position_is_visible(struct visible_ranges *, u_int);
|
||||
struct visible_ranges *window_visible_ranges(struct window_pane *, int, int,
|
||||
@@ -3581,9 +3711,9 @@ void layout_resize_pane(struct window_pane *, enum layout_type,
|
||||
int, int);
|
||||
void layout_resize_pane_to(struct window_pane *, enum layout_type,
|
||||
u_int);
|
||||
void layout_resize_floating_pane(struct window_pane *,
|
||||
int layout_resize_floating_pane(struct window_pane *,
|
||||
enum layout_type, int, int, char **);
|
||||
void layout_resize_floating_pane_to(struct window_pane *,
|
||||
int layout_resize_floating_pane_to(struct window_pane *,
|
||||
enum layout_type, u_int, char **);
|
||||
void layout_assign_pane(struct layout_cell *, struct window_pane *,
|
||||
int);
|
||||
@@ -3591,6 +3721,8 @@ int layout_split_check_space(struct window_pane *,
|
||||
struct layout_cell *, enum layout_type);
|
||||
void layout_split_sizes(struct layout_cell *, int, int,
|
||||
enum layout_type, u_int *, u_int *, u_int *);
|
||||
struct layout_cell *layout_replace_with_node(struct window *,
|
||||
struct layout_cell *, enum layout_type);
|
||||
struct layout_cell *layout_split_pane(struct window_pane *, enum layout_type,
|
||||
int, int);
|
||||
struct layout_cell *layout_floating_pane(struct window *, struct window_pane *,
|
||||
@@ -3601,10 +3733,11 @@ void layout_spread_out(struct window_pane *);
|
||||
void layout_cell_floating_args_parse(struct cmdq_item *, struct args *,
|
||||
struct window *, u_int *, u_int *, int *, int *, char **);
|
||||
struct layout_cell *layout_get_floating_cell(struct cmdq_item *, struct args *,
|
||||
struct window *, struct window_pane *, char **);
|
||||
struct layout_cell *layout_get_tiled_cell(struct cmdq_item *, struct args *,
|
||||
struct window *, struct window_pane *, int, char **);
|
||||
int layout_cell_is_tiled(struct layout_cell *);
|
||||
enum pane_lines, struct window *, struct window_pane *,
|
||||
char **cause);
|
||||
int layout_floating_args_parse(struct cmdq_item *, struct args *,
|
||||
enum pane_lines, struct window *, u_int *, u_int *, int *,
|
||||
int *, char **);
|
||||
int layout_remove_tile(struct window *, struct layout_cell *);
|
||||
int layout_insert_tile(struct window *, struct layout_cell *);
|
||||
|
||||
@@ -3634,6 +3767,7 @@ typedef const char** (*mode_tree_help_cb)(u_int *, const char**);
|
||||
u_int mode_tree_count_tagged(struct mode_tree_data *);
|
||||
void *mode_tree_get_current(struct mode_tree_data *);
|
||||
const char *mode_tree_get_current_name(struct mode_tree_data *);
|
||||
void mode_tree_select_top(struct mode_tree_data *);
|
||||
void mode_tree_expand_current(struct mode_tree_data *);
|
||||
void mode_tree_collapse_current(struct mode_tree_data *);
|
||||
void mode_tree_expand(struct mode_tree_data *, uint64_t);
|
||||
@@ -3662,6 +3796,11 @@ void mode_tree_remove(struct mode_tree_data *, struct mode_tree_item *);
|
||||
void mode_tree_draw(struct mode_tree_data *);
|
||||
int mode_tree_key(struct mode_tree_data *, struct client *, key_code *,
|
||||
struct mouse_event *, u_int *, u_int *);
|
||||
void mode_tree_set_prompt(struct mode_tree_data *, struct client *,
|
||||
const char *, const char *, enum prompt_type, int,
|
||||
mode_tree_prompt_input_cb, prompt_free_cb, void *);
|
||||
void mode_tree_clear_prompt(struct mode_tree_data *);
|
||||
int mode_tree_has_prompt(struct mode_tree_data *);
|
||||
void mode_tree_run_command(struct client *, struct cmd_find_state *,
|
||||
const char *, const char *);
|
||||
|
||||
@@ -3671,6 +3810,9 @@ extern const struct window_mode window_buffer_mode;
|
||||
/* window-tree.c */
|
||||
extern const struct window_mode window_tree_mode;
|
||||
|
||||
/* window-switch.c */
|
||||
extern const struct window_mode window_switch_mode;
|
||||
|
||||
/* window-clock.c */
|
||||
extern const struct window_mode window_clock_mode;
|
||||
extern const char window_clock_table[14][5][5];
|
||||
@@ -3855,8 +3997,7 @@ int menu_display(struct menu *, int, int, struct cmdq_item *,
|
||||
struct screen *menu_mode_cb(struct client *, void *, u_int *, u_int *);
|
||||
struct visible_ranges *menu_check_cb(struct client *, void *, u_int, u_int,
|
||||
u_int);
|
||||
void menu_draw_cb(struct client *, void *,
|
||||
struct screen_redraw_ctx *);
|
||||
void menu_draw_cb(struct client *, void *);
|
||||
void menu_free_cb(struct client *, void *);
|
||||
int menu_key_cb(struct client *, void *, struct key_event *);
|
||||
|
||||
@@ -3877,7 +4018,10 @@ int popup_modify(struct client *, const char *, const char *,
|
||||
/* style.c */
|
||||
int style_parse(struct style *,const struct grid_cell *,
|
||||
const char *);
|
||||
int style_parse_colour(struct style *,
|
||||
const struct grid_cell *, const char *);
|
||||
const char *style_tostring(struct style *);
|
||||
const char *style_link(struct style *);
|
||||
struct style *style_add(struct grid_cell *, struct options *,
|
||||
const char *, struct format_tree *);
|
||||
void style_apply(struct grid_cell *, struct options *,
|
||||
|
||||
632
tools/x11-colours.sh
Normal file
632
tools/x11-colours.sh
Normal file
@@ -0,0 +1,632 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
awk '
|
||||
{
|
||||
if ($0 !~ /\{[[:space:]]*".*",[[:space:]]*0x[0-9A-Fa-f]+/)
|
||||
next
|
||||
|
||||
name = $0
|
||||
sub(/^[^"]*"/, "", name)
|
||||
sub(/".*$/, "", name)
|
||||
|
||||
hex = $0
|
||||
sub(/^.*0x/, "", hex)
|
||||
sub(/[^0-9A-Fa-f].*$/, "", hex)
|
||||
|
||||
printf "%s|%s\n", name, tolower(hex)
|
||||
}
|
||||
' <<'COLOURS' |
|
||||
{ "AliceBlue", 0xf0f8ff },
|
||||
{ "AntiqueWhite", 0xfaebd7 },
|
||||
{ "AntiqueWhite1", 0xffefdb },
|
||||
{ "AntiqueWhite2", 0xeedfcc },
|
||||
{ "AntiqueWhite3", 0xcdc0b0 },
|
||||
{ "AntiqueWhite4", 0x8b8378 },
|
||||
{ "BlanchedAlmond", 0xffebcd },
|
||||
{ "BlueViolet", 0x8a2be2 },
|
||||
{ "CadetBlue", 0x5f9ea0 },
|
||||
{ "CadetBlue1", 0x98f5ff },
|
||||
{ "CadetBlue2", 0x8ee5ee },
|
||||
{ "CadetBlue3", 0x7ac5cd },
|
||||
{ "CadetBlue4", 0x53868b },
|
||||
{ "CornflowerBlue", 0x6495ed },
|
||||
{ "DarkBlue", 0x00008b },
|
||||
{ "DarkCyan", 0x008b8b },
|
||||
{ "DarkGoldenrod", 0xb8860b },
|
||||
{ "DarkGoldenrod1", 0xffb90f },
|
||||
{ "DarkGoldenrod2", 0xeead0e },
|
||||
{ "DarkGoldenrod3", 0xcd950c },
|
||||
{ "DarkGoldenrod4", 0x8b6508 },
|
||||
{ "DarkGray", 0xa9a9a9 },
|
||||
{ "DarkGreen", 0x006400 },
|
||||
{ "DarkGrey", 0xa9a9a9 },
|
||||
{ "DarkKhaki", 0xbdb76b },
|
||||
{ "DarkMagenta", 0x8b008b },
|
||||
{ "DarkOliveGreen", 0x556b2f },
|
||||
{ "DarkOliveGreen1", 0xcaff70 },
|
||||
{ "DarkOliveGreen2", 0xbcee68 },
|
||||
{ "DarkOliveGreen3", 0xa2cd5a },
|
||||
{ "DarkOliveGreen4", 0x6e8b3d },
|
||||
{ "DarkOrange", 0xff8c00 },
|
||||
{ "DarkOrange1", 0xff7f00 },
|
||||
{ "DarkOrange2", 0xee7600 },
|
||||
{ "DarkOrange3", 0xcd6600 },
|
||||
{ "DarkOrange4", 0x8b4500 },
|
||||
{ "DarkOrchid", 0x9932cc },
|
||||
{ "DarkOrchid1", 0xbf3eff },
|
||||
{ "DarkOrchid2", 0xb23aee },
|
||||
{ "DarkOrchid3", 0x9a32cd },
|
||||
{ "DarkOrchid4", 0x68228b },
|
||||
{ "DarkRed", 0x8b0000 },
|
||||
{ "DarkSalmon", 0xe9967a },
|
||||
{ "DarkSeaGreen", 0x8fbc8f },
|
||||
{ "DarkSeaGreen1", 0xc1ffc1 },
|
||||
{ "DarkSeaGreen2", 0xb4eeb4 },
|
||||
{ "DarkSeaGreen3", 0x9bcd9b },
|
||||
{ "DarkSeaGreen4", 0x698b69 },
|
||||
{ "DarkSlateBlue", 0x483d8b },
|
||||
{ "DarkSlateGray", 0x2f4f4f },
|
||||
{ "DarkSlateGray1", 0x97ffff },
|
||||
{ "DarkSlateGray2", 0x8deeee },
|
||||
{ "DarkSlateGray3", 0x79cdcd },
|
||||
{ "DarkSlateGray4", 0x528b8b },
|
||||
{ "DarkSlateGrey", 0x2f4f4f },
|
||||
{ "DarkTurquoise", 0x00ced1 },
|
||||
{ "DarkViolet", 0x9400d3 },
|
||||
{ "DeepPink", 0xff1493 },
|
||||
{ "DeepPink1", 0xff1493 },
|
||||
{ "DeepPink2", 0xee1289 },
|
||||
{ "DeepPink3", 0xcd1076 },
|
||||
{ "DeepPink4", 0x8b0a50 },
|
||||
{ "DeepSkyBlue", 0x00bfff },
|
||||
{ "DeepSkyBlue1", 0x00bfff },
|
||||
{ "DeepSkyBlue2", 0x00b2ee },
|
||||
{ "DeepSkyBlue3", 0x009acd },
|
||||
{ "DeepSkyBlue4", 0x00688b },
|
||||
{ "DimGray", 0x696969 },
|
||||
{ "DimGrey", 0x696969 },
|
||||
{ "DodgerBlue", 0x1e90ff },
|
||||
{ "DodgerBlue1", 0x1e90ff },
|
||||
{ "DodgerBlue2", 0x1c86ee },
|
||||
{ "DodgerBlue3", 0x1874cd },
|
||||
{ "DodgerBlue4", 0x104e8b },
|
||||
{ "FloralWhite", 0xfffaf0 },
|
||||
{ "ForestGreen", 0x228b22 },
|
||||
{ "GhostWhite", 0xf8f8ff },
|
||||
{ "GreenYellow", 0xadff2f },
|
||||
{ "HotPink", 0xff69b4 },
|
||||
{ "HotPink1", 0xff6eb4 },
|
||||
{ "HotPink2", 0xee6aa7 },
|
||||
{ "HotPink3", 0xcd6090 },
|
||||
{ "HotPink4", 0x8b3a62 },
|
||||
{ "IndianRed", 0xcd5c5c },
|
||||
{ "IndianRed1", 0xff6a6a },
|
||||
{ "IndianRed2", 0xee6363 },
|
||||
{ "IndianRed3", 0xcd5555 },
|
||||
{ "IndianRed4", 0x8b3a3a },
|
||||
{ "LavenderBlush", 0xfff0f5 },
|
||||
{ "LavenderBlush1", 0xfff0f5 },
|
||||
{ "LavenderBlush2", 0xeee0e5 },
|
||||
{ "LavenderBlush3", 0xcdc1c5 },
|
||||
{ "LavenderBlush4", 0x8b8386 },
|
||||
{ "LawnGreen", 0x7cfc00 },
|
||||
{ "LemonChiffon", 0xfffacd },
|
||||
{ "LemonChiffon1", 0xfffacd },
|
||||
{ "LemonChiffon2", 0xeee9bf },
|
||||
{ "LemonChiffon3", 0xcdc9a5 },
|
||||
{ "LemonChiffon4", 0x8b8970 },
|
||||
{ "LightBlue", 0xadd8e6 },
|
||||
{ "LightBlue1", 0xbfefff },
|
||||
{ "LightBlue2", 0xb2dfee },
|
||||
{ "LightBlue3", 0x9ac0cd },
|
||||
{ "LightBlue4", 0x68838b },
|
||||
{ "LightCoral", 0xf08080 },
|
||||
{ "LightCyan", 0xe0ffff },
|
||||
{ "LightCyan1", 0xe0ffff },
|
||||
{ "LightCyan2", 0xd1eeee },
|
||||
{ "LightCyan3", 0xb4cdcd },
|
||||
{ "LightCyan4", 0x7a8b8b },
|
||||
{ "LightGoldenrod", 0xeedd82 },
|
||||
{ "LightGoldenrod1", 0xffec8b },
|
||||
{ "LightGoldenrod2", 0xeedc82 },
|
||||
{ "LightGoldenrod3", 0xcdbe70 },
|
||||
{ "LightGoldenrod4", 0x8b814c },
|
||||
{ "LightGoldenrodYellow", 0xfafad2 },
|
||||
{ "LightGray", 0xd3d3d3 },
|
||||
{ "LightGreen", 0x90ee90 },
|
||||
{ "LightGrey", 0xd3d3d3 },
|
||||
{ "LightPink", 0xffb6c1 },
|
||||
{ "LightPink1", 0xffaeb9 },
|
||||
{ "LightPink2", 0xeea2ad },
|
||||
{ "LightPink3", 0xcd8c95 },
|
||||
{ "LightPink4", 0x8b5f65 },
|
||||
{ "LightSalmon", 0xffa07a },
|
||||
{ "LightSalmon1", 0xffa07a },
|
||||
{ "LightSalmon2", 0xee9572 },
|
||||
{ "LightSalmon3", 0xcd8162 },
|
||||
{ "LightSalmon4", 0x8b5742 },
|
||||
{ "LightSeaGreen", 0x20b2aa },
|
||||
{ "LightSkyBlue", 0x87cefa },
|
||||
{ "LightSkyBlue1", 0xb0e2ff },
|
||||
{ "LightSkyBlue2", 0xa4d3ee },
|
||||
{ "LightSkyBlue3", 0x8db6cd },
|
||||
{ "LightSkyBlue4", 0x607b8b },
|
||||
{ "LightSlateBlue", 0x8470ff },
|
||||
{ "LightSlateGray", 0x778899 },
|
||||
{ "LightSlateGrey", 0x778899 },
|
||||
{ "LightSteelBlue", 0xb0c4de },
|
||||
{ "LightSteelBlue1", 0xcae1ff },
|
||||
{ "LightSteelBlue2", 0xbcd2ee },
|
||||
{ "LightSteelBlue3", 0xa2b5cd },
|
||||
{ "LightSteelBlue4", 0x6e7b8b },
|
||||
{ "LightYellow", 0xffffe0 },
|
||||
{ "LightYellow1", 0xffffe0 },
|
||||
{ "LightYellow2", 0xeeeed1 },
|
||||
{ "LightYellow3", 0xcdcdb4 },
|
||||
{ "LightYellow4", 0x8b8b7a },
|
||||
{ "LimeGreen", 0x32cd32 },
|
||||
{ "MediumAquamarine", 0x66cdaa },
|
||||
{ "MediumBlue", 0x0000cd },
|
||||
{ "MediumOrchid", 0xba55d3 },
|
||||
{ "MediumOrchid1", 0xe066ff },
|
||||
{ "MediumOrchid2", 0xd15fee },
|
||||
{ "MediumOrchid3", 0xb452cd },
|
||||
{ "MediumOrchid4", 0x7a378b },
|
||||
{ "MediumPurple", 0x9370db },
|
||||
{ "MediumPurple1", 0xab82ff },
|
||||
{ "MediumPurple2", 0x9f79ee },
|
||||
{ "MediumPurple3", 0x8968cd },
|
||||
{ "MediumPurple4", 0x5d478b },
|
||||
{ "MediumSeaGreen", 0x3cb371 },
|
||||
{ "MediumSlateBlue", 0x7b68ee },
|
||||
{ "MediumSpringGreen", 0x00fa9a },
|
||||
{ "MediumTurquoise", 0x48d1cc },
|
||||
{ "MediumVioletRed", 0xc71585 },
|
||||
{ "MidnightBlue", 0x191970 },
|
||||
{ "MintCream", 0xf5fffa },
|
||||
{ "MistyRose", 0xffe4e1 },
|
||||
{ "MistyRose1", 0xffe4e1 },
|
||||
{ "MistyRose2", 0xeed5d2 },
|
||||
{ "MistyRose3", 0xcdb7b5 },
|
||||
{ "MistyRose4", 0x8b7d7b },
|
||||
{ "NavajoWhite", 0xffdead },
|
||||
{ "NavajoWhite1", 0xffdead },
|
||||
{ "NavajoWhite2", 0xeecfa1 },
|
||||
{ "NavajoWhite3", 0xcdb38b },
|
||||
{ "NavajoWhite4", 0x8b795e },
|
||||
{ "NavyBlue", 0x000080 },
|
||||
{ "OldLace", 0xfdf5e6 },
|
||||
{ "OliveDrab", 0x6b8e23 },
|
||||
{ "OliveDrab1", 0xc0ff3e },
|
||||
{ "OliveDrab2", 0xb3ee3a },
|
||||
{ "OliveDrab3", 0x9acd32 },
|
||||
{ "OliveDrab4", 0x698b22 },
|
||||
{ "OrangeRed", 0xff4500 },
|
||||
{ "OrangeRed1", 0xff4500 },
|
||||
{ "OrangeRed2", 0xee4000 },
|
||||
{ "OrangeRed3", 0xcd3700 },
|
||||
{ "OrangeRed4", 0x8b2500 },
|
||||
{ "PaleGoldenrod", 0xeee8aa },
|
||||
{ "PaleGreen", 0x98fb98 },
|
||||
{ "PaleGreen1", 0x9aff9a },
|
||||
{ "PaleGreen2", 0x90ee90 },
|
||||
{ "PaleGreen3", 0x7ccd7c },
|
||||
{ "PaleGreen4", 0x548b54 },
|
||||
{ "PaleTurquoise", 0xafeeee },
|
||||
{ "PaleTurquoise1", 0xbbffff },
|
||||
{ "PaleTurquoise2", 0xaeeeee },
|
||||
{ "PaleTurquoise3", 0x96cdcd },
|
||||
{ "PaleTurquoise4", 0x668b8b },
|
||||
{ "PaleVioletRed", 0xdb7093 },
|
||||
{ "PaleVioletRed1", 0xff82ab },
|
||||
{ "PaleVioletRed2", 0xee799f },
|
||||
{ "PaleVioletRed3", 0xcd6889 },
|
||||
{ "PaleVioletRed4", 0x8b475d },
|
||||
{ "PapayaWhip", 0xffefd5 },
|
||||
{ "PeachPuff", 0xffdab9 },
|
||||
{ "PeachPuff1", 0xffdab9 },
|
||||
{ "PeachPuff2", 0xeecbad },
|
||||
{ "PeachPuff3", 0xcdaf95 },
|
||||
{ "PeachPuff4", 0x8b7765 },
|
||||
{ "PowderBlue", 0xb0e0e6 },
|
||||
{ "RebeccaPurple", 0x663399 },
|
||||
{ "RosyBrown", 0xbc8f8f },
|
||||
{ "RosyBrown1", 0xffc1c1 },
|
||||
{ "RosyBrown2", 0xeeb4b4 },
|
||||
{ "RosyBrown3", 0xcd9b9b },
|
||||
{ "RosyBrown4", 0x8b6969 },
|
||||
{ "RoyalBlue", 0x4169e1 },
|
||||
{ "RoyalBlue1", 0x4876ff },
|
||||
{ "RoyalBlue2", 0x436eee },
|
||||
{ "RoyalBlue3", 0x3a5fcd },
|
||||
{ "RoyalBlue4", 0x27408b },
|
||||
{ "SaddleBrown", 0x8b4513 },
|
||||
{ "SandyBrown", 0xf4a460 },
|
||||
{ "SeaGreen", 0x2e8b57 },
|
||||
{ "SeaGreen1", 0x54ff9f },
|
||||
{ "SeaGreen2", 0x4eee94 },
|
||||
{ "SeaGreen3", 0x43cd80 },
|
||||
{ "SeaGreen4", 0x2e8b57 },
|
||||
{ "SkyBlue", 0x87ceeb },
|
||||
{ "SkyBlue1", 0x87ceff },
|
||||
{ "SkyBlue2", 0x7ec0ee },
|
||||
{ "SkyBlue3", 0x6ca6cd },
|
||||
{ "SkyBlue4", 0x4a708b },
|
||||
{ "SlateBlue", 0x6a5acd },
|
||||
{ "SlateBlue1", 0x836fff },
|
||||
{ "SlateBlue2", 0x7a67ee },
|
||||
{ "SlateBlue3", 0x6959cd },
|
||||
{ "SlateBlue4", 0x473c8b },
|
||||
{ "SlateGray", 0x708090 },
|
||||
{ "SlateGray1", 0xc6e2ff },
|
||||
{ "SlateGray2", 0xb9d3ee },
|
||||
{ "SlateGray3", 0x9fb6cd },
|
||||
{ "SlateGray4", 0x6c7b8b },
|
||||
{ "SlateGrey", 0x708090 },
|
||||
{ "SpringGreen", 0x00ff7f },
|
||||
{ "SpringGreen1", 0x00ff7f },
|
||||
{ "SpringGreen2", 0x00ee76 },
|
||||
{ "SpringGreen3", 0x00cd66 },
|
||||
{ "SpringGreen4", 0x008b45 },
|
||||
{ "SteelBlue", 0x4682b4 },
|
||||
{ "SteelBlue1", 0x63b8ff },
|
||||
{ "SteelBlue2", 0x5cacee },
|
||||
{ "SteelBlue3", 0x4f94cd },
|
||||
{ "SteelBlue4", 0x36648b },
|
||||
{ "VioletRed", 0xd02090 },
|
||||
{ "VioletRed1", 0xff3e96 },
|
||||
{ "VioletRed2", 0xee3a8c },
|
||||
{ "VioletRed3", 0xcd3278 },
|
||||
{ "VioletRed4", 0x8b2252 },
|
||||
{ "WebGray", 0x808080 },
|
||||
{ "WebGreen", 0x008000 },
|
||||
{ "WebGrey", 0x808080 },
|
||||
{ "WebMaroon", 0x800000 },
|
||||
{ "WebPurple", 0x800080 },
|
||||
{ "WhiteSmoke", 0xf5f5f5 },
|
||||
{ "X11Gray", 0xbebebe },
|
||||
{ "X11Green", 0x00ff00 },
|
||||
{ "X11Grey", 0xbebebe },
|
||||
{ "X11Maroon", 0xb03060 },
|
||||
{ "X11Purple", 0xa020f0 },
|
||||
{ "YellowGreen", 0x9acd32 },
|
||||
{ "alice blue", 0xf0f8ff },
|
||||
{ "antique white", 0xfaebd7 },
|
||||
{ "aqua", 0x00ffff },
|
||||
{ "aquamarine", 0x7fffd4 },
|
||||
{ "aquamarine1", 0x7fffd4 },
|
||||
{ "aquamarine2", 0x76eec6 },
|
||||
{ "aquamarine3", 0x66cdaa },
|
||||
{ "aquamarine4", 0x458b74 },
|
||||
{ "azure", 0xf0ffff },
|
||||
{ "azure1", 0xf0ffff },
|
||||
{ "azure2", 0xe0eeee },
|
||||
{ "azure3", 0xc1cdcd },
|
||||
{ "azure4", 0x838b8b },
|
||||
{ "beige", 0xf5f5dc },
|
||||
{ "bisque", 0xffe4c4 },
|
||||
{ "bisque1", 0xffe4c4 },
|
||||
{ "bisque2", 0xeed5b7 },
|
||||
{ "bisque3", 0xcdb79e },
|
||||
{ "bisque4", 0x8b7d6b },
|
||||
{ "black", 0x000000 },
|
||||
{ "blanched almond", 0xffebcd },
|
||||
{ "blue violet", 0x8a2be2 },
|
||||
{ "blue", 0x0000ff },
|
||||
{ "blue1", 0x0000ff },
|
||||
{ "blue2", 0x0000ee },
|
||||
{ "blue3", 0x0000cd },
|
||||
{ "blue4", 0x00008b },
|
||||
{ "brown", 0xa52a2a },
|
||||
{ "brown1", 0xff4040 },
|
||||
{ "brown2", 0xee3b3b },
|
||||
{ "brown3", 0xcd3333 },
|
||||
{ "brown4", 0x8b2323 },
|
||||
{ "burlywood", 0xdeb887 },
|
||||
{ "burlywood1", 0xffd39b },
|
||||
{ "burlywood2", 0xeec591 },
|
||||
{ "burlywood3", 0xcdaa7d },
|
||||
{ "burlywood4", 0x8b7355 },
|
||||
{ "cadet blue", 0x5f9ea0 },
|
||||
{ "chartreuse", 0x7fff00 },
|
||||
{ "chartreuse1", 0x7fff00 },
|
||||
{ "chartreuse2", 0x76ee00 },
|
||||
{ "chartreuse3", 0x66cd00 },
|
||||
{ "chartreuse4", 0x458b00 },
|
||||
{ "chocolate", 0xd2691e },
|
||||
{ "chocolate1", 0xff7f24 },
|
||||
{ "chocolate2", 0xee7621 },
|
||||
{ "chocolate3", 0xcd661d },
|
||||
{ "chocolate4", 0x8b4513 },
|
||||
{ "coral", 0xff7f50 },
|
||||
{ "coral1", 0xff7256 },
|
||||
{ "coral2", 0xee6a50 },
|
||||
{ "coral3", 0xcd5b45 },
|
||||
{ "coral4", 0x8b3e2f },
|
||||
{ "cornflower blue", 0x6495ed },
|
||||
{ "cornsilk", 0xfff8dc },
|
||||
{ "cornsilk1", 0xfff8dc },
|
||||
{ "cornsilk2", 0xeee8cd },
|
||||
{ "cornsilk3", 0xcdc8b1 },
|
||||
{ "cornsilk4", 0x8b8878 },
|
||||
{ "crimson", 0xdc143c },
|
||||
{ "cyan", 0x00ffff },
|
||||
{ "cyan1", 0x00ffff },
|
||||
{ "cyan2", 0x00eeee },
|
||||
{ "cyan3", 0x00cdcd },
|
||||
{ "cyan4", 0x008b8b },
|
||||
{ "dark blue", 0x00008b },
|
||||
{ "dark cyan", 0x008b8b },
|
||||
{ "dark goldenrod", 0xb8860b },
|
||||
{ "dark gray", 0xa9a9a9 },
|
||||
{ "dark green", 0x006400 },
|
||||
{ "dark grey", 0xa9a9a9 },
|
||||
{ "dark khaki", 0xbdb76b },
|
||||
{ "dark magenta", 0x8b008b },
|
||||
{ "dark olive green", 0x556b2f },
|
||||
{ "dark orange", 0xff8c00 },
|
||||
{ "dark orchid", 0x9932cc },
|
||||
{ "dark red", 0x8b0000 },
|
||||
{ "dark salmon", 0xe9967a },
|
||||
{ "dark sea green", 0x8fbc8f },
|
||||
{ "dark slate blue", 0x483d8b },
|
||||
{ "dark slate gray", 0x2f4f4f },
|
||||
{ "dark slate grey", 0x2f4f4f },
|
||||
{ "dark turquoise", 0x00ced1 },
|
||||
{ "dark violet", 0x9400d3 },
|
||||
{ "deep pink", 0xff1493 },
|
||||
{ "deep sky blue", 0x00bfff },
|
||||
{ "dim gray", 0x696969 },
|
||||
{ "dim grey", 0x696969 },
|
||||
{ "dodger blue", 0x1e90ff },
|
||||
{ "firebrick", 0xb22222 },
|
||||
{ "firebrick1", 0xff3030 },
|
||||
{ "firebrick2", 0xee2c2c },
|
||||
{ "firebrick3", 0xcd2626 },
|
||||
{ "firebrick4", 0x8b1a1a },
|
||||
{ "floral white", 0xfffaf0 },
|
||||
{ "forest green", 0x228b22 },
|
||||
{ "fuchsia", 0xff00ff },
|
||||
{ "gainsboro", 0xdcdcdc },
|
||||
{ "ghost white", 0xf8f8ff },
|
||||
{ "gold", 0xffd700 },
|
||||
{ "gold1", 0xffd700 },
|
||||
{ "gold2", 0xeec900 },
|
||||
{ "gold3", 0xcdad00 },
|
||||
{ "gold4", 0x8b7500 },
|
||||
{ "goldenrod", 0xdaa520 },
|
||||
{ "goldenrod1", 0xffc125 },
|
||||
{ "goldenrod2", 0xeeb422 },
|
||||
{ "goldenrod3", 0xcd9b1d },
|
||||
{ "goldenrod4", 0x8b6914 },
|
||||
{ "green yellow", 0xadff2f },
|
||||
{ "green", 0x00ff00 },
|
||||
{ "green1", 0x00ff00 },
|
||||
{ "green2", 0x00ee00 },
|
||||
{ "green3", 0x00cd00 },
|
||||
{ "green4", 0x008b00 },
|
||||
{ "honeydew", 0xf0fff0 },
|
||||
{ "honeydew1", 0xf0fff0 },
|
||||
{ "honeydew2", 0xe0eee0 },
|
||||
{ "honeydew3", 0xc1cdc1 },
|
||||
{ "honeydew4", 0x838b83 },
|
||||
{ "hot pink", 0xff69b4 },
|
||||
{ "indian red", 0xcd5c5c },
|
||||
{ "indigo", 0x4b0082 },
|
||||
{ "ivory", 0xfffff0 },
|
||||
{ "ivory1", 0xfffff0 },
|
||||
{ "ivory2", 0xeeeee0 },
|
||||
{ "ivory3", 0xcdcdc1 },
|
||||
{ "ivory4", 0x8b8b83 },
|
||||
{ "khaki", 0xf0e68c },
|
||||
{ "khaki1", 0xfff68f },
|
||||
{ "khaki2", 0xeee685 },
|
||||
{ "khaki3", 0xcdc673 },
|
||||
{ "khaki4", 0x8b864e },
|
||||
{ "lavender blush", 0xfff0f5 },
|
||||
{ "lavender", 0xe6e6fa },
|
||||
{ "lawn green", 0x7cfc00 },
|
||||
{ "lemon chiffon", 0xfffacd },
|
||||
{ "light blue", 0xadd8e6 },
|
||||
{ "light coral", 0xf08080 },
|
||||
{ "light cyan", 0xe0ffff },
|
||||
{ "light goldenrod yellow", 0xfafad2 },
|
||||
{ "light goldenrod", 0xeedd82 },
|
||||
{ "light gray", 0xd3d3d3 },
|
||||
{ "light green", 0x90ee90 },
|
||||
{ "light grey", 0xd3d3d3 },
|
||||
{ "light pink", 0xffb6c1 },
|
||||
{ "light salmon", 0xffa07a },
|
||||
{ "light sea green", 0x20b2aa },
|
||||
{ "light sky blue", 0x87cefa },
|
||||
{ "light slate blue", 0x8470ff },
|
||||
{ "light slate gray", 0x778899 },
|
||||
{ "light slate grey", 0x778899 },
|
||||
{ "light steel blue", 0xb0c4de },
|
||||
{ "light yellow", 0xffffe0 },
|
||||
{ "lime green", 0x32cd32 },
|
||||
{ "lime", 0x00ff00 },
|
||||
{ "linen", 0xfaf0e6 },
|
||||
{ "magenta", 0xff00ff },
|
||||
{ "magenta1", 0xff00ff },
|
||||
{ "magenta2", 0xee00ee },
|
||||
{ "magenta3", 0xcd00cd },
|
||||
{ "magenta4", 0x8b008b },
|
||||
{ "maroon", 0xb03060 },
|
||||
{ "maroon1", 0xff34b3 },
|
||||
{ "maroon2", 0xee30a7 },
|
||||
{ "maroon3", 0xcd2990 },
|
||||
{ "maroon4", 0x8b1c62 },
|
||||
{ "medium aquamarine", 0x66cdaa },
|
||||
{ "medium blue", 0x0000cd },
|
||||
{ "medium orchid", 0xba55d3 },
|
||||
{ "medium purple", 0x9370db },
|
||||
{ "medium sea green", 0x3cb371 },
|
||||
{ "medium slate blue", 0x7b68ee },
|
||||
{ "medium spring green", 0x00fa9a },
|
||||
{ "medium turquoise", 0x48d1cc },
|
||||
{ "medium violet red", 0xc71585 },
|
||||
{ "midnight blue", 0x191970 },
|
||||
{ "mint cream", 0xf5fffa },
|
||||
{ "misty rose", 0xffe4e1 },
|
||||
{ "moccasin", 0xffe4b5 },
|
||||
{ "navajo white", 0xffdead },
|
||||
{ "navy blue", 0x000080 },
|
||||
{ "navy", 0x000080 },
|
||||
{ "old lace", 0xfdf5e6 },
|
||||
{ "olive drab", 0x6b8e23 },
|
||||
{ "olive", 0x808000 },
|
||||
{ "orange red", 0xff4500 },
|
||||
{ "orange", 0xffa500 },
|
||||
{ "orange1", 0xffa500 },
|
||||
{ "orange2", 0xee9a00 },
|
||||
{ "orange3", 0xcd8500 },
|
||||
{ "orange4", 0x8b5a00 },
|
||||
{ "orchid", 0xda70d6 },
|
||||
{ "orchid1", 0xff83fa },
|
||||
{ "orchid2", 0xee7ae9 },
|
||||
{ "orchid3", 0xcd69c9 },
|
||||
{ "orchid4", 0x8b4789 },
|
||||
{ "pale goldenrod", 0xeee8aa },
|
||||
{ "pale green", 0x98fb98 },
|
||||
{ "pale turquoise", 0xafeeee },
|
||||
{ "pale violet red", 0xdb7093 },
|
||||
{ "papaya whip", 0xffefd5 },
|
||||
{ "peach puff", 0xffdab9 },
|
||||
{ "peru", 0xcd853f },
|
||||
{ "pink", 0xffc0cb },
|
||||
{ "pink1", 0xffb5c5 },
|
||||
{ "pink2", 0xeea9b8 },
|
||||
{ "pink3", 0xcd919e },
|
||||
{ "pink4", 0x8b636c },
|
||||
{ "plum", 0xdda0dd },
|
||||
{ "plum1", 0xffbbff },
|
||||
{ "plum2", 0xeeaeee },
|
||||
{ "plum3", 0xcd96cd },
|
||||
{ "plum4", 0x8b668b },
|
||||
{ "powder blue", 0xb0e0e6 },
|
||||
{ "purple", 0xa020f0 },
|
||||
{ "purple1", 0x9b30ff },
|
||||
{ "purple2", 0x912cee },
|
||||
{ "purple3", 0x7d26cd },
|
||||
{ "purple4", 0x551a8b },
|
||||
{ "rebecca purple", 0x663399 },
|
||||
{ "red", 0xff0000 },
|
||||
{ "red1", 0xff0000 },
|
||||
{ "red2", 0xee0000 },
|
||||
{ "red3", 0xcd0000 },
|
||||
{ "red4", 0x8b0000 },
|
||||
{ "rosy brown", 0xbc8f8f },
|
||||
{ "royal blue", 0x4169e1 },
|
||||
{ "saddle brown", 0x8b4513 },
|
||||
{ "salmon", 0xfa8072 },
|
||||
{ "salmon1", 0xff8c69 },
|
||||
{ "salmon2", 0xee8262 },
|
||||
{ "salmon3", 0xcd7054 },
|
||||
{ "salmon4", 0x8b4c39 },
|
||||
{ "sandy brown", 0xf4a460 },
|
||||
{ "sea green", 0x2e8b57 },
|
||||
{ "seashell", 0xfff5ee },
|
||||
{ "seashell1", 0xfff5ee },
|
||||
{ "seashell2", 0xeee5de },
|
||||
{ "seashell3", 0xcdc5bf },
|
||||
{ "seashell4", 0x8b8682 },
|
||||
{ "sienna", 0xa0522d },
|
||||
{ "sienna1", 0xff8247 },
|
||||
{ "sienna2", 0xee7942 },
|
||||
{ "sienna3", 0xcd6839 },
|
||||
{ "sienna4", 0x8b4726 },
|
||||
{ "silver", 0xc0c0c0 },
|
||||
{ "sky blue", 0x87ceeb },
|
||||
{ "slate blue", 0x6a5acd },
|
||||
{ "slate gray", 0x708090 },
|
||||
{ "slate grey", 0x708090 },
|
||||
{ "snow", 0xfffafa },
|
||||
{ "snow1", 0xfffafa },
|
||||
{ "snow2", 0xeee9e9 },
|
||||
{ "snow3", 0xcdc9c9 },
|
||||
{ "snow4", 0x8b8989 },
|
||||
{ "spring green", 0x00ff7f },
|
||||
{ "steel blue", 0x4682b4 },
|
||||
{ "tan", 0xd2b48c },
|
||||
{ "tan1", 0xffa54f },
|
||||
{ "tan2", 0xee9a49 },
|
||||
{ "tan3", 0xcd853f },
|
||||
{ "tan4", 0x8b5a2b },
|
||||
{ "teal", 0x008080 },
|
||||
{ "thistle", 0xd8bfd8 },
|
||||
{ "thistle1", 0xffe1ff },
|
||||
{ "thistle2", 0xeed2ee },
|
||||
{ "thistle3", 0xcdb5cd },
|
||||
{ "thistle4", 0x8b7b8b },
|
||||
{ "tomato", 0xff6347 },
|
||||
{ "tomato1", 0xff6347 },
|
||||
{ "tomato2", 0xee5c42 },
|
||||
{ "tomato3", 0xcd4f39 },
|
||||
{ "tomato4", 0x8b3626 },
|
||||
{ "turquoise", 0x40e0d0 },
|
||||
{ "turquoise1", 0x00f5ff },
|
||||
{ "turquoise2", 0x00e5ee },
|
||||
{ "turquoise3", 0x00c5cd },
|
||||
{ "turquoise4", 0x00868b },
|
||||
{ "violet red", 0xd02090 },
|
||||
{ "violet", 0xee82ee },
|
||||
{ "web gray", 0x808080 },
|
||||
{ "web green", 0x008000 },
|
||||
{ "web grey", 0x808080 },
|
||||
{ "web maroon", 0x800000 },
|
||||
{ "web purple", 0x800080 },
|
||||
{ "wheat", 0xf5deb3 },
|
||||
{ "wheat1", 0xffe7ba },
|
||||
{ "wheat2", 0xeed8ae },
|
||||
{ "wheat3", 0xcdba96 },
|
||||
{ "wheat4", 0x8b7e66 },
|
||||
{ "white smoke", 0xf5f5f5 },
|
||||
{ "white", 0xffffff },
|
||||
{ "x11 gray", 0xbebebe },
|
||||
{ "x11 green", 0x00ff00 },
|
||||
{ "x11 grey", 0xbebebe },
|
||||
{ "x11 maroon", 0xb03060 },
|
||||
{ "x11 purple", 0xa020f0 },
|
||||
{ "yellow green", 0x9acd32 },
|
||||
{ "yellow", 0xffff00 },
|
||||
{ "yellow1", 0xffff00 },
|
||||
{ "yellow2", 0xeeee00 },
|
||||
{ "yellow3", 0xcdcd00 },
|
||||
{ "yellow4", 0x8b8b00 }
|
||||
COLOURS
|
||||
LC_ALL=C sort -f |
|
||||
awk -F '|' '
|
||||
function h2d(s, i, n, c, p) {
|
||||
n = 0
|
||||
for (i = 1; i <= length(s); i++) {
|
||||
c = substr(s, i, 1)
|
||||
p = index("0123456789abcdef", tolower(c))
|
||||
if (p == 0)
|
||||
return -1
|
||||
n = n * 16 + p - 1
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
{
|
||||
name[NR] = $1
|
||||
hex[NR] = $2
|
||||
if (length($1) > width)
|
||||
width = length($1)
|
||||
}
|
||||
|
||||
END {
|
||||
esc = sprintf("%c", 27)
|
||||
|
||||
for (i = 1; i <= NR; i++) {
|
||||
r = h2d(substr(hex[i], 1, 2))
|
||||
g = h2d(substr(hex[i], 3, 2))
|
||||
b = h2d(substr(hex[i], 5, 2))
|
||||
|
||||
printf "%-*s %s[38;2;%d;%d;%dmXXXXXXXX%s[0m %s[48;2;%d;%d;%dm %s[0m\n", \
|
||||
width, name[i], esc, r, g, b, esc, esc, r, g, b, esc
|
||||
}
|
||||
}
|
||||
'
|
||||
@@ -580,6 +580,7 @@ tty_default_features(int *feat, const char *name, u_int version)
|
||||
"cstyle,"
|
||||
"extkeys,"
|
||||
"focus,"
|
||||
"hyperlinks,"
|
||||
"usstyle"
|
||||
},
|
||||
{ .name = "XTerm",
|
||||
|
||||
41
tty.c
41
tty.c
@@ -51,6 +51,7 @@ static void tty_check_bg(struct tty *, struct colour_palette *,
|
||||
struct grid_cell *);
|
||||
static void tty_check_us(struct tty *, struct colour_palette *,
|
||||
struct grid_cell *);
|
||||
static int tty_map_theme_colour(struct tty *, int);
|
||||
static void tty_colours_fg(struct tty *, const struct grid_cell *);
|
||||
static void tty_colours_bg(struct tty *, const struct grid_cell *);
|
||||
static void tty_colours_us(struct tty *, const struct grid_cell *);
|
||||
@@ -752,8 +753,10 @@ tty_force_cursor_colour(struct tty *tty, int c)
|
||||
u_char r, g, b;
|
||||
char s[13];
|
||||
|
||||
if (c != -1)
|
||||
if (c != -1) {
|
||||
c = tty_map_theme_colour(tty, c);
|
||||
c = colour_force_rgb(c);
|
||||
}
|
||||
if (c == tty->ccolour)
|
||||
return;
|
||||
if (c == -1)
|
||||
@@ -1545,20 +1548,20 @@ tty_set_client_cb(struct tty_ctx *ttyctx, struct client *c)
|
||||
}
|
||||
|
||||
void
|
||||
tty_draw_images(struct client *c, struct window_pane *wp, struct screen *s)
|
||||
tty_draw_images(struct client *c, struct window_pane *wp)
|
||||
{
|
||||
struct image *im;
|
||||
struct tty_ctx ttyctx;
|
||||
|
||||
TAILQ_FOREACH(im, &s->images, entry) {
|
||||
TAILQ_FOREACH(im, &wp->screen->images, entry) {
|
||||
memset(&ttyctx, 0, sizeof ttyctx);
|
||||
|
||||
/* Set the client independent properties. */
|
||||
ttyctx.ocx = im->px;
|
||||
ttyctx.ocy = im->py;
|
||||
|
||||
ttyctx.orlower = s->rlower;
|
||||
ttyctx.orupper = s->rupper;
|
||||
ttyctx.orlower = wp->screen->rlower;
|
||||
ttyctx.orupper = wp->screen->rupper;
|
||||
|
||||
ttyctx.xoff = ttyctx.rxoff = wp->xoff;
|
||||
ttyctx.sx = wp->sx;
|
||||
@@ -2780,6 +2783,9 @@ tty_attributes(struct tty *tty, const struct grid_cell *gc,
|
||||
gc2.bg = changed;
|
||||
}
|
||||
}
|
||||
gc2.fg = tty_map_theme_colour(tty, gc2.fg);
|
||||
gc2.bg = tty_map_theme_colour(tty, gc2.bg);
|
||||
gc2.us = tty_map_theme_colour(tty, gc2.us);
|
||||
if (style_ctx->dim != 0) {
|
||||
gc2.fg = tty_dim_default_colour(tty, gc2.fg, 1);
|
||||
gc2.bg = tty_dim_default_colour(tty, gc2.bg, 0);
|
||||
@@ -2929,6 +2935,28 @@ tty_colours(struct tty *tty, const struct grid_cell *gc)
|
||||
tty_colours_us(tty, gc);
|
||||
}
|
||||
|
||||
static int
|
||||
tty_map_theme_colour(struct tty *tty, int colour)
|
||||
{
|
||||
struct client *c;
|
||||
u_int n;
|
||||
int m;
|
||||
|
||||
if (~colour & COLOUR_FLAG_THEME)
|
||||
return (colour);
|
||||
|
||||
n = colour & 0xff;
|
||||
if (n >= COLOUR_THEME_COUNT)
|
||||
return (8);
|
||||
if (tty == NULL || (c = tty->client) == NULL)
|
||||
return (8);
|
||||
|
||||
m = c->theme_colours[n];
|
||||
if (m == -1 || (m & COLOUR_FLAG_THEME))
|
||||
return (8);
|
||||
return (m);
|
||||
}
|
||||
|
||||
static void
|
||||
tty_check_fg(struct tty *tty, struct colour_palette *palette,
|
||||
struct grid_cell *gc)
|
||||
@@ -2951,6 +2979,7 @@ tty_check_fg(struct tty *tty, struct colour_palette *palette,
|
||||
if ((c = colour_palette_get(palette, c)) != -1)
|
||||
gc->fg = c;
|
||||
}
|
||||
gc->fg = tty_map_theme_colour(tty, gc->fg);
|
||||
|
||||
/* Is this a 24-bit colour? */
|
||||
if (gc->fg & COLOUR_FLAG_RGB) {
|
||||
@@ -3011,6 +3040,7 @@ tty_check_bg(struct tty *tty, struct colour_palette *palette,
|
||||
if ((c = colour_palette_get(palette, gc->bg)) != -1)
|
||||
gc->bg = c;
|
||||
}
|
||||
gc->bg = tty_map_theme_colour(tty, gc->bg);
|
||||
|
||||
/* Is this a 24-bit colour? */
|
||||
if (gc->bg & COLOUR_FLAG_RGB) {
|
||||
@@ -3061,6 +3091,7 @@ tty_check_us(__unused struct tty *tty, struct colour_palette *palette,
|
||||
if ((c = colour_palette_get(palette, gc->us)) != -1)
|
||||
gc->us = c;
|
||||
}
|
||||
gc->us = tty_map_theme_colour(tty, gc->us);
|
||||
|
||||
/* Convert underscore colour if only RGB can be supported. */
|
||||
if (!tty_term_has(tty->term, TTYC_SETULC1)) {
|
||||
|
||||
171
window-border.c
Normal file
171
window-border.c
Normal file
@@ -0,0 +1,171 @@
|
||||
/* $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 <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
/* Get border cell. */
|
||||
void
|
||||
window_get_border_cell(struct window *w, struct window_pane *wp,
|
||||
enum pane_lines pane_lines, int cell_type, struct grid_cell *gc)
|
||||
{
|
||||
u_int idx;
|
||||
|
||||
if (cell_type == CELL_NONE && w->fill_character != NULL) {
|
||||
utf8_copy(&gc->data, &w->fill_character[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (pane_lines) {
|
||||
case PANE_LINES_NUMBER:
|
||||
if (cell_type == CELL_NONE) {
|
||||
gc->attr |= GRID_ATTR_CHARSET;
|
||||
utf8_set(&gc->data, CELL_BORDERS[CELL_NONE]);
|
||||
break;
|
||||
}
|
||||
gc->attr &= ~GRID_ATTR_CHARSET;
|
||||
if (wp != NULL && window_pane_index(wp, &idx) == 0)
|
||||
utf8_set(&gc->data, '0' + (idx % 10));
|
||||
else
|
||||
utf8_set(&gc->data, '*');
|
||||
break;
|
||||
case PANE_LINES_DOUBLE:
|
||||
gc->attr &= ~GRID_ATTR_CHARSET;
|
||||
utf8_copy(&gc->data, tty_acs_double_borders(cell_type));
|
||||
break;
|
||||
case PANE_LINES_HEAVY:
|
||||
gc->attr &= ~GRID_ATTR_CHARSET;
|
||||
utf8_copy(&gc->data, tty_acs_heavy_borders(cell_type));
|
||||
break;
|
||||
case PANE_LINES_SIMPLE:
|
||||
gc->attr &= ~GRID_ATTR_CHARSET;
|
||||
utf8_set(&gc->data, SIMPLE_BORDERS[cell_type]);
|
||||
break;
|
||||
case PANE_LINES_NONE:
|
||||
case PANE_LINES_SPACES:
|
||||
gc->attr &= ~GRID_ATTR_CHARSET;
|
||||
utf8_set(&gc->data, ' ');
|
||||
break;
|
||||
default:
|
||||
gc->attr |= GRID_ATTR_CHARSET;
|
||||
utf8_set(&gc->data, CELL_BORDERS[cell_type]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get pane border cell. */
|
||||
void
|
||||
window_pane_get_border_cell(struct window_pane *wp, int cell_type,
|
||||
struct grid_cell *gc)
|
||||
{
|
||||
enum pane_lines pane_lines = window_pane_get_pane_lines(wp);
|
||||
|
||||
window_get_border_cell(wp->window, wp, pane_lines, cell_type, gc);
|
||||
}
|
||||
|
||||
/* Get pane border style. */
|
||||
void
|
||||
window_pane_get_border_style(struct window_pane *wp, struct client *c,
|
||||
struct grid_cell *gc)
|
||||
{
|
||||
struct session *s = c->session;
|
||||
struct format_tree *ft;
|
||||
const char *option;
|
||||
struct grid_cell *saved;
|
||||
int *flag;
|
||||
|
||||
if (wp == server_client_get_pane(c)) {
|
||||
flag = &wp->active_border_gc_set;
|
||||
saved = &wp->active_border_gc;
|
||||
option = "pane-active-border-style";
|
||||
} else {
|
||||
flag = &wp->border_gc_set;
|
||||
saved = &wp->border_gc;
|
||||
option = "pane-border-style";
|
||||
}
|
||||
|
||||
if (!*flag) {
|
||||
ft = format_create_defaults(NULL, c, s, s->curw, wp);
|
||||
style_apply(saved, wp->options, option, ft);
|
||||
format_free(ft);
|
||||
*flag = 1;
|
||||
}
|
||||
memcpy(gc, saved, sizeof *gc);
|
||||
}
|
||||
|
||||
/* Build pane status line. */
|
||||
int
|
||||
window_make_pane_status(struct window_pane *wp, struct client *c, u_int width,
|
||||
struct redraw_span *span)
|
||||
{
|
||||
struct grid_cell gc;
|
||||
const char *fmt;
|
||||
struct format_tree *ft;
|
||||
struct style_line_entry *sle = &wp->border_status_line;
|
||||
struct screen_write_ctx ctx;
|
||||
struct screen old;
|
||||
char *expanded;
|
||||
u_int i;
|
||||
enum pane_lines pane_lines;
|
||||
int pane_status, cell_type;
|
||||
|
||||
pane_status = window_pane_get_pane_status(wp);
|
||||
if (pane_status == PANE_STATUS_OFF || width == 0)
|
||||
return (0);
|
||||
|
||||
ft = format_create(c, NULL, FORMAT_PANE|wp->id, FORMAT_STATUS);
|
||||
format_defaults(ft, c, c->session, c->session->curw, wp);
|
||||
|
||||
fmt = options_get_string(wp->options, "pane-border-format");
|
||||
expanded = format_expand_time(ft, fmt);
|
||||
|
||||
memcpy(&old, &wp->status_screen, sizeof old);
|
||||
screen_init(&wp->status_screen, width, 1, 0);
|
||||
wp->status_screen.mode = 0;
|
||||
screen_write_start(&ctx, &wp->status_screen);
|
||||
|
||||
window_pane_get_border_style(wp, c, &gc);
|
||||
pane_lines = window_pane_get_pane_lines(wp);
|
||||
for (i = 0; i < width; i++) {
|
||||
cell_type = redraw_get_status_border_cell_type(&span, i);
|
||||
window_get_border_cell(wp->window, wp, pane_lines, cell_type, &gc);
|
||||
screen_write_cell(&ctx, &gc);
|
||||
}
|
||||
gc.attr &= ~GRID_ATTR_CHARSET;
|
||||
|
||||
screen_write_cursormove(&ctx, 0, 0, 0);
|
||||
style_ranges_free(&sle->ranges);
|
||||
format_draw(&ctx, &gc, width, expanded, &sle->ranges, 0);
|
||||
|
||||
screen_write_stop(&ctx);
|
||||
format_free(ft);
|
||||
|
||||
free(sle->expanded);
|
||||
sle->expanded = expanded;
|
||||
|
||||
if (grid_compare(wp->status_screen.grid, old.grid) == 0) {
|
||||
screen_free(&old);
|
||||
return (0);
|
||||
}
|
||||
screen_free(&old);
|
||||
return (1);
|
||||
}
|
||||
@@ -336,13 +336,20 @@ window_buffer_sort(struct sort_criteria *sort_crit)
|
||||
}
|
||||
|
||||
static const char* window_buffer_help_lines[] = {
|
||||
"#[bold] Enter #[default]#[acs]x#[default] Paste selected %1",
|
||||
"#[bold] p #[default]#[acs]x#[default] Paste selected %1",
|
||||
"#[bold] P #[default]#[acs]x#[default] Paste tagged %1s",
|
||||
"#[bold] d #[default]#[acs]x#[default] Delete selected %1",
|
||||
"#[bold] D #[default]#[acs]x#[default] Delete tagged %1s",
|
||||
"#[bold] e #[default]#[acs]x#[default] Open %1 in editor",
|
||||
"#[bold] f #[default]#[acs]x#[default] Enter a filter",
|
||||
"#[fg=themelightgrey]"
|
||||
" Enter #[#{E:tree-mode-border-style},acs]x#[default] Paste selected %1",
|
||||
"#[fg=themelightgrey]"
|
||||
" p #[#{E:tree-mode-border-style},acs]x#[default] Paste selected %1",
|
||||
"#[fg=themelightgrey]"
|
||||
" P #[#{E:tree-mode-border-style},acs]x#[default] Paste tagged %1s",
|
||||
"#[fg=themelightgrey]"
|
||||
" d #[#{E:tree-mode-border-style},acs]x#[default] Delete selected %1",
|
||||
"#[fg=themelightgrey]"
|
||||
" D #[#{E:tree-mode-border-style},acs]x#[default] Delete tagged %1s",
|
||||
"#[fg=themelightgrey]"
|
||||
" e #[#{E:tree-mode-border-style},acs]x#[default] Open %1 in editor",
|
||||
"#[fg=themelightgrey]"
|
||||
" f #[#{E:tree-mode-border-style},acs]x#[default] Enter a filter",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
129
window-client.c
129
window-client.c
@@ -38,7 +38,7 @@ static void window_client_key(struct window_mode_entry *,
|
||||
#define WINDOW_CLIENT_DEFAULT_COMMAND "detach-client -t '%%'"
|
||||
|
||||
#define WINDOW_CLIENT_DEFAULT_FORMAT \
|
||||
"#{t/p:client_activity}: session #{session_name}"
|
||||
"#[fg=themelightgrey]#{t/p:client_activity}: session #[default]#{session_name}"
|
||||
|
||||
#define WINDOW_CLIENT_DEFAULT_KEY_FORMAT \
|
||||
"#{?#{e|<:#{line},10}," \
|
||||
@@ -49,87 +49,91 @@ static void window_client_key(struct window_mode_entry *,
|
||||
|
||||
#define WINDOW_CLIENT_FEATURE(f) \
|
||||
"#{?#{I/f:" #f "}," \
|
||||
"#[fg=green],#[dim]}#{p/15:#{l:" #f "}}" \
|
||||
"#[fg=themegreen],#[fg=themelightgrey]}#{p/15:#{l:" #f "}}" \
|
||||
"#[default]"
|
||||
static const char *window_client_info_lines[] = {
|
||||
"Client Name #[acs]x#[default] "
|
||||
"#{client_name} "
|
||||
"#[dim](PID #{client_pid})#[default]",
|
||||
"Session #[acs]x#[default] "
|
||||
"#[fg=themelightgrey]Client Name #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
"#{client_name} #[fg=themelightgrey]"
|
||||
"#[fg=themelightgrey](PID #{client_pid})#[default]",
|
||||
"#[fg=themelightgrey]Session #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
"#{session_name}",
|
||||
"Attach Time #[acs]x#[default] "
|
||||
"#[fg=themelightgrey]Attach Time #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
"#{t:client_created} "
|
||||
"#[dim](#{t/r:client_created})#[default]",
|
||||
"Activity Time #[acs]x#[default] "
|
||||
"#[fg=themelightgrey](#{t/r:client_created})#[default]",
|
||||
"#[fg=themelightgrey]Activity Time #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
"#{t:client_activity} "
|
||||
"#[dim](#{t/r:client_activity})#[default]",
|
||||
"Terminal Type #[acs]x#[default] "
|
||||
"#[fg=themelightgrey](#{t/r:client_activity})#[default]",
|
||||
"#[fg=themelightgrey]Terminal Type #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
"#{?client_termtype,#{client_termtype},Unknown}",
|
||||
"TERM #[acs]x#[default] "
|
||||
"#[fg=themelightgrey]TERM #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
"#{client_termname}",
|
||||
"Size #[acs]x#[default] "
|
||||
"#[fg=themelightgrey]Size #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
"#{client_width}x#{client_height} "
|
||||
"#[dim](cell #{client_cell_width}x#{client_cell_height})#[default]",
|
||||
"Bytes Written #[acs]x#[default] "
|
||||
"#[fg=themelightgrey](cell #{client_cell_width}x"
|
||||
"#{client_cell_height})#[default]",
|
||||
"#[fg=themelightgrey]Bytes Written #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
"#{client_written} "
|
||||
"#[dim](#{client_discarded} discarded)#[default]",
|
||||
"#[fg=themelightgrey](#{client_discarded} discarded)#[default]",
|
||||
|
||||
"Features #[acs]x#[default] "
|
||||
"#[fg=themelightgrey]Features #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
WINDOW_CLIENT_FEATURE(256) " "
|
||||
WINDOW_CLIENT_FEATURE(RGB) " "
|
||||
WINDOW_CLIENT_FEATURE(bpaste) " "
|
||||
WINDOW_CLIENT_FEATURE(ccolour),
|
||||
" #[acs]x#[default] "
|
||||
" #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
WINDOW_CLIENT_FEATURE(clipboard) " "
|
||||
WINDOW_CLIENT_FEATURE(cstyle) " "
|
||||
WINDOW_CLIENT_FEATURE(extkeys) " "
|
||||
WINDOW_CLIENT_FEATURE(focus),
|
||||
" #[acs]x#[default] "
|
||||
" #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
WINDOW_CLIENT_FEATURE(hyperlinks) " "
|
||||
WINDOW_CLIENT_FEATURE(ignorefkeys) " "
|
||||
WINDOW_CLIENT_FEATURE(margins) " "
|
||||
WINDOW_CLIENT_FEATURE(mouse),
|
||||
" #[acs]x#[default] "
|
||||
" #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
WINDOW_CLIENT_FEATURE(osc7) " "
|
||||
WINDOW_CLIENT_FEATURE(overline) " "
|
||||
WINDOW_CLIENT_FEATURE(progressbar) " "
|
||||
WINDOW_CLIENT_FEATURE(rectfill),
|
||||
" #[acs]x#[default] "
|
||||
" #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
WINDOW_CLIENT_FEATURE(sixel) " "
|
||||
WINDOW_CLIENT_FEATURE(strikethrough) " "
|
||||
WINDOW_CLIENT_FEATURE(sync) " "
|
||||
WINDOW_CLIENT_FEATURE(title),
|
||||
" #[acs]x#[default] "
|
||||
" #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
WINDOW_CLIENT_FEATURE(usstyle),
|
||||
"#[acs]qqqqqqqqqqqqqqn#{R:q,#{window_width}}#[default]",
|
||||
"#[#{E:tree-mode-border-style},acs]qqqqqqqqqqqqqqn#{R:q,#{window_width}}#[default]",
|
||||
|
||||
"prefix #[acs]x#[default] "
|
||||
"#[fg=themelightgrey]prefix #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
"#{prefix}",
|
||||
|
||||
"mouse #[acs]x#[default] "
|
||||
"#{?mouse,#{?#{I/c:kmous},,#[fg=red]}on,#[dim]off} "
|
||||
"#[fg=themelightgrey]mouse #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
"#{?mouse,#{?#{I/c:kmous},,#[fg=themered]}on,#[fg=themelightgrey]off} "
|
||||
"#{?#{I/c:kmous},,#[align=right]unavailable: [kmous] missing}",
|
||||
|
||||
"set-clipboard #[acs]x#[default] "
|
||||
"#{?#{!=:#{set-clipboard},off},#{?#{I/f:clipboard},,#[fg=red]}#{set-clipboard},#[dim]off} "
|
||||
"#[fg=themelightgrey]set-clipboard #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
"#{?#{!=:#{set-clipboard},off},#{?#{I/f:clipboard},,"
|
||||
"#[fg=themered]}#{set-clipboard},#[fg=themelightgrey]off} "
|
||||
"#{?#{I/f:clipboard},,#[align=right]unavailable: [Ms] missing}",
|
||||
|
||||
"get-clipboard #[acs]x#[default] "
|
||||
"#{?#{!=:#{get-clipboard},off},#{?#{I/f:clipboard},,#[fg=red]}#{get-clipboard},#[dim]off} "
|
||||
"#[fg=themelightgrey]get-clipboard #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
"#{?#{!=:#{get-clipboard},off},#{?#{I/f:clipboard},,"
|
||||
"#[fg=themered]}#{get-clipboard},#[fg=themelightgrey]off} "
|
||||
"#{?#{I/f:clipboard},,#[align=right]unavailable: [Ms] missing}",
|
||||
|
||||
"focus-events #[acs]x#[default] "
|
||||
"#{?focus-events,#{?#{I/f:focus},,#[fg=red]}on,#[dim]off} "
|
||||
"#[fg=themelightgrey]focus-events #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
"#{?focus-events,#{?#{I/f:focus},,#[fg=themered]}on,#[fg=themelightgrey]off} "
|
||||
"#{?#{I/f:focus},,#[align=right]unavailable: [Enfcs] or [Dcfcs] missing}",
|
||||
|
||||
"extended-keys #[acs]x#[default] "
|
||||
"#{?#{!=:#{extended-keys},off},#{?#{I/f:extkeys},,#[fg=red]}#{extended-keys},#[dim]off} "
|
||||
"#[fg=themelightgrey]extended-keys #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
"#{?#{!=:#{extended-keys},off},#{?#{I/f:extkeys},,"
|
||||
"#[fg=themered]}#{extended-keys},#[fg=themelightgrey]off} "
|
||||
"#{?#{I/f:extkeys},,#[align=right]unavailable: [Eneks] or [Dseks] missing}",
|
||||
|
||||
"set-titles #[acs]x#[default] "
|
||||
"#{?set-titles,on,#[dim]off}",
|
||||
"#[fg=themelightgrey]set-titles #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
"#{?set-titles,on,#[fg=themelightgrey]off}",
|
||||
|
||||
"escape-time #[acs]x#[default] "
|
||||
"#[fg=themelightgrey]escape-time #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
"#{escape-time} ms",
|
||||
};
|
||||
|
||||
@@ -258,6 +262,8 @@ window_client_draw_info(__unused void *modedata, void *itemdata,
|
||||
struct window_client_itemdata *item = itemdata;
|
||||
struct client *c = item->c;
|
||||
struct screen *s = ctx->s;
|
||||
struct window *w = c->session->curw->window;
|
||||
struct grid_cell gc;
|
||||
u_int cx = s->cx, cy = s->cy, i;
|
||||
struct format_tree *ft;
|
||||
char *expanded;
|
||||
@@ -273,6 +279,12 @@ window_client_draw_info(__unused void *modedata, void *itemdata,
|
||||
format_draw(ctx, &grid_default_cell, sx, expanded, NULL, 0);
|
||||
free(expanded);
|
||||
}
|
||||
if (sx > 14 && i < sy) {
|
||||
memcpy(&gc, &grid_default_cell, sizeof gc);
|
||||
style_apply(&gc, w->options, "tree-mode-border-style", NULL);
|
||||
screen_write_cursormove(ctx, cx + 14, cy + i, 0);
|
||||
screen_write_vline(ctx, sy - i, 0, 0, &gc);
|
||||
}
|
||||
|
||||
format_free(ft);
|
||||
}
|
||||
@@ -284,20 +296,24 @@ window_client_draw(void *modedata, void *itemdata,
|
||||
struct window_client_modedata *data = modedata;
|
||||
struct window_client_itemdata *item = itemdata;
|
||||
struct client *c = item->c;
|
||||
struct session *session = c->session;
|
||||
struct screen *s = ctx->s;
|
||||
struct window *w;
|
||||
struct window_pane *wp;
|
||||
struct grid_cell gc;
|
||||
u_int cx = s->cx, cy = s->cy, lines, at;
|
||||
|
||||
if (c->session == NULL || (c->flags & CLIENT_UNATTACHEDFLAGS))
|
||||
if (session == NULL || (c->flags & CLIENT_UNATTACHEDFLAGS))
|
||||
return;
|
||||
if (data->preview_is_info) {
|
||||
window_client_draw_info(modedata, itemdata, ctx, sx, sy);
|
||||
return;
|
||||
}
|
||||
wp = c->session->curw->window->active;
|
||||
w = session->curw->window;
|
||||
wp = w->active;
|
||||
if (data->hide_preview_this_pane && wp == data->wp) {
|
||||
if (!TAILQ_EMPTY(&c->session->curw->window->last_panes))
|
||||
wp = TAILQ_FIRST(&c->session->curw->window->last_panes);
|
||||
if (!TAILQ_EMPTY(&w->last_panes))
|
||||
wp = TAILQ_FIRST(&w->last_panes);
|
||||
else
|
||||
wp = NULL;
|
||||
}
|
||||
@@ -318,7 +334,9 @@ window_client_draw(void *modedata, void *itemdata,
|
||||
screen_write_cursormove(ctx, cx, cy + 2, 0);
|
||||
else
|
||||
screen_write_cursormove(ctx, cx, cy + sy - 1 - lines, 0);
|
||||
screen_write_hline(ctx, sx, 0, 0, BOX_LINES_DEFAULT, NULL);
|
||||
memcpy(&gc, &grid_default_cell, sizeof gc);
|
||||
style_apply(&gc, w->options, "tree-mode-border-style", NULL);
|
||||
screen_write_hline(ctx, sx, 0, 0, BOX_LINES_DEFAULT, &gc);
|
||||
|
||||
if (at != 0)
|
||||
screen_write_cursormove(ctx, cx, cy, 0);
|
||||
@@ -369,15 +387,24 @@ window_client_sort(struct sort_criteria *sort_crit)
|
||||
}
|
||||
|
||||
static const char* window_client_help_lines[] = {
|
||||
"#[bold] i #[default]#[acs]x#[default] Toggle info view",
|
||||
"#[bold] Enter #[default]#[acs]x#[default] Choose selected %1",
|
||||
"#[bold] d #[default]#[acs]x#[default] Detach selected %1",
|
||||
"#[bold] D #[default]#[acs]x#[default] Detach tagged %1s",
|
||||
"#[bold] x #[default]#[acs]x#[default] Detach selected %1",
|
||||
"#[bold] X #[default]#[acs]x#[default] Detach tagged %1s",
|
||||
"#[bold] z #[default]#[acs]x#[default] Suspend selected %1",
|
||||
"#[bold] Z #[default]#[acs]x#[default] Suspend tagged %1s",
|
||||
"#[bold] f #[default]#[acs]x#[default] Enter a filter",
|
||||
"#[fg=themelightgrey]"
|
||||
" i #[#{E:tree-mode-border-style},acs]x#[default] Toggle info view",
|
||||
"#[fg=themelightgrey]"
|
||||
" Enter #[#{E:tree-mode-border-style},acs]x#[default] Choose selected %1",
|
||||
"#[fg=themelightgrey]"
|
||||
" d #[#{E:tree-mode-border-style},acs]x#[default] Detach selected %1",
|
||||
"#[fg=themelightgrey]"
|
||||
" D #[#{E:tree-mode-border-style},acs]x#[default] Detach tagged %1s",
|
||||
"#[fg=themelightgrey]"
|
||||
" x #[#{E:tree-mode-border-style},acs]x#[default] Detach selected %1",
|
||||
"#[fg=themelightgrey]"
|
||||
" X #[#{E:tree-mode-border-style},acs]x#[default] Detach tagged %1s",
|
||||
"#[fg=themelightgrey]"
|
||||
" z #[#{E:tree-mode-border-style},acs]x#[default] Suspend selected %1",
|
||||
"#[fg=themelightgrey]"
|
||||
" Z #[#{E:tree-mode-border-style},acs]x#[default] Suspend tagged %1s",
|
||||
"#[fg=themelightgrey]"
|
||||
" f #[#{E:tree-mode-border-style},acs]x#[default] Enter a filter",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
@@ -222,18 +222,23 @@ static void
|
||||
window_clock_draw_screen(struct window_mode_entry *wme)
|
||||
{
|
||||
struct window_pane *wp = wme->wp;
|
||||
struct window *w = wp->window;
|
||||
struct window_clock_mode_data *data = wme->data;
|
||||
struct screen_write_ctx ctx;
|
||||
int colour, style;
|
||||
struct screen *s = &data->screen;
|
||||
struct grid_cell gc;
|
||||
struct format_tree *ft;
|
||||
char tim[64], *ptr;
|
||||
time_t t;
|
||||
struct tm *tm;
|
||||
u_int i, j, x, y, idx;
|
||||
|
||||
colour = options_get_number(wp->window->options, "clock-mode-colour");
|
||||
style = options_get_number(wp->window->options, "clock-mode-style");
|
||||
ft = format_create_defaults(NULL, NULL, NULL, NULL, wp);
|
||||
style_apply(&gc, w->options, "clock-mode-colour", ft);
|
||||
format_free(ft);
|
||||
colour = gc.fg;
|
||||
style = options_get_number(w->options, "clock-mode-style");
|
||||
|
||||
screen_write_start(&ctx, s);
|
||||
|
||||
|
||||
@@ -61,8 +61,10 @@ static int window_copy_line_number_mode(struct window_mode_entry *);
|
||||
static int window_copy_line_number_is_absolute(struct window_mode_entry *);
|
||||
static int window_copy_line_numbers_active(struct window_mode_entry *);
|
||||
static u_int window_copy_line_number_width(struct window_mode_entry *);
|
||||
static u_int window_copy_cursor_offset(struct window_mode_entry *, u_int, u_int);
|
||||
static u_int window_copy_cursor_unoffset(struct window_mode_entry *, u_int, u_int);
|
||||
static u_int window_copy_cursor_offset(struct window_mode_entry *, u_int,
|
||||
u_int);
|
||||
static u_int window_copy_cursor_unoffset(struct window_mode_entry *, u_int,
|
||||
u_int);
|
||||
static void window_copy_write_line(struct window_mode_entry *,
|
||||
struct screen_write_ctx *, u_int);
|
||||
static void window_copy_write_lines(struct window_mode_entry *,
|
||||
@@ -800,7 +802,7 @@ window_copy_scroll1(struct window_mode_entry *wme, struct window_pane *wp,
|
||||
return;
|
||||
|
||||
/*
|
||||
* See screen_redraw_draw_pane_scrollbar - this is the inverse of the
|
||||
* See redraw_draw_pane_scrollbar - this is the inverse of the
|
||||
* formula used there.
|
||||
*/
|
||||
new_offset = new_slider_y * ((float)(size + sb_height) / sb_height);
|
||||
@@ -860,6 +862,7 @@ window_copy_scroll1(struct window_mode_entry *wme, struct window_pane *wp,
|
||||
if (data->searchmark != NULL && !data->timeout)
|
||||
window_copy_search_marks(wme, NULL, data->searchregex, 1);
|
||||
window_copy_update_selection(wme, 1, 0);
|
||||
window_pane_scrollbar_show(wp, 1);
|
||||
window_copy_redraw_screen(wme);
|
||||
}
|
||||
|
||||
@@ -913,6 +916,7 @@ window_copy_pageup1(struct window_mode_entry *wme, int half_page)
|
||||
if (data->searchmark != NULL && !data->timeout)
|
||||
window_copy_search_marks(wme, NULL, data->searchregex, 1);
|
||||
window_copy_update_selection(wme, 1, 0);
|
||||
window_pane_scrollbar_show(wme->wp, 1);
|
||||
window_copy_redraw_screen(wme);
|
||||
}
|
||||
|
||||
@@ -973,6 +977,7 @@ window_copy_pagedown1(struct window_mode_entry *wme, int half_page,
|
||||
if (data->searchmark != NULL && !data->timeout)
|
||||
window_copy_search_marks(wme, NULL, data->searchregex, 1);
|
||||
window_copy_update_selection(wme, 1, 0);
|
||||
window_pane_scrollbar_show(wme->wp, 1);
|
||||
window_copy_redraw_screen(wme);
|
||||
return (0);
|
||||
}
|
||||
@@ -1789,7 +1794,7 @@ window_copy_cmd_history_bottom(struct window_copy_cmd_state *cs)
|
||||
struct window_mode_entry *wme = cs->wme;
|
||||
struct window_copy_mode_data *data = wme->data;
|
||||
struct screen *s = data->backing;
|
||||
u_int oy;
|
||||
u_int oy, old_oy = data->oy;
|
||||
|
||||
oy = screen_hsize(s) + data->cy - data->oy;
|
||||
if (data->lineflag == LINE_SEL_RIGHT_LEFT && oy == data->endsely)
|
||||
@@ -1802,6 +1807,8 @@ window_copy_cmd_history_bottom(struct window_copy_cmd_state *cs)
|
||||
if (data->searchmark != NULL && !data->timeout)
|
||||
window_copy_search_marks(wme, NULL, data->searchregex, 1);
|
||||
window_copy_update_selection(wme, 1, 0);
|
||||
if (data->oy != old_oy)
|
||||
window_pane_scrollbar_show(wme->wp, 1);
|
||||
return (WINDOW_COPY_CMD_REDRAW);
|
||||
}
|
||||
|
||||
@@ -1810,7 +1817,7 @@ window_copy_cmd_history_top(struct window_copy_cmd_state *cs)
|
||||
{
|
||||
struct window_mode_entry *wme = cs->wme;
|
||||
struct window_copy_mode_data *data = wme->data;
|
||||
u_int oy;
|
||||
u_int oy, old_oy = data->oy;
|
||||
|
||||
oy = screen_hsize(data->backing) + data->cy - data->oy;
|
||||
if (data->lineflag == LINE_SEL_LEFT_RIGHT && oy == data->sely)
|
||||
@@ -1823,6 +1830,8 @@ window_copy_cmd_history_top(struct window_copy_cmd_state *cs)
|
||||
if (data->searchmark != NULL && !data->timeout)
|
||||
window_copy_search_marks(wme, NULL, data->searchregex, 1);
|
||||
window_copy_update_selection(wme, 1, 0);
|
||||
if (data->oy != old_oy)
|
||||
window_pane_scrollbar_show(wme->wp, 1);
|
||||
return (WINDOW_COPY_CMD_REDRAW);
|
||||
}
|
||||
|
||||
@@ -3772,7 +3781,7 @@ window_copy_scroll_to(struct window_mode_entry *wme, u_int px, u_int py,
|
||||
{
|
||||
struct window_copy_mode_data *data = wme->data;
|
||||
struct grid *gd = data->backing->grid;
|
||||
u_int offset, gap;
|
||||
u_int offset, gap, old_oy = data->oy;
|
||||
|
||||
data->cx = px;
|
||||
|
||||
@@ -3796,6 +3805,8 @@ window_copy_scroll_to(struct window_mode_entry *wme, u_int px, u_int py,
|
||||
if (!no_redraw && data->searchmark != NULL && !data->timeout)
|
||||
window_copy_search_marks(wme, NULL, data->searchregex, 1);
|
||||
window_copy_update_selection(wme, 1, 0);
|
||||
if (data->oy != old_oy)
|
||||
window_pane_scrollbar_show(wme->wp, 1);
|
||||
if (!no_redraw)
|
||||
window_copy_redraw_screen(wme);
|
||||
}
|
||||
@@ -5154,6 +5165,9 @@ window_copy_write_line(struct window_mode_entry *wme,
|
||||
else
|
||||
content_sx = sx;
|
||||
|
||||
screen_write_cursormove(ctx, 0, py, 0);
|
||||
screen_write_clearline(ctx, 8);
|
||||
|
||||
ft = format_create_defaults(NULL, NULL, NULL, NULL, wp);
|
||||
|
||||
style_apply(&gc, oo, "copy-mode-position-style", ft);
|
||||
@@ -5275,7 +5289,10 @@ window_copy_redraw_lines(struct window_mode_entry *wme, u_int py, u_int ny)
|
||||
return;
|
||||
}
|
||||
|
||||
screen_write_start_pane(&ctx, wp, NULL);
|
||||
if (window_pane_scrollbar_overlay_visible(wp))
|
||||
screen_write_start(&ctx, &data->screen);
|
||||
else
|
||||
screen_write_start_pane(&ctx, wp, NULL);
|
||||
for (i = py; i < py + ny; i++)
|
||||
window_copy_write_line(wme, &ctx, i);
|
||||
screen_write_cursormove(&ctx,
|
||||
@@ -5283,7 +5300,7 @@ window_copy_redraw_lines(struct window_mode_entry *wme, u_int py, u_int ny)
|
||||
0);
|
||||
screen_write_stop(&ctx);
|
||||
|
||||
wp->flags |= PANE_REDRAWSCROLLBAR;
|
||||
window_pane_scrollbar_redraw(wp);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -6539,6 +6556,7 @@ window_copy_scroll_up(struct window_mode_entry *wme, u_int ny)
|
||||
if (ny == 0)
|
||||
return;
|
||||
data->oy -= ny;
|
||||
window_pane_scrollbar_show(wp, 1);
|
||||
|
||||
if (data->searchmark != NULL && !data->timeout)
|
||||
window_copy_search_marks(wme, NULL, data->searchregex, 1);
|
||||
@@ -6570,7 +6588,10 @@ window_copy_scroll_up(struct window_mode_entry *wme, u_int ny)
|
||||
return;
|
||||
}
|
||||
|
||||
screen_write_start_pane(&ctx, wp, NULL);
|
||||
if (window_pane_scrollbar_overlay_visible(wp))
|
||||
screen_write_start(&ctx, &data->screen);
|
||||
else
|
||||
screen_write_start_pane(&ctx, wp, NULL);
|
||||
screen_write_cursormove(&ctx, 0, 0, 0);
|
||||
screen_write_deleteline(&ctx, ny, 8);
|
||||
window_copy_write_lines(wme, &ctx, screen_size_y(s) - ny, ny);
|
||||
@@ -6585,7 +6606,7 @@ window_copy_scroll_up(struct window_mode_entry *wme, u_int ny)
|
||||
window_copy_cursor_offset(wme, data->cx, screen_size_x(s)), data->cy,
|
||||
0);
|
||||
screen_write_stop(&ctx);
|
||||
wp->flags |= PANE_REDRAWSCROLLBAR;
|
||||
window_pane_scrollbar_redraw(wp);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -6604,6 +6625,7 @@ window_copy_scroll_down(struct window_mode_entry *wme, u_int ny)
|
||||
if (ny == 0)
|
||||
return;
|
||||
data->oy += ny;
|
||||
window_pane_scrollbar_show(wp, 1);
|
||||
|
||||
if (data->searchmark != NULL && !data->timeout)
|
||||
window_copy_search_marks(wme, NULL, data->searchregex, 1);
|
||||
@@ -6630,7 +6652,10 @@ window_copy_scroll_down(struct window_mode_entry *wme, u_int ny)
|
||||
return;
|
||||
}
|
||||
|
||||
screen_write_start_pane(&ctx, wp, NULL);
|
||||
if (window_pane_scrollbar_overlay_visible(wp))
|
||||
screen_write_start(&ctx, &data->screen);
|
||||
else
|
||||
screen_write_start_pane(&ctx, wp, NULL);
|
||||
screen_write_cursormove(&ctx, 0, 0, 0);
|
||||
screen_write_insertline(&ctx, ny, 8);
|
||||
window_copy_write_lines(wme, &ctx, 0, ny);
|
||||
@@ -6641,7 +6666,7 @@ window_copy_scroll_down(struct window_mode_entry *wme, u_int ny)
|
||||
screen_write_cursormove(&ctx, window_copy_cursor_offset(wme, data->cx,
|
||||
screen_size_x(s)), data->cy, 0);
|
||||
screen_write_stop(&ctx);
|
||||
wp->flags |= PANE_REDRAWSCROLLBAR;
|
||||
window_pane_scrollbar_redraw(wp);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
@@ -36,8 +36,8 @@ static void window_customize_key(struct window_mode_entry *,
|
||||
#define WINDOW_CUSTOMIZE_DEFAULT_FORMAT \
|
||||
"#{?is_option," \
|
||||
"#{?option_is_global,,#[reverse](#{option_scope})#[default] }" \
|
||||
"#[ignore]" \
|
||||
"#{option_value}#{?option_unit, #{option_unit},}" \
|
||||
"#[fg=themelightgrey]#[ignore]#{option_value}" \
|
||||
"#{?option_unit, #{option_unit},}" \
|
||||
"," \
|
||||
"#{key}" \
|
||||
"}"
|
||||
@@ -472,6 +472,7 @@ window_customize_build_keys(struct window_customize_modedata *data,
|
||||
expanded = format_expand(ft, filter);
|
||||
if (!format_true(expanded)) {
|
||||
free(expanded);
|
||||
bd = key_bindings_next(kt, bd);
|
||||
continue;
|
||||
}
|
||||
free(expanded);
|
||||
@@ -740,8 +741,10 @@ window_customize_draw_option(struct window_customize_modedata *data,
|
||||
if (strcmp(expanded, value) != 0) {
|
||||
if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy),
|
||||
0, &grid_default_cell, "This expands to: %s",
|
||||
expanded))
|
||||
expanded)) {
|
||||
free(expanded);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
free(expanded);
|
||||
}
|
||||
@@ -766,6 +769,15 @@ window_customize_draw_option(struct window_customize_modedata *data,
|
||||
"EXAMPLE"))
|
||||
goto out;
|
||||
}
|
||||
if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_COLOUR)) {
|
||||
if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 1,
|
||||
&grid_default_cell, "This is a colour option: "))
|
||||
goto out;
|
||||
style_apply(&gc, item->oo, name, ft);
|
||||
if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 0, &gc,
|
||||
"EXAMPLE"))
|
||||
goto out;
|
||||
}
|
||||
if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_STYLE)) {
|
||||
if (!screen_write_text(ctx, cx, sx, sy - (s->cy - cy), 1,
|
||||
&grid_default_cell, "This is a style option: "))
|
||||
@@ -869,15 +881,24 @@ window_customize_height(__unused void *modedata, __unused u_int height)
|
||||
}
|
||||
|
||||
static const char* window_customize_help_lines[] = {
|
||||
"#[bold] Enter, s #[default]#[acs]x#[default] Set %1 value",
|
||||
"#[bold] S #[default]#[acs]x#[default] Set global %1 value",
|
||||
"#[bold] w #[default]#[acs]x#[default] Set window %1 value",
|
||||
"#[bold] d #[default]#[acs]x#[default] Set to default value",
|
||||
"#[bold] D #[default]#[acs]x#[default] Set tagged %1s to default value",
|
||||
"#[bold] u #[default]#[acs]x#[default] Unset an %1",
|
||||
"#[bold] U #[default]#[acs]x#[default] Unset tagged %1s",
|
||||
"#[bold] f #[default]#[acs]x#[default] Enter a filter",
|
||||
"#[bold] v #[default]#[acs]x#[default] Toggle information",
|
||||
"#[fg=themelightgrey]"
|
||||
" Enter, s #[#{E:tree-mode-border-style},acs]x#[default] Set %1 value",
|
||||
"#[fg=themelightgrey]"
|
||||
" S #[#{E:tree-mode-border-style},acs]x#[default] Set global %1 value",
|
||||
"#[fg=themelightgrey]"
|
||||
" w #[#{E:tree-mode-border-style},acs]x#[default] Set window %1 value",
|
||||
"#[fg=themelightgrey]"
|
||||
" d #[#{E:tree-mode-border-style},acs]x#[default] Set to default value",
|
||||
"#[fg=themelightgrey]"
|
||||
" D #[#{E:tree-mode-border-style},acs]x#[default] Set tagged %1s to default value",
|
||||
"#[fg=themelightgrey]"
|
||||
" u #[#{E:tree-mode-border-style},acs]x#[default] Unset an %1",
|
||||
"#[fg=themelightgrey]"
|
||||
" U #[#{E:tree-mode-border-style},acs]x#[default] Unset tagged %1s",
|
||||
"#[fg=themelightgrey]"
|
||||
" f #[#{E:tree-mode-border-style},acs]x#[default] Enter a filter",
|
||||
"#[fg=themelightgrey]"
|
||||
" v #[#{E:tree-mode-border-style},acs]x#[default] Toggle information",
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -976,9 +997,9 @@ window_customize_free_item_callback(void *itemdata)
|
||||
window_customize_destroy(data);
|
||||
}
|
||||
|
||||
static int
|
||||
static enum prompt_result
|
||||
window_customize_set_option_callback(struct client *c, void *itemdata,
|
||||
const char *s, __unused int done)
|
||||
const char *s, __unused enum prompt_key_result key)
|
||||
{
|
||||
struct window_customize_itemdata *item = itemdata;
|
||||
struct window_customize_modedata *data = item->data;
|
||||
@@ -990,12 +1011,12 @@ window_customize_set_option_callback(struct client *c, void *itemdata,
|
||||
int idx = item->idx;
|
||||
|
||||
if (s == NULL || *s == '\0' || data->dead)
|
||||
return (0);
|
||||
return (PROMPT_CLOSE);
|
||||
if (item == NULL || !window_customize_check_item(data, item, NULL))
|
||||
return (0);
|
||||
return (PROMPT_CLOSE);
|
||||
o = options_get(oo, name);
|
||||
if (o == NULL)
|
||||
return (0);
|
||||
return (PROMPT_CLOSE);
|
||||
oe = options_table_entry(o);
|
||||
|
||||
if (oe != NULL && (oe->flags & OPTIONS_TABLE_IS_ARRAY)) {
|
||||
@@ -1017,13 +1038,13 @@ window_customize_set_option_callback(struct client *c, void *itemdata,
|
||||
mode_tree_draw(data->data);
|
||||
data->wp->flags |= PANE_REDRAW;
|
||||
|
||||
return (0);
|
||||
return (PROMPT_CLOSE);
|
||||
|
||||
fail:
|
||||
*cause = toupper((u_char)*cause);
|
||||
status_message_set(c, -1, 1, 0, 0, "%s", cause);
|
||||
free(cause);
|
||||
return (0);
|
||||
return (PROMPT_CLOSE);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1142,10 +1163,10 @@ window_customize_set_option(struct client *c,
|
||||
new_item->idx = idx;
|
||||
|
||||
data->references++;
|
||||
status_prompt_set(c, NULL, prompt, value,
|
||||
mode_tree_set_prompt(data->data, c, prompt, value,
|
||||
PROMPT_TYPE_COMMAND, PROMPT_NOFORMAT,
|
||||
window_customize_set_option_callback,
|
||||
window_customize_free_item_callback, new_item,
|
||||
PROMPT_NOFORMAT, PROMPT_TYPE_COMMAND);
|
||||
window_customize_free_item_callback, new_item);
|
||||
|
||||
free(prompt);
|
||||
free(value);
|
||||
@@ -1190,9 +1211,9 @@ window_customize_reset_option(struct window_customize_modedata *data,
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
static enum prompt_result
|
||||
window_customize_set_command_callback(struct client *c, void *itemdata,
|
||||
const char *s, __unused int done)
|
||||
const char *s, __unused enum prompt_key_result key)
|
||||
{
|
||||
struct window_customize_itemdata *item = itemdata;
|
||||
struct window_customize_modedata *data = item->data;
|
||||
@@ -1201,9 +1222,9 @@ window_customize_set_command_callback(struct client *c, void *itemdata,
|
||||
char *error;
|
||||
|
||||
if (s == NULL || *s == '\0' || data->dead)
|
||||
return (0);
|
||||
return (PROMPT_CLOSE);
|
||||
if (item == NULL || !window_customize_get_key(item, NULL, &bd))
|
||||
return (0);
|
||||
return (PROMPT_CLOSE);
|
||||
|
||||
pr = cmd_parse_from_string(s, NULL);
|
||||
switch (pr->status) {
|
||||
@@ -1220,27 +1241,27 @@ window_customize_set_command_callback(struct client *c, void *itemdata,
|
||||
mode_tree_draw(data->data);
|
||||
data->wp->flags |= PANE_REDRAW;
|
||||
|
||||
return (0);
|
||||
return (PROMPT_CLOSE);
|
||||
|
||||
fail:
|
||||
*error = toupper((u_char)*error);
|
||||
status_message_set(c, -1, 1, 0, 0, "%s", error);
|
||||
free(error);
|
||||
return (0);
|
||||
return (PROMPT_CLOSE);
|
||||
}
|
||||
|
||||
static int
|
||||
static enum prompt_result
|
||||
window_customize_set_note_callback(__unused struct client *c, void *itemdata,
|
||||
const char *s, __unused int done)
|
||||
const char *s, __unused enum prompt_key_result key)
|
||||
{
|
||||
struct window_customize_itemdata *item = itemdata;
|
||||
struct window_customize_modedata *data = item->data;
|
||||
struct key_binding *bd;
|
||||
|
||||
if (s == NULL || *s == '\0' || data->dead)
|
||||
return (0);
|
||||
return (PROMPT_CLOSE);
|
||||
if (item == NULL || !window_customize_get_key(item, NULL, &bd))
|
||||
return (0);
|
||||
return (PROMPT_CLOSE);
|
||||
|
||||
free((void *)bd->note);
|
||||
bd->note = xstrdup(s);
|
||||
@@ -1249,7 +1270,7 @@ window_customize_set_note_callback(__unused struct client *c, void *itemdata,
|
||||
mode_tree_draw(data->data);
|
||||
data->wp->flags |= PANE_REDRAW;
|
||||
|
||||
return (0);
|
||||
return (PROMPT_CLOSE);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1280,10 +1301,10 @@ window_customize_set_key(struct client *c,
|
||||
new_item->key = key;
|
||||
|
||||
data->references++;
|
||||
status_prompt_set(c, NULL, prompt, value,
|
||||
mode_tree_set_prompt(data->data, c, prompt, value,
|
||||
PROMPT_TYPE_COMMAND, PROMPT_NOFORMAT,
|
||||
window_customize_set_command_callback,
|
||||
window_customize_free_item_callback, new_item,
|
||||
PROMPT_NOFORMAT, PROMPT_TYPE_COMMAND);
|
||||
window_customize_free_item_callback, new_item);
|
||||
free(prompt);
|
||||
free(value);
|
||||
} else if (strcmp(s, "Note") == 0) {
|
||||
@@ -1296,11 +1317,11 @@ window_customize_set_key(struct client *c,
|
||||
new_item->key = key;
|
||||
|
||||
data->references++;
|
||||
status_prompt_set(c, NULL, prompt,
|
||||
mode_tree_set_prompt(data->data, c, prompt,
|
||||
(bd->note == NULL ? "" : bd->note),
|
||||
PROMPT_TYPE_COMMAND, PROMPT_NOFORMAT,
|
||||
window_customize_set_note_callback,
|
||||
window_customize_free_item_callback, new_item,
|
||||
PROMPT_NOFORMAT, PROMPT_TYPE_COMMAND);
|
||||
window_customize_free_item_callback, new_item);
|
||||
free(prompt);
|
||||
}
|
||||
}
|
||||
@@ -1367,17 +1388,17 @@ window_customize_change_each(void *modedata, void *itemdata,
|
||||
options_push_changes(item->name);
|
||||
}
|
||||
|
||||
static int
|
||||
static enum prompt_result
|
||||
window_customize_change_current_callback(__unused struct client *c,
|
||||
void *modedata, const char *s, __unused int done)
|
||||
void *modedata, const char *s, __unused enum prompt_key_result key)
|
||||
{
|
||||
struct window_customize_modedata *data = modedata;
|
||||
struct window_customize_itemdata *item;
|
||||
|
||||
if (s == NULL || *s == '\0' || data->dead)
|
||||
return (0);
|
||||
return (PROMPT_CLOSE);
|
||||
if (tolower((u_char) s[0]) != 'y' || s[1] != '\0')
|
||||
return (0);
|
||||
return (PROMPT_CLOSE);
|
||||
|
||||
item = mode_tree_get_current(data->data);
|
||||
switch (data->change) {
|
||||
@@ -1400,19 +1421,19 @@ window_customize_change_current_callback(__unused struct client *c,
|
||||
mode_tree_draw(data->data);
|
||||
data->wp->flags |= PANE_REDRAW;
|
||||
|
||||
return (0);
|
||||
return (PROMPT_CLOSE);
|
||||
}
|
||||
|
||||
static int
|
||||
static enum prompt_result
|
||||
window_customize_change_tagged_callback(struct client *c, void *modedata,
|
||||
const char *s, __unused int done)
|
||||
const char *s, __unused enum prompt_key_result key)
|
||||
{
|
||||
struct window_customize_modedata *data = modedata;
|
||||
|
||||
if (s == NULL || *s == '\0' || data->dead)
|
||||
return (0);
|
||||
return (PROMPT_CLOSE);
|
||||
if (tolower((u_char) s[0]) != 'y' || s[1] != '\0')
|
||||
return (0);
|
||||
return (PROMPT_CLOSE);
|
||||
|
||||
mode_tree_each_tagged(data->data, window_customize_change_each, c,
|
||||
KEYC_NONE, 0);
|
||||
@@ -1420,7 +1441,7 @@ window_customize_change_tagged_callback(struct client *c, void *modedata,
|
||||
mode_tree_draw(data->data);
|
||||
data->wp->flags |= PANE_REDRAW;
|
||||
|
||||
return (0);
|
||||
return (PROMPT_CLOSE);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1474,11 +1495,11 @@ window_customize_key(struct window_mode_entry *wme, struct client *c,
|
||||
xasprintf(&prompt, "Reset %s to default? ", item->name);
|
||||
data->references++;
|
||||
data->change = WINDOW_CUSTOMIZE_RESET;
|
||||
status_prompt_set(c, NULL, prompt, "",
|
||||
window_customize_change_current_callback,
|
||||
window_customize_free_callback, data,
|
||||
mode_tree_set_prompt(data->data, c, prompt, "",
|
||||
PROMPT_TYPE_COMMAND,
|
||||
PROMPT_SINGLE|PROMPT_NOFORMAT|data->prompt_flags,
|
||||
PROMPT_TYPE_COMMAND);
|
||||
window_customize_change_current_callback,
|
||||
window_customize_free_callback, data);
|
||||
free(prompt);
|
||||
break;
|
||||
case 'D':
|
||||
@@ -1488,11 +1509,11 @@ window_customize_key(struct window_mode_entry *wme, struct client *c,
|
||||
xasprintf(&prompt, "Reset %u tagged to default? ", tagged);
|
||||
data->references++;
|
||||
data->change = WINDOW_CUSTOMIZE_RESET;
|
||||
status_prompt_set(c, NULL, prompt, "",
|
||||
window_customize_change_tagged_callback,
|
||||
window_customize_free_callback, data,
|
||||
mode_tree_set_prompt(data->data, c, prompt, "",
|
||||
PROMPT_TYPE_COMMAND,
|
||||
PROMPT_SINGLE|PROMPT_NOFORMAT|data->prompt_flags,
|
||||
PROMPT_TYPE_COMMAND);
|
||||
window_customize_change_tagged_callback,
|
||||
window_customize_free_callback, data);
|
||||
free(prompt);
|
||||
break;
|
||||
case 'u':
|
||||
@@ -1505,11 +1526,11 @@ window_customize_key(struct window_mode_entry *wme, struct client *c,
|
||||
xasprintf(&prompt, "Unset %s? ", item->name);
|
||||
data->references++;
|
||||
data->change = WINDOW_CUSTOMIZE_UNSET;
|
||||
status_prompt_set(c, NULL, prompt, "",
|
||||
window_customize_change_current_callback,
|
||||
window_customize_free_callback, data,
|
||||
mode_tree_set_prompt(data->data, c, prompt, "",
|
||||
PROMPT_TYPE_COMMAND,
|
||||
PROMPT_SINGLE|PROMPT_NOFORMAT|data->prompt_flags,
|
||||
PROMPT_TYPE_COMMAND);
|
||||
window_customize_change_current_callback,
|
||||
window_customize_free_callback, data);
|
||||
free(prompt);
|
||||
break;
|
||||
case 'U':
|
||||
@@ -1519,11 +1540,11 @@ window_customize_key(struct window_mode_entry *wme, struct client *c,
|
||||
xasprintf(&prompt, "Unset %u tagged? ", tagged);
|
||||
data->references++;
|
||||
data->change = WINDOW_CUSTOMIZE_UNSET;
|
||||
status_prompt_set(c, NULL, prompt, "",
|
||||
window_customize_change_tagged_callback,
|
||||
window_customize_free_callback, data,
|
||||
mode_tree_set_prompt(data->data, c, prompt, "",
|
||||
PROMPT_TYPE_COMMAND,
|
||||
PROMPT_SINGLE|PROMPT_NOFORMAT|data->prompt_flags,
|
||||
PROMPT_TYPE_COMMAND);
|
||||
window_customize_change_tagged_callback,
|
||||
window_customize_free_callback, data);
|
||||
free(prompt);
|
||||
break;
|
||||
case 'H':
|
||||
|
||||
636
window-switch.c
Normal file
636
window-switch.c
Normal file
@@ -0,0 +1,636 @@
|
||||
/* $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 <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "tmux.h"
|
||||
|
||||
static struct screen *window_switch_init(struct window_mode_entry *,
|
||||
struct cmd_find_state *, struct args *);
|
||||
static void window_switch_free(struct window_mode_entry *);
|
||||
static void window_switch_resize(struct window_mode_entry *, u_int,
|
||||
u_int);
|
||||
static void window_switch_key(struct window_mode_entry *,
|
||||
struct client *, struct session *,
|
||||
struct winlink *, key_code, struct mouse_event *);
|
||||
static enum prompt_result window_switch_prompt_callback(void *, const char *,
|
||||
enum prompt_key_result);
|
||||
|
||||
#define WINDOW_SWITCH_DEFAULT_COMMAND "switch-client -Zt '%%'"
|
||||
|
||||
#define WINDOW_SWITCH_DEFAULT_FORMAT \
|
||||
"#{?window_format," \
|
||||
"#{window_name} " \
|
||||
"#[dim]#{session_name}:#{window_index}#{window_flags}#[default] " \
|
||||
"#[dim]#{pane_current_command}#[default] " \
|
||||
"#[dim]#{?#{!=:#{pane_title},#{host_short}},#{pane_title},}#[default]" \
|
||||
"," \
|
||||
"#{session_name} " \
|
||||
"#[dim]#{session_windows} windows#[default] " \
|
||||
"#{?session_attached,attached,#[dim]detached#[default]} " \
|
||||
"#[dim]#{window_name}#[default]" \
|
||||
"}"
|
||||
|
||||
const struct window_mode window_switch_mode = {
|
||||
.name = "switch-mode",
|
||||
.default_format = WINDOW_SWITCH_DEFAULT_FORMAT,
|
||||
|
||||
.init = window_switch_init,
|
||||
.free = window_switch_free,
|
||||
.resize = window_switch_resize,
|
||||
.key = window_switch_key,
|
||||
};
|
||||
|
||||
enum window_switch_type {
|
||||
WINDOW_SWITCH_TYPE_SESSION,
|
||||
WINDOW_SWITCH_TYPE_WINDOW
|
||||
};
|
||||
|
||||
struct window_switch_itemdata {
|
||||
enum window_switch_type type;
|
||||
int session;
|
||||
int winlink;
|
||||
|
||||
uint64_t tag;
|
||||
char *text;
|
||||
bitstr_t *match;
|
||||
|
||||
u_int score;
|
||||
u_int order;
|
||||
};
|
||||
|
||||
struct window_switch_modedata {
|
||||
struct window_pane *wp;
|
||||
struct screen screen;
|
||||
int zoomed;
|
||||
|
||||
char *format;
|
||||
char *command;
|
||||
|
||||
enum window_switch_type type;
|
||||
char *filter;
|
||||
struct prompt *prompt;
|
||||
u_int prompt_cx;
|
||||
|
||||
struct window_switch_itemdata **item_list;
|
||||
u_int item_size;
|
||||
|
||||
struct window_switch_itemdata **matches;
|
||||
u_int matches_size;
|
||||
|
||||
u_int current;
|
||||
u_int offset;
|
||||
};
|
||||
|
||||
static void
|
||||
window_switch_free_item(struct window_switch_itemdata *item)
|
||||
{
|
||||
free(item->match);
|
||||
free(item->text);
|
||||
free(item);
|
||||
}
|
||||
|
||||
static struct window_switch_itemdata *
|
||||
window_switch_add_item(struct window_switch_modedata *data)
|
||||
{
|
||||
struct window_switch_itemdata *item;
|
||||
|
||||
data->item_list = xreallocarray(data->item_list, data->item_size + 1,
|
||||
sizeof *data->item_list);
|
||||
item = data->item_list[data->item_size++] = xcalloc(1, sizeof *item);
|
||||
return (item);
|
||||
}
|
||||
|
||||
static void
|
||||
window_switch_add_session(struct window_switch_modedata *data,
|
||||
struct session *s, u_int *order)
|
||||
{
|
||||
struct window_switch_itemdata *item;
|
||||
struct format_tree *ft;
|
||||
|
||||
ft = format_create(NULL, NULL, FORMAT_NONE, 0);
|
||||
format_defaults(ft, NULL, s, NULL, NULL);
|
||||
|
||||
item = window_switch_add_item(data);
|
||||
item->type = WINDOW_SWITCH_TYPE_SESSION;
|
||||
item->session = s->id;
|
||||
item->winlink = -1;
|
||||
item->tag = (uint64_t)s;
|
||||
item->order = (*order)++;
|
||||
item->text = format_expand(ft, data->format);
|
||||
|
||||
format_free(ft);
|
||||
}
|
||||
|
||||
static void
|
||||
window_switch_add_window(struct window_switch_modedata *data,
|
||||
struct winlink *wl, u_int *order)
|
||||
{
|
||||
struct window_switch_itemdata *item;
|
||||
struct format_tree *ft;
|
||||
|
||||
ft = format_create(NULL, NULL, FORMAT_NONE, 0);
|
||||
format_defaults(ft, NULL, wl->session, wl, NULL);
|
||||
|
||||
item = window_switch_add_item(data);
|
||||
item->type = WINDOW_SWITCH_TYPE_WINDOW;
|
||||
item->session = wl->session->id;
|
||||
item->winlink = wl->idx;
|
||||
item->tag = (uint64_t)wl;
|
||||
item->order = (*order)++;
|
||||
item->text = format_expand(ft, data->format);
|
||||
|
||||
format_free(ft);
|
||||
}
|
||||
|
||||
static int
|
||||
window_switch_compare(const void *a0, const void *b0)
|
||||
{
|
||||
struct window_switch_itemdata *const *a = a0;
|
||||
struct window_switch_itemdata *const *b = b0;
|
||||
|
||||
if ((*a)->score > (*b)->score)
|
||||
return (-1);
|
||||
if ((*a)->score < (*b)->score)
|
||||
return (1);
|
||||
if ((*a)->order < (*b)->order)
|
||||
return (-1);
|
||||
if ((*a)->order > (*b)->order)
|
||||
return (1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
window_switch_build(struct window_switch_modedata *data)
|
||||
{
|
||||
struct window_switch_itemdata *item, **m = NULL;
|
||||
const char *f = data->filter;
|
||||
u_int ns, nw, i, n = 0, order = 0;
|
||||
u_int sx = screen_size_x(&data->screen);
|
||||
struct session **sl;
|
||||
struct winlink **wl;
|
||||
struct sort_criteria sort_crit;
|
||||
|
||||
sort_crit.order = SORT_NAME;
|
||||
sort_crit.reversed = 0;
|
||||
|
||||
for (i = 0; i < data->item_size; i++)
|
||||
window_switch_free_item(data->item_list[i]);
|
||||
free(data->item_list);
|
||||
data->item_list = NULL;
|
||||
data->item_size = 0;
|
||||
|
||||
switch (data->type) {
|
||||
case WINDOW_SWITCH_TYPE_SESSION:
|
||||
sl = sort_get_sessions(&ns, &sort_crit);
|
||||
for (i = 0; i < ns; i++)
|
||||
window_switch_add_session(data, sl[i], &order);
|
||||
break;
|
||||
case WINDOW_SWITCH_TYPE_WINDOW:
|
||||
wl = sort_get_winlinks(&nw, &sort_crit);
|
||||
for (i = 0; i < nw; i++)
|
||||
window_switch_add_window(data, wl[i], &order);
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < data->item_size; i++) {
|
||||
item = data->item_list[i];
|
||||
if (*f == '\0') {
|
||||
m = xreallocarray(m, n + 1, sizeof *m);
|
||||
m[n++] = item;
|
||||
continue;
|
||||
}
|
||||
|
||||
item->match = fuzzy_match(f, item->text, sx, &item->score);
|
||||
if (item->match == NULL)
|
||||
continue;
|
||||
m = xreallocarray(m, n + 1, sizeof *m);
|
||||
m[n++] = item;
|
||||
}
|
||||
qsort(m, n, sizeof *m, window_switch_compare);
|
||||
|
||||
free(data->matches);
|
||||
data->matches = m;
|
||||
data->matches_size = n;
|
||||
}
|
||||
|
||||
static u_int
|
||||
window_switch_visible(struct window_switch_modedata *data)
|
||||
{
|
||||
u_int sy = screen_size_y(&data->screen);
|
||||
|
||||
if (sy <= 1)
|
||||
return (0);
|
||||
return (sy - 1);
|
||||
}
|
||||
|
||||
static void
|
||||
window_switch_set_current(struct window_switch_modedata *data, u_int current)
|
||||
{
|
||||
u_int visible = window_switch_visible(data);
|
||||
|
||||
if (data->matches_size == 0) {
|
||||
data->current = 0;
|
||||
data->offset = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (current > data->matches_size - 1)
|
||||
current = data->matches_size - 1;
|
||||
data->current = current;
|
||||
|
||||
if (data->current < data->offset)
|
||||
data->offset = data->current;
|
||||
else if (visible != 0 && data->current >= data->offset + visible)
|
||||
data->offset = data->current - visible + 1;
|
||||
}
|
||||
|
||||
static void
|
||||
window_switch_draw_screen(struct window_mode_entry *wme)
|
||||
{
|
||||
struct window_pane *wp = wme->wp;
|
||||
struct window_switch_modedata *data = wme->data;
|
||||
struct options *oo = wp->options;
|
||||
struct screen_write_ctx ctx;
|
||||
struct screen *s = &data->screen;
|
||||
u_int sx = screen_size_x(s), i, j;
|
||||
u_int sy = screen_size_y(s), visible, idx;
|
||||
struct window_switch_itemdata *item;
|
||||
struct grid_cell mgc, sgc, gc;
|
||||
const struct grid_cell *dgc = &grid_default_cell;
|
||||
struct prompt_draw_data pdd;
|
||||
screen_write_start(&ctx, s);
|
||||
screen_write_clearscreen(&ctx, 8);
|
||||
|
||||
if (sy <= 1) {
|
||||
screen_write_stop(&ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
style_apply(&mgc, oo, "switch-mode-match-style", NULL);
|
||||
style_apply(&sgc, oo, "mode-style", NULL);
|
||||
|
||||
visible = window_switch_visible(data);
|
||||
for (i = 0; i < visible; i++) {
|
||||
idx = data->offset + i;
|
||||
if (idx >= data->matches_size)
|
||||
break;
|
||||
item = data->matches[idx];
|
||||
|
||||
screen_write_cursormove(&ctx, 0, i, 0);
|
||||
if (idx != data->current)
|
||||
format_draw(&ctx, dgc, sx, item->text, NULL, 0);
|
||||
else {
|
||||
screen_write_clearendofline(&ctx, sgc.bg);
|
||||
format_draw(&ctx, &sgc, sx, item->text, NULL, 0);
|
||||
}
|
||||
|
||||
if (item->match == NULL)
|
||||
continue;
|
||||
for (j = 0; j < sx; j++) {
|
||||
if (!bit_test(item->match, j))
|
||||
continue;
|
||||
grid_get_cell(s->grid, j, i, &gc);
|
||||
gc.attr = mgc.attr;
|
||||
gc.fg = mgc.fg;
|
||||
gc.bg = mgc.bg;
|
||||
screen_write_cursormove(&ctx, j, i, 0);
|
||||
screen_write_cell(&ctx, &gc);
|
||||
}
|
||||
}
|
||||
|
||||
if (data->prompt != NULL) {
|
||||
pdd.ctx = &ctx;
|
||||
pdd.cursor_x = &data->prompt_cx;
|
||||
pdd.area_x = 0;
|
||||
pdd.area_width = sx;
|
||||
pdd.prompt_line = sy - 1;
|
||||
s->mode |= MODE_CURSOR;
|
||||
prompt_draw(data->prompt, &pdd);
|
||||
screen_write_cursormove(&ctx, data->prompt_cx, sy - 1, 0);
|
||||
}
|
||||
screen_write_stop(&ctx);
|
||||
}
|
||||
|
||||
static struct screen *
|
||||
window_switch_init(struct window_mode_entry *wme,
|
||||
struct cmd_find_state *fs, struct args *args)
|
||||
{
|
||||
struct window_pane *wp = wme->wp;
|
||||
struct window_switch_modedata *data;
|
||||
struct screen *s;
|
||||
struct prompt_create_data pd;
|
||||
|
||||
wme->data = data = xcalloc(1, sizeof *data);
|
||||
data->wp = wp;
|
||||
|
||||
if (args_has(args, 'w'))
|
||||
data->type = WINDOW_SWITCH_TYPE_WINDOW;
|
||||
else
|
||||
data->type = WINDOW_SWITCH_TYPE_SESSION;
|
||||
|
||||
data->filter = xstrdup("");
|
||||
if (args == NULL || !args_has(args, 'F'))
|
||||
data->format = xstrdup(WINDOW_SWITCH_DEFAULT_FORMAT);
|
||||
else
|
||||
data->format = xstrdup(args_get(args, 'F'));
|
||||
if (args == NULL || args_count(args) == 0)
|
||||
data->command = xstrdup(WINDOW_SWITCH_DEFAULT_COMMAND);
|
||||
else
|
||||
data->command = xstrdup(args_string(args, 0));
|
||||
|
||||
memset(&pd, 0, sizeof pd);
|
||||
prompt_set_options(&pd, fs->s);
|
||||
pd.fs = fs;
|
||||
pd.prompt = "(search) ";
|
||||
pd.input = "";
|
||||
pd.type = PROMPT_TYPE_SEARCH;
|
||||
pd.flags = PROMPT_INCREMENTAL|PROMPT_NOFORMAT|PROMPT_ISMODE|
|
||||
PROMPT_EDITARROWS;
|
||||
pd.inputcb = window_switch_prompt_callback;
|
||||
pd.data = data;
|
||||
data->prompt = prompt_create(&pd);
|
||||
prompt_update(data->prompt, "(search) ", data->filter);
|
||||
|
||||
if (!args_has(args, 'Z'))
|
||||
data->zoomed = -1;
|
||||
else {
|
||||
data->zoomed = (wp->window->flags & WINDOW_ZOOMED);
|
||||
if (!data->zoomed && window_zoom(wp) == 0)
|
||||
server_redraw_window(wp->window);
|
||||
}
|
||||
|
||||
s = &data->screen;
|
||||
screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0);
|
||||
|
||||
window_switch_build(data);
|
||||
prompt_incremental_start(data->prompt);
|
||||
window_switch_draw_screen(wme);
|
||||
|
||||
return (s);
|
||||
}
|
||||
|
||||
static void
|
||||
window_switch_free(struct window_mode_entry *wme)
|
||||
{
|
||||
struct window_switch_modedata *data = wme->data;
|
||||
u_int i;
|
||||
|
||||
if (data->zoomed == 0)
|
||||
server_unzoom_window(wme->wp->window);
|
||||
|
||||
for (i = 0; i < data->item_size; i++)
|
||||
window_switch_free_item(data->item_list[i]);
|
||||
free(data->item_list);
|
||||
|
||||
free(data->matches);
|
||||
free(data->filter);
|
||||
prompt_free(data->prompt);
|
||||
free(data->format);
|
||||
free(data->command);
|
||||
screen_free(&data->screen);
|
||||
|
||||
free(data);
|
||||
}
|
||||
|
||||
static void
|
||||
window_switch_resize(struct window_mode_entry *wme, u_int sx, u_int sy)
|
||||
{
|
||||
struct window_switch_modedata *data = wme->data;
|
||||
struct screen *s = &data->screen;
|
||||
|
||||
screen_resize(s, sx, sy, 0);
|
||||
window_switch_build(data);
|
||||
window_switch_set_current(data, data->current);
|
||||
window_switch_draw_screen(wme);
|
||||
}
|
||||
|
||||
static int
|
||||
window_switch_run_command(struct window_switch_modedata *data, struct client *c)
|
||||
{
|
||||
struct window_switch_itemdata *item;
|
||||
struct cmd_find_state fs;
|
||||
struct session *s;
|
||||
struct winlink *wl;
|
||||
char *target = NULL;
|
||||
struct cmdq_state *state;
|
||||
char *command, *error;
|
||||
enum cmd_parse_status status;
|
||||
|
||||
if (data->matches_size == 0)
|
||||
return (0);
|
||||
item = data->matches[data->current];
|
||||
|
||||
cmd_find_clear_state(&fs, 0);
|
||||
switch (item->type) {
|
||||
case WINDOW_SWITCH_TYPE_SESSION:
|
||||
s = session_find_by_id(item->session);
|
||||
if (s != NULL) {
|
||||
xasprintf(&target, "=%s:", s->name);
|
||||
cmd_find_from_session(&fs, s, 0);
|
||||
}
|
||||
break;
|
||||
case WINDOW_SWITCH_TYPE_WINDOW:
|
||||
s = session_find_by_id(item->session);
|
||||
if (s != NULL) {
|
||||
wl = winlink_find_by_index(&s->windows, item->winlink);
|
||||
if (s != NULL && wl != NULL) {
|
||||
xasprintf(&target, "=%s:%u.", s->name, wl->idx);
|
||||
cmd_find_from_winlink(&fs, wl, 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (target == NULL)
|
||||
return (0);
|
||||
|
||||
command = cmd_template_replace(data->command, target, 1);
|
||||
if (command != NULL && *command != '\0') {
|
||||
state = cmdq_new_state(&fs, NULL, 0);
|
||||
status = cmd_parse_and_append(command, NULL, c, state, &error);
|
||||
if (status == CMD_PARSE_ERROR) {
|
||||
if (c != NULL) {
|
||||
*error = toupper((u_char)*error);
|
||||
status_message_set(c, -1, 1, 0, 0, "%s", error);
|
||||
}
|
||||
free(error);
|
||||
}
|
||||
cmdq_free_state(state);
|
||||
}
|
||||
free(command);
|
||||
free(target);
|
||||
return (1);
|
||||
}
|
||||
|
||||
static enum prompt_result
|
||||
window_switch_prompt_callback(void *arg, const char *s,
|
||||
enum prompt_key_result key)
|
||||
{
|
||||
struct window_switch_modedata *data = arg;
|
||||
|
||||
if (key != PROMPT_KEY_HANDLED)
|
||||
return (PROMPT_CONTINUE);
|
||||
|
||||
if (s == NULL)
|
||||
s = "";
|
||||
else if (*s != '\0')
|
||||
s++;
|
||||
|
||||
free(data->filter);
|
||||
data->filter = xstrdup(s);
|
||||
window_switch_build(data);
|
||||
data->current = 0;
|
||||
data->offset = 0;
|
||||
|
||||
return (PROMPT_CONTINUE);
|
||||
}
|
||||
|
||||
static void
|
||||
window_switch_key(struct window_mode_entry *wme, struct client *c,
|
||||
__unused struct session *s, __unused struct winlink *wl, key_code key,
|
||||
struct mouse_event *m)
|
||||
{
|
||||
struct window_pane *wp = wme->wp;
|
||||
struct window_switch_modedata *data = wme->data;
|
||||
u_int visible, current = data->current;
|
||||
u_int x, y, size = data->matches_size;
|
||||
enum prompt_key_result result;
|
||||
int redraw = 0;
|
||||
|
||||
if (KEYC_IS_MOUSE(key)) {
|
||||
if (m == NULL || cmd_mouse_at(wp, m, &x, &y, 0) != 0)
|
||||
return;
|
||||
if (data->prompt != NULL && screen_size_y(&data->screen) != 0 &&
|
||||
y == screen_size_y(&data->screen) - 1 &&
|
||||
MOUSE_BUTTONS(m->b) == MOUSE_BUTTON_1 && !MOUSE_DRAG(m->b) &&
|
||||
!MOUSE_RELEASE(m->b)) {
|
||||
result = prompt_mouse(data->prompt, x, 0,
|
||||
screen_size_x(&data->screen), &redraw);
|
||||
if (redraw || result == PROMPT_KEY_HANDLED) {
|
||||
window_switch_draw_screen(wme);
|
||||
wp->flags |= PANE_REDRAW;
|
||||
}
|
||||
return;
|
||||
}
|
||||
switch (key) {
|
||||
case KEYC_WHEELUP_PANE:
|
||||
if (size != 0 && current != 0)
|
||||
window_switch_set_current(data, current - 1);
|
||||
goto moved;
|
||||
case KEYC_WHEELDOWN_PANE:
|
||||
if (size != 0 && current != size - 1)
|
||||
window_switch_set_current(data, current + 1);
|
||||
goto moved;
|
||||
case KEYC_MOUSEDOWN1_PANE:
|
||||
case KEYC_DOUBLECLICK1_PANE:
|
||||
if (y >= window_switch_visible(data) ||
|
||||
data->offset + y >= size)
|
||||
return;
|
||||
window_switch_set_current(data, data->offset + y);
|
||||
if (key == KEYC_DOUBLECLICK1_PANE) {
|
||||
if (window_switch_run_command(data, c))
|
||||
window_pane_reset_mode(wp);
|
||||
return;
|
||||
}
|
||||
goto moved;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
switch (key) {
|
||||
case 'p'|KEYC_CTRL:
|
||||
case 'k'|KEYC_CTRL:
|
||||
key = KEYC_UP;
|
||||
break;
|
||||
case 'n'|KEYC_CTRL:
|
||||
case 'j'|KEYC_CTRL:
|
||||
key = KEYC_DOWN;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (key) {
|
||||
case '\r':
|
||||
if (window_switch_run_command(data, c))
|
||||
window_pane_reset_mode(wp);
|
||||
return;
|
||||
case '\033': /* Escape */
|
||||
case '['|KEYC_CTRL:
|
||||
case 'c'|KEYC_CTRL:
|
||||
case 'g'|KEYC_CTRL:
|
||||
window_pane_reset_mode(wp);
|
||||
return;
|
||||
}
|
||||
|
||||
if (data->prompt != NULL) {
|
||||
result = prompt_key(data->prompt, key, &redraw);
|
||||
if (redraw) {
|
||||
window_switch_draw_screen(wme);
|
||||
wp->flags |= PANE_REDRAW;
|
||||
}
|
||||
if (result == PROMPT_KEY_HANDLED ||
|
||||
result == PROMPT_KEY_NOT_HANDLED)
|
||||
return;
|
||||
current = data->current;
|
||||
size = data->matches_size;
|
||||
}
|
||||
|
||||
switch (key) {
|
||||
case KEYC_UP:
|
||||
if (size == 0)
|
||||
goto moved;
|
||||
if (current == 0)
|
||||
window_switch_set_current(data, size - 1);
|
||||
else
|
||||
window_switch_set_current(data, current - 1);
|
||||
goto moved;
|
||||
case KEYC_DOWN:
|
||||
if (size == 0)
|
||||
goto moved;
|
||||
if (current == size - 1)
|
||||
window_switch_set_current(data, 0);
|
||||
else
|
||||
window_switch_set_current(data, current + 1);
|
||||
goto moved;
|
||||
case KEYC_PPAGE:
|
||||
visible = window_switch_visible(data);
|
||||
if (current >= visible)
|
||||
window_switch_set_current(data, current - visible);
|
||||
else
|
||||
window_switch_set_current(data, 0);
|
||||
goto moved;
|
||||
case KEYC_NPAGE:
|
||||
visible = window_switch_visible(data);
|
||||
window_switch_set_current(data, current + visible);
|
||||
goto moved;
|
||||
case KEYC_HOME:
|
||||
window_switch_set_current(data, 0);
|
||||
goto moved;
|
||||
case KEYC_END:
|
||||
if (size > 0)
|
||||
window_switch_set_current(data, size - 1);
|
||||
goto moved;
|
||||
}
|
||||
|
||||
moved:
|
||||
window_switch_draw_screen(wme);
|
||||
wp->flags |= PANE_REDRAW;
|
||||
}
|
||||
317
window-tree.c
317
window-tree.c
@@ -38,15 +38,15 @@ static void window_tree_key(struct window_mode_entry *,
|
||||
|
||||
#define WINDOW_TREE_DEFAULT_FORMAT \
|
||||
"#{?pane_format," \
|
||||
"#{?pane_marked,#[reverse],}#{?pane_floating_flag,#[italics],}" \
|
||||
"#{pane_current_command}#{pane_flags}" \
|
||||
"#{?pane_marked,#[fg=thememagenta],}#{?pane_floating_flag,#[underscore],}" \
|
||||
"#{pane_current_command}#[fg=themelightgrey]#{pane_flags}" \
|
||||
"#{?#{&&:#{pane_title},#{!=:#{pane_title},#{host_short}}},: \"#{pane_title}\",}" \
|
||||
",window_format," \
|
||||
"#{?window_marked_flag,#[reverse],}" \
|
||||
"#{window_name}#{window_flags}" \
|
||||
"#{?window_marked_flag,#[fg=thememagenta],}" \
|
||||
"#{window_name}#[fg=themelightgrey]#{window_flags}" \
|
||||
"#{?#{&&:#{==:#{window_panes},1},#{&&:#{pane_title},#{!=:#{pane_title},#{host_short}}}},: \"#{pane_title}\",}" \
|
||||
"," \
|
||||
"#{session_windows} windows" \
|
||||
"#[fg=themelightgrey]#{session_windows} windows" \
|
||||
"#{?session_grouped, " \
|
||||
"(group #{session_group}: " \
|
||||
"#{session_group_list})," \
|
||||
@@ -114,6 +114,7 @@ struct window_tree_modedata {
|
||||
char *command;
|
||||
int squash_groups;
|
||||
int hide_preview_this_pane;
|
||||
int preview_is_info;
|
||||
int prompt_flags;
|
||||
|
||||
struct window_tree_itemdata **item_list;
|
||||
@@ -141,6 +142,80 @@ static enum sort_order window_tree_order_seq[] = {
|
||||
SORT_END,
|
||||
};
|
||||
|
||||
#define WINDOW_TREE_FLAG(label, cond) \
|
||||
"#{?" cond ",#[fg=themegreen],#[fg=themelightgrey]}" label "#[default]"
|
||||
|
||||
static const char *window_tree_pane_info_lines[] = {
|
||||
"#[fg=themelightgrey]Pane #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
"#{pane_index} #[fg=themelightgrey](#{pane_id})#[default]",
|
||||
"#[fg=themelightgrey]Title #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
"#{pane_title}",
|
||||
"#[fg=themelightgrey]Command #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
"#{pane_current_command} #[fg=themelightgrey](PID #{pane_pid})#[default]",
|
||||
"#[fg=themelightgrey]Path #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
"#{pane_current_path}",
|
||||
"#[fg=themelightgrey]TTY #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
"#{pane_tty}",
|
||||
"#[fg=themelightgrey]Position #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
"#{pane_x},#{pane_y} #{pane_width}x#{pane_height}",
|
||||
"#[fg=themelightgrey]Mode #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
"#{?pane_in_mode,#{pane_mode},none}",
|
||||
"#[fg=themelightgrey]Flags #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
WINDOW_TREE_FLAG("active", "pane_active") " "
|
||||
WINDOW_TREE_FLAG("zoomed", "window_zoomed_flag") " "
|
||||
WINDOW_TREE_FLAG("marked", "pane_marked") " "
|
||||
WINDOW_TREE_FLAG("sync", "pane_synchronized") " "
|
||||
WINDOW_TREE_FLAG("dead", "pane_dead") " "
|
||||
WINDOW_TREE_FLAG("piped", "pane_pipe"),
|
||||
};
|
||||
|
||||
static const char *window_tree_window_info_lines[] = {
|
||||
"#[fg=themelightgrey]Window #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
"#{window_index}: #{window_name} #[fg=themelightgrey](#{window_id})#[default]",
|
||||
"#[fg=themelightgrey]Size #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
"#{window_width}x#{window_height}",
|
||||
"#[fg=themelightgrey]Panes #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
"#{window_panes}",
|
||||
"#[fg=themelightgrey]Activity Time #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
"#{t:window_activity} #[fg=themelightgrey](#{t/r:window_activity})#[default]",
|
||||
"#[fg=themelightgrey]Sessions #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
"#{s/,/ /:window_linked_sessions_list}",
|
||||
"#[fg=themelightgrey]Flags #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
WINDOW_TREE_FLAG("active", "window_active") " "
|
||||
WINDOW_TREE_FLAG("last", "window_last_flag") " "
|
||||
WINDOW_TREE_FLAG("bell", "window_bell_flag") " "
|
||||
WINDOW_TREE_FLAG("activity", "window_activity_flag") " "
|
||||
WINDOW_TREE_FLAG("silence", "window_silence_flag") " "
|
||||
WINDOW_TREE_FLAG("zoomed", "window_zoomed_flag") " "
|
||||
WINDOW_TREE_FLAG("marked", "window_marked_flag"),
|
||||
};
|
||||
|
||||
static const char *window_tree_session_info_lines[] = {
|
||||
"#[fg=themelightgrey]Session #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
"#{session_name} #[fg=themelightgrey](#{session_id})#[default]",
|
||||
"#[fg=themelightgrey]Created Time #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
"#{t:session_created} #[fg=themelightgrey](#{t/r:session_created})#[default]",
|
||||
"#[fg=themelightgrey]Activity Time #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
"#{t:session_activity} #[fg=themelightgrey](#{t/r:session_activity})#[default]",
|
||||
"#[fg=themelightgrey]Attached Time #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
"#{?#{t:session_last_attached},#{t:session_last_attached} #[fg=themelightgrey](#{t/r:session_last_attached})#[default],never}",
|
||||
"#[fg=themelightgrey]Clients #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
"#{s/,/ /:session_attached_list}",
|
||||
"#[fg=themelightgrey]Windows #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
"#{session_windows}",
|
||||
"#[fg=themelightgrey]Path #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
"#{session_path}",
|
||||
"#[fg=themelightgrey]Group #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
"#{?session_grouped,#{session_group} (#{session_group_size}),none}",
|
||||
"#[fg=themelightgrey]Flags #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
WINDOW_TREE_FLAG("attached", "session_attached") " "
|
||||
WINDOW_TREE_FLAG("grouped", "session_grouped") " "
|
||||
WINDOW_TREE_FLAG("marked", "session_marked") " "
|
||||
WINDOW_TREE_FLAG("bell", "session_bell_flag") " "
|
||||
WINDOW_TREE_FLAG("activity", "session_activity_flag") " "
|
||||
WINDOW_TREE_FLAG("silence", "session_silence_flag"),
|
||||
};
|
||||
|
||||
static void
|
||||
window_tree_pull_item(struct window_tree_itemdata *item, struct session **sp,
|
||||
struct winlink **wlp, struct window_pane **wp)
|
||||
@@ -401,7 +476,8 @@ window_tree_build(void *modedata, struct sort_criteria *sort_crit,
|
||||
|
||||
static void
|
||||
window_tree_draw_label(struct screen_write_ctx *ctx, u_int px, u_int py,
|
||||
u_int sx, u_int sy, const struct grid_cell *gc, const char *label)
|
||||
u_int sx, u_int sy, const struct grid_cell *border_gc,
|
||||
const struct grid_cell *label_gc, const char *label)
|
||||
{
|
||||
u_int width, ox, oy;
|
||||
char *new_label = NULL;
|
||||
@@ -420,14 +496,22 @@ window_tree_draw_label(struct screen_write_ctx *ctx, u_int px, u_int py,
|
||||
|
||||
screen_write_cursormove(ctx, px + ox - 2, py + oy - 1, 0);
|
||||
screen_write_box(ctx, width + 4, 3, BOX_LINES_DEFAULT,
|
||||
NULL, NULL);
|
||||
border_gc, NULL);
|
||||
screen_write_cursormove(ctx, px + ox - 1, py + oy, 0);
|
||||
screen_write_clearcharacter(ctx, width + 2, 8);
|
||||
screen_write_clearcharacter(ctx, width + 2, border_gc->bg);
|
||||
screen_write_cursormove(ctx, px + ox, py + oy, 0);
|
||||
format_draw(ctx, gc, width, label, NULL, 0);
|
||||
format_draw(ctx, label_gc, width, label, NULL, 0);
|
||||
free(new_label);
|
||||
}
|
||||
|
||||
static void
|
||||
window_tree_border_cell(struct grid_cell *gc, struct options *oo,
|
||||
struct format_tree *ft)
|
||||
{
|
||||
memcpy(gc, &grid_default_cell, sizeof *gc);
|
||||
style_apply(gc, oo, "tree-mode-border-style", ft);
|
||||
}
|
||||
|
||||
static void
|
||||
window_tree_draw_session(struct window_tree_modedata *data, struct session *s,
|
||||
struct screen_write_ctx *ctx, u_int sx, u_int sy)
|
||||
@@ -437,7 +521,7 @@ window_tree_draw_session(struct window_tree_modedata *data, struct session *s,
|
||||
u_int cx = ctx->s->cx, cy = ctx->s->cy;
|
||||
u_int loop, total, visible, each, width, offset;
|
||||
u_int current, start, end, remaining, i;
|
||||
struct grid_cell gc;
|
||||
struct grid_cell gc, label_gc;
|
||||
int left, right;
|
||||
char *label;
|
||||
const char *format;
|
||||
@@ -495,20 +579,21 @@ window_tree_draw_session(struct window_tree_modedata *data, struct session *s,
|
||||
if (each == 0)
|
||||
return;
|
||||
|
||||
window_tree_border_cell(&gc, data->wp->window->options, NULL);
|
||||
if (left) {
|
||||
data->left = cx + 2;
|
||||
screen_write_cursormove(ctx, cx + 2, cy, 0);
|
||||
screen_write_vline(ctx, sy, 0, 0);
|
||||
screen_write_vline(ctx, sy, 0, 0, &gc);
|
||||
screen_write_cursormove(ctx, cx, cy + sy / 2, 0);
|
||||
screen_write_puts(ctx, &grid_default_cell, "<");
|
||||
screen_write_puts(ctx, &gc, "<");
|
||||
} else
|
||||
data->left = -1;
|
||||
if (right) {
|
||||
data->right = cx + sx - 3;
|
||||
screen_write_cursormove(ctx, cx + sx - 3, cy, 0);
|
||||
screen_write_vline(ctx, sy, 0, 0);
|
||||
screen_write_vline(ctx, sy, 0, 0, &gc);
|
||||
screen_write_cursormove(ctx, cx + sx - 1, cy + sy / 2, 0);
|
||||
screen_write_puts(ctx, &grid_default_cell, ">");
|
||||
screen_write_puts(ctx, &gc, ">");
|
||||
} else
|
||||
data->right = -1;
|
||||
|
||||
@@ -530,8 +615,10 @@ window_tree_draw_session(struct window_tree_modedata *data, struct session *s,
|
||||
ft = format_create(NULL, NULL, FORMAT_WINDOW|w->id, 0);
|
||||
format_defaults(ft, NULL, s, wl, NULL);
|
||||
|
||||
memcpy(&gc, &grid_default_cell, sizeof gc);
|
||||
style_apply(&gc, oo, "tree-mode-preview-style", ft);
|
||||
window_tree_border_cell(&gc, oo, ft);
|
||||
memcpy(&label_gc, &grid_default_cell, sizeof label_gc);
|
||||
style_apply(&label_gc, oo, "tree-mode-preview-style", ft);
|
||||
label_gc.bg = gc.bg;
|
||||
|
||||
if (left)
|
||||
offset = 3 + (i * each);
|
||||
@@ -550,7 +637,7 @@ window_tree_draw_session(struct window_tree_modedata *data, struct session *s,
|
||||
label = format_expand(ft, format);
|
||||
if (*label != '\0') {
|
||||
window_tree_draw_label(ctx, cx + offset, cy,
|
||||
width, sy, &gc, label);
|
||||
width, sy, &gc, &label_gc, label);
|
||||
}
|
||||
free(label);
|
||||
}
|
||||
@@ -558,7 +645,7 @@ window_tree_draw_session(struct window_tree_modedata *data, struct session *s,
|
||||
if (loop != end - 1) {
|
||||
screen_write_cursormove(ctx, cx + offset + width, cy,
|
||||
0);
|
||||
screen_write_vline(ctx, sy, 0, 0);
|
||||
screen_write_vline(ctx, sy, 0, 0, &gc);
|
||||
}
|
||||
loop++;
|
||||
|
||||
@@ -575,7 +662,7 @@ window_tree_draw_window(struct window_tree_modedata *data, struct session *s,
|
||||
u_int cx = ctx->s->cx, cy = ctx->s->cy;
|
||||
u_int loop, total, visible, each, width, offset;
|
||||
u_int current, start, end, remaining, i;
|
||||
struct grid_cell gc;
|
||||
struct grid_cell gc, label_gc;
|
||||
int left, right;
|
||||
char *label;
|
||||
const char *format;
|
||||
@@ -639,20 +726,21 @@ window_tree_draw_window(struct window_tree_modedata *data, struct session *s,
|
||||
if (each == 0)
|
||||
return;
|
||||
|
||||
window_tree_border_cell(&gc, data->wp->window->options, NULL);
|
||||
if (left) {
|
||||
data->left = cx + 2;
|
||||
screen_write_cursormove(ctx, cx + 2, cy, 0);
|
||||
screen_write_vline(ctx, sy, 0, 0);
|
||||
screen_write_vline(ctx, sy, 0, 0, &gc);
|
||||
screen_write_cursormove(ctx, cx, cy + sy / 2, 0);
|
||||
screen_write_puts(ctx, &grid_default_cell, "<");
|
||||
screen_write_puts(ctx, &gc, "<");
|
||||
} else
|
||||
data->left = -1;
|
||||
if (right) {
|
||||
data->right = cx + sx - 3;
|
||||
screen_write_cursormove(ctx, cx + sx - 3, cy, 0);
|
||||
screen_write_vline(ctx, sy, 0, 0);
|
||||
screen_write_vline(ctx, sy, 0, 0, &gc);
|
||||
screen_write_cursormove(ctx, cx + sx - 1, cy + sy / 2, 0);
|
||||
screen_write_puts(ctx, &grid_default_cell, ">");
|
||||
screen_write_puts(ctx, &gc, ">");
|
||||
} else
|
||||
data->right = -1;
|
||||
|
||||
@@ -675,8 +763,10 @@ window_tree_draw_window(struct window_tree_modedata *data, struct session *s,
|
||||
ft = format_create(NULL, NULL, FORMAT_PANE|wp->id, 0);
|
||||
format_defaults(ft, NULL, s, wl, wp);
|
||||
|
||||
memcpy(&gc, &grid_default_cell, sizeof gc);
|
||||
style_apply(&gc, oo, "tree-mode-preview-style", ft);
|
||||
window_tree_border_cell(&gc, oo, ft);
|
||||
memcpy(&label_gc, &grid_default_cell, sizeof label_gc);
|
||||
style_apply(&label_gc, oo, "tree-mode-preview-style", ft);
|
||||
label_gc.bg = gc.bg;
|
||||
|
||||
if (left)
|
||||
offset = 3 + (i * each);
|
||||
@@ -695,7 +785,7 @@ window_tree_draw_window(struct window_tree_modedata *data, struct session *s,
|
||||
label = format_expand(ft, format);
|
||||
if (*label != '\0') {
|
||||
window_tree_draw_label(ctx, cx + offset, cy,
|
||||
width, sy, &gc, label);
|
||||
width, sy, &gc, &label_gc, label);
|
||||
}
|
||||
free(label);
|
||||
}
|
||||
@@ -703,7 +793,7 @@ window_tree_draw_window(struct window_tree_modedata *data, struct session *s,
|
||||
if (loop != end - 1) {
|
||||
screen_write_cursormove(ctx, cx + offset + width, cy,
|
||||
0);
|
||||
screen_write_vline(ctx, sy, 0, 0);
|
||||
screen_write_vline(ctx, sy, 0, 0, &gc);
|
||||
}
|
||||
loop++;
|
||||
|
||||
@@ -711,6 +801,81 @@ window_tree_draw_window(struct window_tree_modedata *data, struct session *s,
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
window_tree_draw_info(struct window_tree_modedata *data, void *itemdata,
|
||||
struct screen_write_ctx *ctx, u_int sx, u_int sy)
|
||||
{
|
||||
struct window_tree_itemdata *item = itemdata;
|
||||
struct screen *s = ctx->s;
|
||||
struct session *sp;
|
||||
struct winlink *wl;
|
||||
struct window_pane *wp;
|
||||
struct grid_cell gc;
|
||||
u_int cx = s->cx, cy = s->cy, i, j, k;
|
||||
struct format_tree *ft;
|
||||
char *expanded;
|
||||
const char *const *lines[3];
|
||||
u_int count[3], n = 0;
|
||||
|
||||
window_tree_pull_item(item, &sp, &wl, &wp);
|
||||
if (sp == NULL || wp == NULL)
|
||||
return;
|
||||
|
||||
if (item->type == WINDOW_TREE_PANE) {
|
||||
lines[n] = window_tree_pane_info_lines;
|
||||
count[n++] = nitems(window_tree_pane_info_lines);
|
||||
}
|
||||
if (item->type == WINDOW_TREE_PANE ||
|
||||
item->type == WINDOW_TREE_WINDOW) {
|
||||
lines[n] = window_tree_window_info_lines;
|
||||
count[n++] = nitems(window_tree_window_info_lines);
|
||||
}
|
||||
lines[n] = window_tree_session_info_lines;
|
||||
count[n++] = nitems(window_tree_session_info_lines);
|
||||
|
||||
ft = format_create(NULL, NULL, FORMAT_NONE, 0);
|
||||
format_defaults(ft, NULL, sp, wl, wp);
|
||||
|
||||
i = 0;
|
||||
for (j = 0; j < n; j++) {
|
||||
if (j != 0) {
|
||||
if (i == sy)
|
||||
break;
|
||||
window_tree_border_cell(&gc, data->wp->window->options,
|
||||
NULL);
|
||||
screen_write_cursormove(ctx, cx, cy + i, 0);
|
||||
screen_write_hline(ctx, sx, 0, 0, BOX_LINES_DEFAULT,
|
||||
&gc);
|
||||
if (sx > 14) {
|
||||
gc.attr |= GRID_ATTR_CHARSET;
|
||||
screen_write_cursormove(ctx, cx + 14, cy + i,
|
||||
0);
|
||||
screen_write_putc(ctx, &gc, 'n');
|
||||
}
|
||||
i++;
|
||||
}
|
||||
for (k = 0; k < count[j]; k++) {
|
||||
if (i == sy)
|
||||
break;
|
||||
expanded = format_expand(ft, lines[j][k]);
|
||||
screen_write_cursormove(ctx, cx, cy + i, 0);
|
||||
format_draw(ctx, &grid_default_cell, sx, expanded, NULL,
|
||||
0);
|
||||
free(expanded);
|
||||
i++;
|
||||
}
|
||||
if (i == sy)
|
||||
break;
|
||||
}
|
||||
if (sx > 14 && i < sy) {
|
||||
window_tree_border_cell(&gc, data->wp->window->options, NULL);
|
||||
screen_write_cursormove(ctx, cx + 14, cy + i, 0);
|
||||
screen_write_vline(ctx, sy - i, 0, 0, &gc);
|
||||
}
|
||||
|
||||
format_free(ft);
|
||||
}
|
||||
|
||||
static void
|
||||
window_tree_draw(void *modedata, void *itemdata, struct screen_write_ctx *ctx,
|
||||
u_int sx, u_int sy)
|
||||
@@ -725,6 +890,11 @@ window_tree_draw(void *modedata, void *itemdata, struct screen_write_ctx *ctx,
|
||||
if (wp == NULL)
|
||||
return;
|
||||
|
||||
if (data->preview_is_info) {
|
||||
window_tree_draw_info(data, item, ctx, sx, sy);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (item->type) {
|
||||
case WINDOW_TREE_NONE:
|
||||
break;
|
||||
@@ -889,18 +1059,32 @@ window_tree_sort(struct sort_criteria *sort_crit)
|
||||
}
|
||||
|
||||
static const char* window_tree_help_lines[] = {
|
||||
"#[bold] Enter #[default]#[acs]x#[default] Choose selected item",
|
||||
"#[bold] S-Up #[default]#[acs]x#[default] Swap current and previous window",
|
||||
"#[bold] S-Down #[default]#[acs]x#[default] Swap current and next window",
|
||||
"#[bold] x #[default]#[acs]x#[default] Kill selected item",
|
||||
"#[bold] X #[default]#[acs]x#[default] Kill tagged items",
|
||||
"#[bold] < #[default]#[acs]x#[default] Scroll previews left",
|
||||
"#[bold] > #[default]#[acs]x#[default] Scroll previews right",
|
||||
"#[bold] m #[default]#[acs]x#[default] Set the marked pane",
|
||||
"#[bold] M #[default]#[acs]x#[default] Clear the marked pane",
|
||||
"#[bold] : #[default]#[acs]x#[default] Run a command for each tagged item",
|
||||
"#[bold] f #[default]#[acs]x#[default] Enter a format",
|
||||
"#[bold] H #[default]#[acs]x#[default] Jump to the starting pane",
|
||||
"#[fg=themelightgrey]"
|
||||
" Enter #[#{E:tree-mode-border-style},acs]x#[default] Choose selected item",
|
||||
"#[fg=themelightgrey]"
|
||||
" S-Up #[#{E:tree-mode-border-style},acs]x#[default] Swap current and previous window",
|
||||
"#[fg=themelightgrey]"
|
||||
" S-Down #[#{E:tree-mode-border-style},acs]x#[default] Swap current and next window",
|
||||
"#[fg=themelightgrey]"
|
||||
" x #[#{E:tree-mode-border-style},acs]x#[default] Kill selected item",
|
||||
"#[fg=themelightgrey]"
|
||||
" X #[#{E:tree-mode-border-style},acs]x#[default] Kill tagged items",
|
||||
"#[fg=themelightgrey]"
|
||||
" < #[#{E:tree-mode-border-style},acs]x#[default] Scroll previews left",
|
||||
"#[fg=themelightgrey]"
|
||||
" > #[#{E:tree-mode-border-style},acs]x#[default] Scroll previews right",
|
||||
"#[fg=themelightgrey]"
|
||||
" m #[#{E:tree-mode-border-style},acs]x#[default] Set the marked pane",
|
||||
"#[fg=themelightgrey]"
|
||||
" M #[#{E:tree-mode-border-style},acs]x#[default] Clear the marked pane",
|
||||
"#[fg=themelightgrey]"
|
||||
" i #[#{E:tree-mode-border-style},acs]x#[default] Toggle session, window and pane information",
|
||||
"#[fg=themelightgrey]"
|
||||
" : #[#{E:tree-mode-border-style},acs]x#[default] Run a command for each tagged item",
|
||||
"#[fg=themelightgrey]"
|
||||
" f #[#{E:tree-mode-border-style},acs]x#[default] Enter a format",
|
||||
"#[fg=themelightgrey]"
|
||||
" H #[#{E:tree-mode-border-style},acs]x#[default] Jump to the starting pane",
|
||||
NULL
|
||||
};
|
||||
|
||||
@@ -954,6 +1138,7 @@ window_tree_init(struct window_mode_entry *wme, struct cmd_find_state *fs,
|
||||
window_tree_get_key, window_tree_swap, window_tree_sort,
|
||||
window_tree_help, data, window_tree_menu_items, &s);
|
||||
mode_tree_zoom(data->data, args);
|
||||
mode_tree_view_name(data->data, "preview");
|
||||
|
||||
mode_tree_build(data->data);
|
||||
mode_tree_draw(data->data);
|
||||
@@ -1080,14 +1265,14 @@ window_tree_command_done(__unused struct cmdq_item *item, void *modedata)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
static int
|
||||
static enum prompt_result
|
||||
window_tree_command_callback(struct client *c, void *modedata, const char *s,
|
||||
__unused int done)
|
||||
__unused enum prompt_key_result key)
|
||||
{
|
||||
struct window_tree_modedata *data = modedata;
|
||||
|
||||
if (s == NULL || *s == '\0' || data->dead)
|
||||
return (0);
|
||||
return (PROMPT_CLOSE);
|
||||
|
||||
data->entered = s;
|
||||
mode_tree_each_tagged(data->data, window_tree_command_each, c,
|
||||
@@ -1097,7 +1282,7 @@ window_tree_command_callback(struct client *c, void *modedata, const char *s,
|
||||
data->references++;
|
||||
cmdq_append(c, cmdq_get_callback(window_tree_command_done, data));
|
||||
|
||||
return (0);
|
||||
return (PROMPT_CLOSE);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1139,17 +1324,17 @@ window_tree_kill_each(__unused void *modedata, void *itemdata,
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
static enum prompt_result
|
||||
window_tree_kill_current_callback(struct client *c, void *modedata,
|
||||
const char *s, __unused int done)
|
||||
const char *s, __unused enum prompt_key_result key)
|
||||
{
|
||||
struct window_tree_modedata *data = modedata;
|
||||
struct mode_tree_data *mtd = data->data;
|
||||
|
||||
if (s == NULL || *s == '\0' || data->dead)
|
||||
return (0);
|
||||
return (PROMPT_CLOSE);
|
||||
if (tolower((u_char) s[0]) != 'y' || s[1] != '\0')
|
||||
return (0);
|
||||
return (PROMPT_CLOSE);
|
||||
|
||||
window_tree_kill_each(data, mode_tree_get_current(mtd), c, KEYC_NONE);
|
||||
server_renumber_all();
|
||||
@@ -1157,20 +1342,20 @@ window_tree_kill_current_callback(struct client *c, void *modedata,
|
||||
data->references++;
|
||||
cmdq_append(c, cmdq_get_callback(window_tree_command_done, data));
|
||||
|
||||
return (0);
|
||||
return (PROMPT_CLOSE);
|
||||
}
|
||||
|
||||
static int
|
||||
static enum prompt_result
|
||||
window_tree_kill_tagged_callback(struct client *c, void *modedata,
|
||||
const char *s, __unused int done)
|
||||
const char *s, __unused enum prompt_key_result key)
|
||||
{
|
||||
struct window_tree_modedata *data = modedata;
|
||||
struct mode_tree_data *mtd = data->data;
|
||||
|
||||
if (s == NULL || *s == '\0' || data->dead)
|
||||
return (0);
|
||||
return (PROMPT_CLOSE);
|
||||
if (tolower((u_char) s[0]) != 'y' || s[1] != '\0')
|
||||
return (0);
|
||||
return (PROMPT_CLOSE);
|
||||
|
||||
mode_tree_each_tagged(mtd, window_tree_kill_each, c, KEYC_NONE, 1);
|
||||
server_renumber_all();
|
||||
@@ -1178,7 +1363,7 @@ window_tree_kill_tagged_callback(struct client *c, void *modedata,
|
||||
data->references++;
|
||||
cmdq_append(c, cmdq_get_callback(window_tree_command_done, data));
|
||||
|
||||
return (0);
|
||||
return (PROMPT_CLOSE);
|
||||
}
|
||||
|
||||
static key_code
|
||||
@@ -1293,6 +1478,13 @@ again:
|
||||
server_clear_marked();
|
||||
mode_tree_build(data->data);
|
||||
break;
|
||||
case 'i':
|
||||
data->preview_is_info = !data->preview_is_info;
|
||||
if (data->preview_is_info)
|
||||
mode_tree_view_name(data->data, "info");
|
||||
else
|
||||
mode_tree_view_name(data->data, "preview");
|
||||
break;
|
||||
case 'x':
|
||||
window_tree_pull_item(item, &ns, &nwl, &nwp);
|
||||
switch (item->type) {
|
||||
@@ -1317,10 +1509,11 @@ again:
|
||||
if (prompt == NULL)
|
||||
break;
|
||||
data->references++;
|
||||
status_prompt_set(c, NULL, prompt, "",
|
||||
mode_tree_set_prompt(data->data, c, prompt, "",
|
||||
PROMPT_TYPE_COMMAND,
|
||||
PROMPT_SINGLE|PROMPT_NOFORMAT|data->prompt_flags,
|
||||
window_tree_kill_current_callback, window_tree_command_free,
|
||||
data, PROMPT_SINGLE|PROMPT_NOFORMAT|data->prompt_flags,
|
||||
PROMPT_TYPE_COMMAND);
|
||||
data);
|
||||
free(prompt);
|
||||
break;
|
||||
case 'X':
|
||||
@@ -1329,10 +1522,11 @@ again:
|
||||
break;
|
||||
xasprintf(&prompt, "Kill %u tagged? ", tagged);
|
||||
data->references++;
|
||||
status_prompt_set(c, NULL, prompt, "",
|
||||
mode_tree_set_prompt(data->data, c, prompt, "",
|
||||
PROMPT_TYPE_COMMAND,
|
||||
PROMPT_SINGLE|PROMPT_NOFORMAT|data->prompt_flags,
|
||||
window_tree_kill_tagged_callback, window_tree_command_free,
|
||||
data, PROMPT_SINGLE|PROMPT_NOFORMAT|data->prompt_flags,
|
||||
PROMPT_TYPE_COMMAND);
|
||||
data);
|
||||
free(prompt);
|
||||
break;
|
||||
case ':':
|
||||
@@ -1342,9 +1536,10 @@ again:
|
||||
else
|
||||
xasprintf(&prompt, "(current) ");
|
||||
data->references++;
|
||||
status_prompt_set(c, NULL, prompt, "",
|
||||
mode_tree_set_prompt(data->data, c, prompt, "",
|
||||
PROMPT_TYPE_COMMAND, PROMPT_NOFORMAT,
|
||||
window_tree_command_callback, window_tree_command_free,
|
||||
data, PROMPT_NOFORMAT, PROMPT_TYPE_COMMAND);
|
||||
data);
|
||||
free(prompt);
|
||||
break;
|
||||
case '\r':
|
||||
|
||||
@@ -55,7 +55,7 @@ window_visible_ranges(struct window_pane *base_wp, int px, int py, u_int width,
|
||||
struct window *w;
|
||||
struct visible_range *ri;
|
||||
static struct visible_ranges sr = { NULL, 0, 0 };
|
||||
int found_self, sb, sb_w, sb_pos;
|
||||
int found_self, sb_w, sb_pos;
|
||||
int lb, rb, tb, bb, sx, ex, no_border;
|
||||
u_int i, s;
|
||||
|
||||
@@ -95,8 +95,6 @@ window_visible_ranges(struct window_pane *base_wp, int px, int py, u_int width,
|
||||
r->used = 1;
|
||||
}
|
||||
|
||||
sb = options_get_number(w->options, "pane-scrollbars");
|
||||
sb_pos = options_get_number(w->options, "pane-scrollbars-position");
|
||||
|
||||
found_self = 0;
|
||||
TAILQ_FOREACH_REVERSE(wp, &w->z_index, window_panes_zindex, zentry) {
|
||||
@@ -126,7 +124,9 @@ window_visible_ranges(struct window_pane *base_wp, int px, int py, u_int width,
|
||||
continue;
|
||||
|
||||
sb_w = wp->scrollbar_style.width + wp->scrollbar_style.pad;
|
||||
if (!window_pane_show_scrollbar(wp, sb))
|
||||
if (window_pane_scrollbar_reserve(wp))
|
||||
sb_pos = w->sb_pos;
|
||||
else
|
||||
sb_w = sb_pos = 0;
|
||||
|
||||
for (i = 0; i < r->used; i++) {
|
||||
|
||||
352
window.c
352
window.c
@@ -71,6 +71,7 @@ struct window_pane_input_data {
|
||||
static struct window_pane *window_pane_create(struct window *, u_int, u_int,
|
||||
u_int);
|
||||
static void window_pane_destroy(struct window_pane *);
|
||||
static void window_pane_scrollbar_timer(int, short, void *);
|
||||
static void window_pane_full_size_offset(struct window_pane *wp,
|
||||
int *xoff, int *yoff, u_int *sx, u_int *sy);
|
||||
|
||||
@@ -78,6 +79,14 @@ RB_GENERATE(windows, window, entry, window_cmp);
|
||||
RB_GENERATE(winlinks, winlink, entry, winlink_cmp);
|
||||
RB_GENERATE(window_pane_tree, window_pane, tree_entry, window_pane_cmp);
|
||||
|
||||
struct window_pane_prompt {
|
||||
u_int wp_id;
|
||||
struct client *c;
|
||||
status_prompt_input_cb inputcb;
|
||||
prompt_free_cb freecb;
|
||||
void *data;
|
||||
};
|
||||
|
||||
int
|
||||
window_cmp(struct window *w1, struct window *w2)
|
||||
{
|
||||
@@ -411,11 +420,11 @@ window_remove_ref(struct window *w, const char *from)
|
||||
}
|
||||
|
||||
void
|
||||
window_set_name(struct window *w, const char *new_name, const char *forbid)
|
||||
window_set_name(struct window *w, const char *new_name, int untrusted)
|
||||
{
|
||||
char *name;
|
||||
|
||||
name = clean_name(new_name, forbid);
|
||||
name = clean_name(new_name, untrusted);
|
||||
if (name != NULL) {
|
||||
free(w->name);
|
||||
w->name = name;
|
||||
@@ -635,6 +644,7 @@ window_redraw_active_switch(struct window *w, struct window_pane *wp)
|
||||
TAILQ_REMOVE(&w->z_index, wp, zentry);
|
||||
TAILQ_INSERT_HEAD(&w->z_index, wp, zentry);
|
||||
wp->flags |= PANE_REDRAW;
|
||||
redraw_invalidate_scene(w);
|
||||
}
|
||||
|
||||
wp = w->active;
|
||||
@@ -772,6 +782,7 @@ window_zoom(struct window_pane *wp)
|
||||
w->flags |= WINDOW_ZOOMED;
|
||||
notify_window("window-layout-changed", w);
|
||||
|
||||
redraw_invalidate_scene(w);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -798,6 +809,7 @@ window_unzoom(struct window *w, int notify)
|
||||
if (notify)
|
||||
notify_window("window-layout-changed", w);
|
||||
|
||||
redraw_invalidate_scene(w);
|
||||
return (0);
|
||||
}
|
||||
|
||||
@@ -854,6 +866,7 @@ window_add_pane(struct window *w, struct window_pane *other, u_int hlimit,
|
||||
else {
|
||||
TAILQ_INSERT_HEAD(&w->z_index, wp, zentry);
|
||||
}
|
||||
redraw_invalidate_scene(w);
|
||||
return (wp);
|
||||
}
|
||||
|
||||
@@ -895,6 +908,7 @@ window_lost_pane(struct window *w, struct window_pane *wp)
|
||||
notify_window("window-pane-changed", w);
|
||||
window_update_focus(w);
|
||||
}
|
||||
redraw_invalidate_scene(w);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -903,6 +917,7 @@ window_remove_pane(struct window *w, struct window_pane *wp)
|
||||
window_lost_pane(w, wp);
|
||||
TAILQ_REMOVE(&w->panes, wp, entry);
|
||||
TAILQ_REMOVE(&w->z_index, wp, zentry);
|
||||
redraw_invalidate_scene(w);
|
||||
window_pane_destroy(wp);
|
||||
}
|
||||
|
||||
@@ -1126,6 +1141,7 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
|
||||
|
||||
screen_init(&wp->status_screen, 1, 1, 0);
|
||||
style_ranges_init(&wp->border_status_line.ranges);
|
||||
evtimer_set(&wp->sb_auto_timer, window_pane_scrollbar_timer, wp);
|
||||
|
||||
if (gethostname(host, sizeof host) == 0)
|
||||
screen_set_title(&wp->base, host, 0);
|
||||
@@ -1157,13 +1173,71 @@ window_pane_wait_finish(struct window_pane *wp)
|
||||
cmdq_continue(item);
|
||||
}
|
||||
|
||||
static void
|
||||
window_pane_free_modes(struct window_pane *wp)
|
||||
{
|
||||
struct window_mode_entry *wme;
|
||||
|
||||
while (!TAILQ_EMPTY(&wp->modes)) {
|
||||
wme = TAILQ_FIRST(&wp->modes);
|
||||
TAILQ_REMOVE(&wp->modes, wme, entry);
|
||||
wme->mode->free(wme);
|
||||
free(wme);
|
||||
}
|
||||
|
||||
wp->screen = &wp->base;
|
||||
}
|
||||
|
||||
static void
|
||||
window_pane_scrollbar_timer(__unused int fd, __unused short events, void *arg)
|
||||
{
|
||||
struct window_pane *wp = arg;
|
||||
|
||||
wp->sb_auto_hover = 0;
|
||||
window_pane_scrollbar_hide(wp);
|
||||
}
|
||||
|
||||
static int
|
||||
window_pane_scrollbar_auto_hide(struct window_pane *wp)
|
||||
{
|
||||
return (wp->window->sb == PANE_SCROLLBARS_MODAL ||
|
||||
wp->window->sb == PANE_SCROLLBARS_AUTOHIDE);
|
||||
}
|
||||
|
||||
int
|
||||
window_pane_scrollbar_overlay_visible(struct window_pane *wp)
|
||||
{
|
||||
return (window_pane_scrollbar_overlay(wp) &&
|
||||
window_pane_scrollbar_visible(wp));
|
||||
}
|
||||
|
||||
void
|
||||
window_pane_scrollbar_redraw(struct window_pane *wp)
|
||||
{
|
||||
if (window_pane_scrollbar_overlay_visible(wp)) {
|
||||
wp->flags |= PANE_REDRAW;
|
||||
return;
|
||||
}
|
||||
wp->flags |= PANE_REDRAWSCROLLBAR;
|
||||
}
|
||||
|
||||
static void
|
||||
window_pane_scrollbar_redraw_visibility(struct window_pane *wp)
|
||||
{
|
||||
redraw_invalidate_scene(wp->window);
|
||||
wp->flags |= PANE_REDRAW;
|
||||
server_redraw_window(wp->window);
|
||||
}
|
||||
|
||||
static void
|
||||
window_pane_destroy(struct window_pane *wp)
|
||||
{
|
||||
window_pane_wait_finish(wp);
|
||||
spawn_editor_finish(wp);
|
||||
|
||||
window_pane_reset_mode_all(wp);
|
||||
window_pane_clear_prompt(wp);
|
||||
|
||||
window_pane_free_modes(wp);
|
||||
free(wp->searchstr);
|
||||
|
||||
if (wp->fd != -1) {
|
||||
@@ -1190,6 +1264,8 @@ window_pane_destroy(struct window_pane *wp)
|
||||
event_del(&wp->resize_timer);
|
||||
if (event_initialized(&wp->sync_timer))
|
||||
event_del(&wp->sync_timer);
|
||||
if (event_initialized(&wp->sb_auto_timer))
|
||||
event_del(&wp->sb_auto_timer);
|
||||
window_pane_clear_resizes(wp, NULL);
|
||||
|
||||
RB_REMOVE(window_pane_tree, &all_window_panes, wp);
|
||||
@@ -1259,7 +1335,8 @@ window_pane_set_event(struct window_pane *wp)
|
||||
}
|
||||
|
||||
void
|
||||
window_pane_clear_resizes(struct window_pane *wp, struct window_pane_resize *except)
|
||||
window_pane_clear_resizes(struct window_pane *wp,
|
||||
struct window_pane_resize *except)
|
||||
{
|
||||
struct window_pane_resize *r, *r1;
|
||||
|
||||
@@ -1379,6 +1456,7 @@ window_pane_reset_mode(struct window_pane *wp)
|
||||
server_kill_pane(wp);
|
||||
}
|
||||
|
||||
/* Reset all modes. */
|
||||
void
|
||||
window_pane_reset_mode_all(struct window_pane *wp)
|
||||
{
|
||||
@@ -1386,6 +1464,165 @@ window_pane_reset_mode_all(struct window_pane *wp)
|
||||
window_pane_reset_mode(wp);
|
||||
}
|
||||
|
||||
/* Prompt input callback. */
|
||||
static enum prompt_result
|
||||
window_pane_prompt_input_callback(void *data, const char *s,
|
||||
enum prompt_key_result key)
|
||||
{
|
||||
struct window_pane_prompt *wpp = data;
|
||||
|
||||
if (wpp->inputcb != NULL)
|
||||
return (wpp->inputcb(wpp->c, wpp->data, s, key));
|
||||
return (PROMPT_CLOSE);
|
||||
}
|
||||
|
||||
/* Prompt free callback. */
|
||||
static void
|
||||
window_pane_prompt_free_callback(void *data)
|
||||
{
|
||||
struct window_pane_prompt *wpp = data;
|
||||
struct window_pane *wp;
|
||||
|
||||
wp = window_pane_find_by_id(wpp->wp_id);
|
||||
if (wp != NULL && wp->prompt_data == wpp)
|
||||
wp->prompt_data = NULL;
|
||||
if (wpp->freecb != NULL)
|
||||
wpp->freecb(wpp->data);
|
||||
free(wpp);
|
||||
}
|
||||
|
||||
/* Open a prompt owned by a pane, drawn over the pane instead of the status. */
|
||||
void
|
||||
window_pane_set_prompt(struct window_pane *wp, struct client *c,
|
||||
struct cmd_find_state *fs, const char *msg, const char *input,
|
||||
status_prompt_input_cb inputcb, prompt_free_cb freecb, void *data,
|
||||
int flags, enum prompt_type type)
|
||||
{
|
||||
struct session *s = NULL;
|
||||
struct prompt_create_data pd;
|
||||
struct window_pane_prompt *wpp;
|
||||
|
||||
if (c != NULL)
|
||||
s = c->session;
|
||||
|
||||
window_pane_clear_prompt(wp);
|
||||
|
||||
wpp = xcalloc(1, sizeof *wpp);
|
||||
wpp->wp_id = wp->id;
|
||||
wpp->c = c;
|
||||
wpp->inputcb = inputcb;
|
||||
wpp->freecb = freecb;
|
||||
wpp->data = data;
|
||||
|
||||
memset(&pd, 0, sizeof pd);
|
||||
prompt_set_options(&pd, s);
|
||||
pd.fs = fs;
|
||||
pd.prompt = msg;
|
||||
pd.input = input;
|
||||
pd.type = type;
|
||||
pd.flags = flags;
|
||||
pd.inputcb = window_pane_prompt_input_callback;
|
||||
pd.freecb = window_pane_prompt_free_callback;
|
||||
pd.data = wpp;
|
||||
|
||||
wp->prompt = prompt_create(&pd);
|
||||
wp->prompt_data = wpp;
|
||||
wp->flags |= PANE_REDRAW;
|
||||
|
||||
prompt_incremental_start(wp->prompt);
|
||||
}
|
||||
|
||||
/* Close a pane prompt. */
|
||||
void
|
||||
window_pane_clear_prompt(struct window_pane *wp)
|
||||
{
|
||||
struct prompt *prompt = wp->prompt;
|
||||
|
||||
if (prompt == NULL)
|
||||
return;
|
||||
wp->prompt = NULL;
|
||||
prompt_free(prompt);
|
||||
wp->flags |= PANE_REDRAW;
|
||||
}
|
||||
|
||||
/* Does this pane have an open prompt? */
|
||||
int
|
||||
window_pane_has_prompt(struct window_pane *wp)
|
||||
{
|
||||
return (wp->prompt != NULL);
|
||||
}
|
||||
|
||||
/* Replace the message and input of an open pane prompt. */
|
||||
void
|
||||
window_pane_update_prompt(struct window_pane *wp, const char *msg,
|
||||
const char *input)
|
||||
{
|
||||
if (wp->prompt != NULL) {
|
||||
prompt_update(wp->prompt, msg, input);
|
||||
wp->flags |= PANE_REDRAW;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Pass a key to a pane prompt. The client is set transiently for the duration
|
||||
* of the key in case the prompt or pane is destroyed by the callback.
|
||||
*/
|
||||
enum prompt_key_result
|
||||
window_pane_prompt_key(struct window_pane *wp, struct client *c, key_code key,
|
||||
struct mouse_event *m)
|
||||
{
|
||||
struct prompt *prompt = wp->prompt;
|
||||
struct window_pane_prompt *wpp = wp->prompt_data;
|
||||
enum prompt_key_result result;
|
||||
u_int wp_id = wp->id, x, y, py;
|
||||
int redraw = 0;
|
||||
|
||||
if (prompt == NULL)
|
||||
return (PROMPT_KEY_NOT_HANDLED);
|
||||
|
||||
if (wpp != NULL)
|
||||
wpp->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(wp, m, &x, &y, 0) != 0)
|
||||
result = PROMPT_KEY_NOT_HANDLED;
|
||||
else {
|
||||
if (c != NULL && status_at_line(c) == 0)
|
||||
py = 0;
|
||||
else
|
||||
py = wp->sy - 1;
|
||||
if (y == py) {
|
||||
result = prompt_mouse(prompt, x, 0, wp->sx,
|
||||
&redraw);
|
||||
} else
|
||||
result = PROMPT_KEY_NOT_HANDLED;
|
||||
}
|
||||
} else
|
||||
result = prompt_key(prompt, key, &redraw);
|
||||
|
||||
wp = window_pane_find_by_id(wp_id);
|
||||
if (wp == NULL)
|
||||
return (result);
|
||||
if (wpp != NULL && wp->prompt_data == wpp)
|
||||
wpp->c = NULL;
|
||||
|
||||
/*
|
||||
* Only an explicit close or the prompt marking itself closed ends it;
|
||||
* cursor movement and editing keep it open.
|
||||
*/
|
||||
if (wp->prompt == prompt &&
|
||||
(result == PROMPT_KEY_CLOSE || prompt_closed(prompt)))
|
||||
window_pane_clear_prompt(wp);
|
||||
|
||||
if (redraw || wp->prompt != prompt)
|
||||
wp->flags |= PANE_REDRAW;
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
static void
|
||||
window_pane_copy_paste(struct window_pane *wp, char *buf, size_t len)
|
||||
{
|
||||
@@ -1450,6 +1687,12 @@ window_pane_key(struct window_pane *wp, struct client *c, struct session *s,
|
||||
|
||||
wme = TAILQ_FIRST(&wp->modes);
|
||||
if (wme != NULL) {
|
||||
/*
|
||||
* No mode uses mouse motion events, so drop them here rather
|
||||
* than passing them on and causing a redraw on every movement.
|
||||
*/
|
||||
if (KEYC_IS_TYPE(key, KEYC_TYPE_MOUSEMOVE))
|
||||
return (0);
|
||||
if (wme->mode->key != NULL && c != NULL) {
|
||||
key &= ~KEYC_MASK_FLAGS;
|
||||
wme->mode->key(wme, c, s, wl, key, m);
|
||||
@@ -1563,17 +1806,13 @@ window_pane_full_size_offset(struct window_pane *wp, int *xoff, int *yoff,
|
||||
u_int *sx, u_int *sy)
|
||||
{
|
||||
struct window *w = wp->window;
|
||||
int pane_scrollbars;
|
||||
u_int sb_w, sb_pos;
|
||||
u_int sb_w;
|
||||
|
||||
pane_scrollbars = options_get_number(w->options, "pane-scrollbars");
|
||||
sb_pos = options_get_number(w->options, "pane-scrollbars-position");
|
||||
|
||||
if (window_pane_show_scrollbar(wp, pane_scrollbars))
|
||||
if (window_pane_scrollbar_reserve(wp))
|
||||
sb_w = wp->scrollbar_style.width + wp->scrollbar_style.pad;
|
||||
else
|
||||
sb_w = 0;
|
||||
if (sb_pos == PANE_SCROLLBARS_LEFT) {
|
||||
if (w->sb_pos == PANE_SCROLLBARS_LEFT) {
|
||||
*xoff = wp->xoff - sb_w;
|
||||
*sx = wp->sx + sb_w;
|
||||
} else { /* sb_pos == PANE_SCROLLBARS_RIGHT */
|
||||
@@ -1989,19 +2228,93 @@ window_pane_mode(struct window_pane *wp)
|
||||
return (WINDOW_PANE_NO_MODE);
|
||||
}
|
||||
|
||||
/* Return 1 if scrollbar is or should be displayed. */
|
||||
int
|
||||
window_pane_show_scrollbar(struct window_pane *wp, int sb_option)
|
||||
window_pane_show_scrollbar(struct window_pane *wp)
|
||||
{
|
||||
if (SCREEN_IS_ALTERNATE(&wp->base))
|
||||
return (0);
|
||||
if (sb_option == PANE_SCROLLBARS_ALWAYS ||
|
||||
(sb_option == PANE_SCROLLBARS_MODAL &&
|
||||
if (wp->window->sb == PANE_SCROLLBARS_ALWAYS ||
|
||||
wp->window->sb == PANE_SCROLLBARS_AUTOHIDE ||
|
||||
(wp->window->sb == PANE_SCROLLBARS_MODAL &&
|
||||
window_pane_mode(wp) != WINDOW_PANE_NO_MODE))
|
||||
return (1);
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
window_pane_scrollbar_reserve(struct window_pane *wp)
|
||||
{
|
||||
if (!window_pane_show_scrollbar(wp))
|
||||
return (0);
|
||||
return (wp->window->sb == PANE_SCROLLBARS_ALWAYS);
|
||||
}
|
||||
|
||||
int
|
||||
window_pane_scrollbar_overlay(struct window_pane *wp)
|
||||
{
|
||||
if (!window_pane_show_scrollbar(wp))
|
||||
return (0);
|
||||
return (window_pane_scrollbar_auto_hide(wp));
|
||||
}
|
||||
|
||||
int
|
||||
window_pane_scrollbar_visible(struct window_pane *wp)
|
||||
{
|
||||
if (!window_pane_show_scrollbar(wp))
|
||||
return (0);
|
||||
if (!window_pane_scrollbar_auto_hide(wp))
|
||||
return (1);
|
||||
return (wp->sb_auto_visible);
|
||||
}
|
||||
|
||||
void
|
||||
window_pane_scrollbar_start_timer(struct window_pane *wp)
|
||||
{
|
||||
struct timeval tv;
|
||||
u_int delay;
|
||||
|
||||
if (!window_pane_scrollbar_auto_hide(wp) || !wp->sb_auto_visible)
|
||||
return;
|
||||
|
||||
delay = options_get_number(wp->window->options,
|
||||
"pane-scrollbars-timeout");
|
||||
tv.tv_sec = delay / 1000;
|
||||
tv.tv_usec = (delay % 1000) * 1000L;
|
||||
evtimer_del(&wp->sb_auto_timer);
|
||||
evtimer_add(&wp->sb_auto_timer, &tv);
|
||||
}
|
||||
|
||||
void
|
||||
window_pane_scrollbar_show(struct window_pane *wp, int start_timer)
|
||||
{
|
||||
int changed = 0;
|
||||
if (!window_pane_scrollbar_auto_hide(wp))
|
||||
return;
|
||||
if (!window_pane_show_scrollbar(wp))
|
||||
return;
|
||||
if (!wp->sb_auto_visible) {
|
||||
wp->sb_auto_visible = 1;
|
||||
changed = 1;
|
||||
}
|
||||
evtimer_del(&wp->sb_auto_timer);
|
||||
if (start_timer)
|
||||
window_pane_scrollbar_start_timer(wp);
|
||||
if (changed)
|
||||
window_pane_scrollbar_redraw_visibility(wp);
|
||||
}
|
||||
|
||||
void
|
||||
window_pane_scrollbar_hide(struct window_pane *wp)
|
||||
{
|
||||
if (event_initialized(&wp->sb_auto_timer))
|
||||
evtimer_del(&wp->sb_auto_timer);
|
||||
wp->sb_auto_hover = 0;
|
||||
if (!wp->sb_auto_visible)
|
||||
return;
|
||||
wp->sb_auto_visible = 0;
|
||||
window_pane_scrollbar_redraw_visibility(wp);
|
||||
}
|
||||
|
||||
int
|
||||
window_pane_get_bg(struct window_pane *wp)
|
||||
{
|
||||
@@ -2202,6 +2515,15 @@ window_pane_status_get_range(struct window_pane *wp, u_int x, u_int y)
|
||||
return (style_ranges_get_range(srs, x - wp->xoff - 2));
|
||||
}
|
||||
|
||||
enum pane_lines
|
||||
window_get_pane_lines(struct window *w)
|
||||
{
|
||||
struct options *oo;
|
||||
|
||||
oo = w->options;
|
||||
return (options_get_number(oo, "pane-border-lines"));
|
||||
}
|
||||
|
||||
enum pane_lines
|
||||
window_pane_get_pane_lines(struct window_pane *wp)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user