Merge branch 'master' into floating_panes

This commit is contained in:
Michael Grant
2026-03-16 09:12:08 +00:00
18 changed files with 500 additions and 75 deletions

View File

@@ -195,10 +195,6 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
}
sort_crit.reversed = args_has(args, 'r');
prefix = cmd_list_keys_get_prefix(args);
single = args_has(args, '1');
notes_only = args_has(args, 'N');
if ((tablename = args_get(args, 'T')) != NULL) {
table = key_bindings_get_table(tablename, 0);
if (table == NULL) {
@@ -207,6 +203,10 @@ cmd_list_keys_exec(struct cmd *self, struct cmdq_item *item)
}
}
prefix = cmd_list_keys_get_prefix(args);
single = args_has(args, '1');
notes_only = args_has(args, 'N');
if ((template = args_get(args, 'F')) == NULL)
template = LIST_KEYS_TEMPLATE;

View File

@@ -1604,7 +1604,9 @@ yylex_token_tilde(char **buf, size_t *len)
if (*name == '\0') {
envent = environ_find(global_environ, "HOME");
if (envent != NULL && *envent->value != '\0')
if (envent != NULL &&
envent->value != NULL &&
*envent->value != '\0')
home = envent->value;
else if ((pw = getpwuid(getuid())) != NULL)
home = pw->pw_dir;

View File

@@ -1045,6 +1045,9 @@ control_check_subs_timer(__unused int fd, __unused short events, void *data)
log_debug("%s: timer fired", __func__);
evtimer_add(&cs->subs_timer, &tv);
if (s == NULL)
return;
/* Find which subscription types are present. */
RB_FOREACH(csub, control_subs, &cs->subs) {
switch (csub->type) {

View File

@@ -4508,6 +4508,37 @@ format_window_name(struct format_expand_state *es, const char *fmt)
return (xstrdup("0"));
}
/* Add neighbor window variables to the format tree. */
static void
format_add_window_neighbor(struct format_tree *nft, struct winlink *wl,
struct session *s, const char *prefix)
{
struct options_entry *o;
const char *oname;
char *key, *prefixed, *oval;
xasprintf(&key, "%s_window_index", prefix);
format_add(nft, key, "%u", wl->idx);
free(key);
xasprintf(&key, "%s_window_active", prefix);
format_add(nft, key, "%d", wl == s->curw);
free(key);
o = options_first(wl->window->options);
while (o != NULL) {
oname = options_name(o);
if (*oname == '@') {
xasprintf(&prefixed, "%s_%s", prefix, oname);
oval = options_to_string(o, -1, 1);
format_add(nft, prefixed, "%s", oval);
free(oval);
free(prefixed);
}
o = options_next(o);
}
}
/* Loop over windows. */
static char *
format_loop_windows(struct format_expand_state *es, const char *fmt)
@@ -4551,6 +4582,17 @@ format_loop_windows(struct format_expand_state *es, const char *fmt)
nft = format_create(c, item, FORMAT_WINDOW|w->id,
ft->flags|last);
format_defaults(nft, ft->c, ft->s, wl, NULL);
/* Add neighbor window data to the format tree. */
format_add(nft, "window_after_active", "%d",
i > 0 && l[i - 1] == ft->s->curw);
format_add(nft, "window_before_active", "%d",
i + 1 < n && l[i + 1] == ft->s->curw);
if (i + 1 < n)
format_add_window_neighbor(nft, l[i + 1], ft->s, "next");
if (i > 0)
format_add_window_neighbor(nft, l[i - 1], ft->s, "prev");
format_copy_state(&next, es, 0);
next.ft = nft;
expanded = format_expand1(&next, use);

View File

@@ -357,7 +357,7 @@ sixel_parse(const char *buf, size_t len, u_int p2, u_int xpixel, u_int ypixel)
return (si);
bad:
free(si);
sixel_free(si);
return (NULL);
}

View File

@@ -949,7 +949,7 @@ input_set_state(struct input_ctx *ictx, const struct input_transition *itr)
/* Parse data. */
static void
input_parse(struct input_ctx *ictx, u_char *buf, size_t len)
input_parse(struct input_ctx *ictx, const u_char *buf, size_t len)
{
struct screen_write_ctx *sctx = &ictx->ctx;
const struct input_state *state = NULL;
@@ -1020,7 +1020,7 @@ input_parse_pane(struct window_pane *wp)
/* Parse given input. */
void
input_parse_buffer(struct window_pane *wp, u_char *buf, size_t len)
input_parse_buffer(struct window_pane *wp, const u_char *buf, size_t len)
{
struct input_ctx *ictx = wp->ictx;
struct screen_write_ctx *sctx = &ictx->ctx;
@@ -1051,7 +1051,7 @@ input_parse_buffer(struct window_pane *wp, u_char *buf, size_t len)
/* Parse given input for screen. */
void
input_parse_screen(struct input_ctx *ictx, struct screen *s,
screen_write_init_ctx_cb cb, void *arg, u_char *buf, size_t len)
screen_write_init_ctx_cb cb, void *arg, const u_char *buf, size_t len)
{
struct screen_write_ctx *sctx = &ictx->ctx;

2
menu.c
View File

@@ -363,7 +363,7 @@ menu_key_cb(struct client *c, void *data, struct key_event *event)
name = menu->items[i].name;
if (name == NULL || *name == '-')
continue;
if (event->key == menu->items[i].key) {
if ((event->key & ~KEYC_MASK_FLAGS) == menu->items[i].key) {
md->choice = i;
goto chosen;
}

View File

@@ -58,6 +58,7 @@ struct mode_tree_data {
mode_tree_key_cb keycb;
mode_tree_swap_cb swapcb;
mode_tree_sort_cb sortcb;
mode_tree_help_cb helpcb;
struct mode_tree_list children;
struct mode_tree_list saved;
@@ -132,6 +133,36 @@ static const struct menu_item mode_tree_menu_items[] = {
{ NULL, KEYC_NONE, NULL }
};
static const char* mode_tree_help_start[] = {
"\r\033[1m Up, k \033[0m\016x\017 \033[0mMove cursor up\n",
"\r\033[1m Down, j \033[0m\016x\017 \033[0mMove cursor down\n",
"\r\033[1m g \033[0m\016x\017 \033[0mGo to top\n",
"\r\033[1m G \033[0m\016x\017 \033[0mGo to bottom\n",
"\r\033[1m PPage, C-b \033[0m\016x\017 \033[0mPage up\n",
"\r\033[1m NPage, C-f \033[0m\016x\017 \033[0mPage down\n",
"\r\033[1m Left, h \033[0m\016x\017 \033[0mCollapse %1\n",
"\r\033[1m Right, l \033[0m\016x\017 \033[0mExpand %1\n",
"\r\033[1m M-- \033[0m\016x\017 \033[0mCollapse all %1s\n",
"\r\033[1m M-+ \033[0m\016x\017 \033[0mExpand all %1s\n",
"\r\033[1m t \033[0m\016x\017 \033[0mToggle %1 tag\n",
"\r\033[1m T \033[0m\016x\017 \033[0mUntag all %1s\n",
"\r\033[1m C-t \033[0m\016x\017 \033[0mTag all %1s\n",
"\r\033[1m C-s \033[0m\016x\017 \033[0mSearch forward\n",
"\r\033[1m C-r \033[0m\016x\017 \033[0mSearch backward\n",
"\r\033[1m n \033[0m\016x\017 \033[0mRepeat search forward\n",
"\r\033[1m N \033[0m\016x\017 \033[0mRepeat search backward\n",
"\r\033[1m f \033[0m\016x\017 \033[0mFilter %1s\n",
"\r\033[1m O \033[0m\016x\017 \033[0mChange sort order\n",
"\r\033[1m r \033[0m\016x\017 \033[0mReverse sort order\n",
"\r\033[1m v \033[0m\016x\017 \033[0mToggle preview\n",
NULL
};
static const char* mode_tree_help_end[] = {
"\r\033[1m q, Escape \033[0m\016x\017 \033[0mExit mode\033[H",
NULL
};
#define MODE_TREE_HELP_DEFAULT_WIDTH 39
static int
mode_tree_is_lowercase(const char *ptr)
{
@@ -453,8 +484,9 @@ mode_tree_start(struct window_pane *wp, struct args *args,
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, void *modedata,
const struct menu_item *menu, struct screen **s)
mode_tree_swap_cb swapcb, mode_tree_sort_cb sortcb,
mode_tree_help_cb helpcb, void *modedata, const struct menu_item *menu,
struct screen **s)
{
struct mode_tree_data *mtd;
@@ -488,6 +520,7 @@ mode_tree_start(struct window_pane *wp, struct args *args,
mtd->keycb = keycb;
mtd->swapcb = swapcb;
mtd->sortcb = sortcb;
mtd->helpcb = helpcb;
TAILQ_INIT(&mtd->children);
@@ -1123,6 +1156,57 @@ mode_tree_display_menu(struct mode_tree_data *mtd, struct client *c, u_int x,
}
}
static void
mode_tree_display_help(__unused struct mode_tree_data *mtd, struct client *c)
{
struct session *s = c->session;
u_int px, py, w, h = 0;
const char **line, **lines = NULL, *item = "item";
char *new_line;
if (mtd->helpcb == NULL)
w = MODE_TREE_HELP_DEFAULT_WIDTH;
else {
lines = mtd->helpcb(&w, &item);
if (w < MODE_TREE_HELP_DEFAULT_WIDTH)
w = MODE_TREE_HELP_DEFAULT_WIDTH;
}
for (line = mode_tree_help_start; *line != NULL; line++)
h++;
for (line = lines; *line != NULL; line++)
h++;
for (line = mode_tree_help_end; *line != NULL; line++)
h++;
if (c->tty.sx < w || c->tty.sy < h)
return;
px = (c->tty.sx - w) / 2;
py = (c->tty.sy - h) / 2;
if (popup_display(POPUP_CLOSEANYKEY|POPUP_NOJOB, BOX_LINES_DEFAULT,
NULL, px, py, w, h, NULL, NULL, 0, NULL, NULL, NULL, c, s, NULL,
NULL, NULL, NULL) != 0)
return;
popup_write(c, "\033[H\033[?25l\033[?7l\033)0", 17);
for (line = mode_tree_help_start; *line != NULL; line++) {
new_line = cmd_template_replace(*line, item, 1);
popup_write(c, new_line, strlen(new_line));
free(new_line);
}
for (line = lines; *line != NULL; line++) {
new_line = cmd_template_replace(*line, item, 1);
popup_write(c, new_line, strlen(new_line));
free(new_line);
}
for (line = mode_tree_help_end; *line != NULL; line++) {
new_line = cmd_template_replace(*line, item, 1);
popup_write(c, new_line, strlen(new_line));
free(new_line);
}
popup_write(c, "\033[H", 3);
}
int
mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
struct mouse_event *m, u_int *xp, u_int *yp)
@@ -1193,6 +1277,10 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
case '\033': /* Escape */
case 'g'|KEYC_CTRL:
return (1);
case KEYC_F1:
case 'h'|KEYC_CTRL:
mode_tree_display_help(mtd, c);
break;
case KEYC_UP:
case 'k':
case KEYC_WHEELUP_PANE:

View File

@@ -141,7 +141,7 @@ static const char *options_table_allow_passthrough_list[] = {
"#{T:window-status-format}" \
"#[pop-default]" \
"#[norange default]" \
"#{?loop_last_flag,,#{window-status-separator}}" \
"#{?loop_last_flag,,#{E:window-status-separator}}" \
"," \
"#[range=window|#{window_index} list=focus " \
"#{?#{!=:#{E:window-status-current-style},default}," \
@@ -168,7 +168,7 @@ static const char *options_table_allow_passthrough_list[] = {
"#{T:window-status-current-format}" \
"#[pop-default]" \
"#[norange list=on default]" \
"#{?loop_last_flag,,#{window-status-separator}}" \
"#{?loop_last_flag,,#{E:window-status-separator}}" \
"}" \
"#[nolist align=right range=right #{E:status-right-style}]" \
"#[push-default]" \
@@ -723,13 +723,24 @@ 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",
.default_str = "bg=black,fg=yellow,fill=black",
.flags = OPTIONS_TABLE_IS_STYLE,
.separator = ",",
.text = "Style of the command prompt when in command mode, if "
"'mode-keys' is set to 'vi'."
},
{ .name = "message-format",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SESSION,
.default_str = "#[#{?#{command_prompt},"
"#{E:message-command-style},"
"#{E:message-style}}]"
"#{message}",
.text = "Format string for the prompt and message area. "
"The '#{message}' placeholder is replaced with the content."
},
{ .name = "message-line",
.type = OPTIONS_TABLE_CHOICE,
.scope = OPTIONS_TABLE_SESSION,
@@ -741,10 +752,13 @@ const struct options_table_entry options_table[] = {
{ .name = "message-style",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SESSION,
.default_str = "bg=yellow,fg=black",
.default_str = "bg=yellow,fg=black,fill=yellow",
.flags = OPTIONS_TABLE_IS_STYLE,
.separator = ",",
.text = "Style of messages and the command prompt."
.text = "Style of messages and the command prompt. "
"A 'fill' attribute controls background clearing and "
"a 'width' attribute (fixed or percentage) constrains "
"the prompt area width."
},
{ .name = "mouse",

27
popup.c
View File

@@ -847,16 +847,35 @@ popup_display(int flags, enum box_lines lines, struct cmdq_item *item, u_int px,
pd->psx = sx;
pd->psy = sy;
pd->job = job_run(shellcmd, argc, argv, env, s, cwd,
popup_job_update_cb, popup_job_complete_cb, NULL, pd,
JOB_NOWAIT|JOB_PTY|JOB_KEEPWRITE|JOB_DEFAULTSHELL, jx, jy);
pd->ictx = input_init(NULL, job_get_event(pd->job), &pd->palette, c);
if (flags & POPUP_NOJOB)
pd->ictx = input_init(NULL, NULL, &pd->palette, NULL);
else {
pd->job = job_run(shellcmd, argc, argv, env, s, cwd,
popup_job_update_cb, popup_job_complete_cb, NULL, pd,
JOB_NOWAIT|JOB_PTY|JOB_KEEPWRITE|JOB_DEFAULTSHELL, jx, jy);
pd->ictx = input_init(NULL, job_get_event(pd->job),
&pd->palette, c);
}
server_client_set_overlay(c, 0, popup_check_cb, popup_mode_cb,
popup_draw_cb, popup_key_cb, popup_free_cb, popup_resize_cb, pd);
return (0);
}
void
popup_write(struct client *c, const char *data, size_t size)
{
struct popup_data *pd = c->overlay_data;
if (!popup_present(c))
return;
c->overlay_check = NULL;
c->overlay_data = NULL;
input_parse_screen(pd->ictx, &pd->s, popup_init_ctx_cb, pd, data, size);
c->overlay_check = popup_check_cb;
c->overlay_data = pd;
}
static void
popup_editor_free(struct popup_editor *pe)
{

155
status.c
View File

@@ -551,6 +551,71 @@ status_message_callback(__unused int fd, __unused short event, void *data)
status_message_clear(c);
}
/*
* Calculate prompt/message area geometry from the style's width and align
* directives: x offset and available width within the status line.
*/
static void
status_prompt_area(struct client *c, u_int *area_x, u_int *area_w)
{
struct session *s = c->session;
struct style *sy;
u_int w;
/* Get width from message-style's width directive. */
sy = options_string_to_style(s->options, "message-style", NULL);
if (sy != NULL && sy->width >= 0) {
if (sy->width_percentage)
w = (c->tty.sx * (u_int)sy->width) / 100;
else
w = (u_int)sy->width;
} else
w = c->tty.sx;
if (w == 0 || w > c->tty.sx)
w = c->tty.sx;
/* Get horizontal position from message-style's align directive. */
if (sy != NULL) {
switch (sy->align) {
case STYLE_ALIGN_CENTRE:
case STYLE_ALIGN_ABSOLUTE_CENTRE:
*area_x = (c->tty.sx - w) / 2;
break;
case STYLE_ALIGN_RIGHT:
*area_x = c->tty.sx - w;
break;
default:
*area_x = 0;
break;
}
} else
*area_x = 0;
*area_w = w;
}
/* Escape # characters in a string so format_draw treats them as literal. */
static char *
status_prompt_escape(const char *s)
{
const char *cp;
char *out, *p;
size_t n = 0;
for (cp = s; *cp != '\0'; cp++) {
if (*cp == '#')
n++;
}
p = out = xmalloc(strlen(s) + n + 1);
for (cp = s; *cp != '\0'; cp++) {
if (*cp == '#')
*p++ = '#';
*p++ = *cp;
}
*p = '\0';
return (out);
}
/* Draw client message on status line of present else on last line. */
int
status_message_redraw(struct client *c)
@@ -559,10 +624,12 @@ status_message_redraw(struct client *c)
struct screen_write_ctx ctx;
struct session *s = c->session;
struct screen old_screen;
size_t len;
u_int lines, offset, messageline;
u_int lines, messageline;
u_int ax, aw;
struct grid_cell gc;
struct format_tree *ft;
const char *msgfmt;
char *expanded, *msg;
if (c->tty.sx == 0 || c->tty.sy == 0)
return (0);
@@ -577,26 +644,36 @@ status_message_redraw(struct client *c)
if (messageline > lines - 1)
messageline = lines - 1;
len = screen_write_strlen("%s", c->message_string);
if (len > c->tty.sx)
len = c->tty.sx;
status_prompt_area(c, &ax, &aw);
ft = format_create_defaults(NULL, c, NULL, NULL, NULL);
style_apply(&gc, s->options, "message-style", ft);
memcpy(&gc, &grid_default_cell, sizeof gc);
/*
* Set #{message} in the format tree. If styles should be ignored in
* the message content, escape # characters so format_draw treats them
* as literal text.
*/
if (c->message_ignore_styles) {
msg = status_prompt_escape(c->message_string);
format_add(ft, "message", "%s", msg);
free(msg);
} else
format_add(ft, "message", "%s", c->message_string);
format_add(ft, "command_prompt", "%d", 0);
msgfmt = options_get_string(s->options, "message-format");
expanded = format_expand_time(ft, msgfmt);
format_free(ft);
screen_write_start(&ctx, sl->active);
screen_write_fast_copy(&ctx, &sl->screen, 0, 0, c->tty.sx, lines);
screen_write_cursormove(&ctx, 0, messageline, 0);
for (offset = 0; offset < c->tty.sx; offset++)
screen_write_putc(&ctx, &gc, ' ');
screen_write_cursormove(&ctx, 0, messageline, 0);
if (c->message_ignore_styles)
screen_write_nputs(&ctx, len, &gc, "%s", c->message_string);
else
format_draw(&ctx, &gc, c->tty.sx, c->message_string, NULL, 0);
screen_write_cursormove(&ctx, ax, messageline, 0);
format_draw(&ctx, &gc, aw, expanded, NULL, 0);
screen_write_stop(&ctx);
free(expanded);
if (grid_compare(sl->active->grid, old_screen.grid) == 0) {
screen_free(&old_screen);
return (0);
@@ -789,9 +866,10 @@ status_prompt_redraw(struct client *c)
struct screen old_screen;
u_int i, lines, offset, left, start, width, n;
u_int pcursor, pwidth, promptline;
u_int ax, aw;
struct grid_cell gc;
struct format_tree *ft = c->prompt_formats;
char *prompt, *tmp;
const char *msgfmt;
char *expanded, *prompt, *tmp;
if (c->tty.sx == 0 || c->tty.sy == 0)
return (0);
@@ -816,29 +894,40 @@ status_prompt_redraw(struct client *c)
promptline = lines - 1;
if (c->prompt_mode == PROMPT_COMMAND)
style_apply(&gc, s->options, "message-command-style", ft);
style_apply(&gc, s->options, "message-command-style", NULL);
else
style_apply(&gc, s->options, "message-style", ft);
style_apply(&gc, s->options, "message-style", NULL);
status_prompt_area(c, &ax, &aw);
tmp = utf8_tocstr(c->prompt_buffer);
format_add(c->prompt_formats, "prompt-input", "%s", tmp);
prompt = format_expand_time(c->prompt_formats, c->prompt_string);
free (tmp);
free(tmp);
/*
* Set #{message} to the prompt string and expand message-format.
* format_draw handles fill, alignment, and decorations in one call.
*/
format_add(c->prompt_formats, "message", "%s", prompt);
format_add(c->prompt_formats, "command_prompt", "%d",
c->prompt_mode == PROMPT_COMMAND);
msgfmt = options_get_string(s->options, "message-format");
expanded = format_expand_time(c->prompt_formats, msgfmt);
start = format_width(prompt);
if (start > c->tty.sx)
start = c->tty.sx;
if (start > aw)
start = aw;
screen_write_start(&ctx, sl->active);
screen_write_fast_copy(&ctx, &sl->screen, 0, 0, c->tty.sx, lines);
screen_write_cursormove(&ctx, 0, promptline, 0);
for (offset = 0; offset < c->tty.sx; offset++)
screen_write_putc(&ctx, &gc, ' ');
screen_write_cursormove(&ctx, 0, promptline, 0);
format_draw(&ctx, &gc, start, prompt, NULL, 0);
screen_write_cursormove(&ctx, start, promptline, 0);
screen_write_cursormove(&ctx, ax, promptline, 0);
format_draw(&ctx, &gc, aw, expanded, NULL, 0);
screen_write_cursormove(&ctx, ax + start, promptline, 0);
left = c->tty.sx - start;
free(expanded);
left = aw - start;
if (left == 0)
goto finished;
@@ -857,7 +946,7 @@ status_prompt_redraw(struct client *c)
offset = 0;
if (pwidth > left)
pwidth = left;
c->prompt_cursor = start + pcursor - offset;
c->prompt_cursor = ax + start + pcursor - offset;
width = 0;
for (i = 0; c->prompt_buffer[i].size != 0; i++) {
@@ -1831,7 +1920,7 @@ status_prompt_complete_list_menu(struct client *c, char **list, u_int size,
struct menu_item item;
struct status_prompt_menu *spm;
u_int lines = status_line_size(c), height, i;
u_int py;
u_int py, ax, aw;
if (size <= 1)
return (0);
@@ -1859,11 +1948,13 @@ status_prompt_complete_list_menu(struct client *c, char **list, u_int size,
menu_add_item(menu, &item, NULL, c, NULL);
}
status_prompt_area(c, &ax, &aw);
if (options_get_number(c->session->options, "status-position") == 0)
py = lines;
else
py = c->tty.sy - 3 - height;
offset += utf8_cstrwidth(c->prompt_string);
offset += ax;
if (offset > 2)
offset -= 2;
else
@@ -1890,7 +1981,7 @@ status_prompt_complete_window_menu(struct client *c, struct session *s,
struct winlink *wl;
char **list = NULL, *tmp;
u_int lines = status_line_size(c), height;
u_int py, size = 0, i;
u_int py, size = 0, i, ax, aw;
if (c->tty.sy - lines < 3)
return (NULL);
@@ -1955,11 +2046,13 @@ status_prompt_complete_window_menu(struct client *c, struct session *s,
spm->size = size;
spm->list = list;
status_prompt_area(c, &ax, &aw);
if (options_get_number(c->session->options, "status-position") == 0)
py = lines;
else
py = c->tty.sy - 3 - height;
offset += utf8_cstrwidth(c->prompt_string);
offset += ax;
if (offset > 2)
offset -= 2;
else

30
style.c
View File

@@ -39,7 +39,7 @@ static struct style style_default = {
STYLE_RANGE_NONE, 0, "",
STYLE_WIDTH_DEFAULT, STYLE_PAD_DEFAULT,
STYLE_WIDTH_DEFAULT, 0, STYLE_PAD_DEFAULT,
STYLE_DEFAULT_BASE
};
@@ -226,10 +226,20 @@ style_parse(struct style *sy, const struct grid_cell *base, const char *in)
sy->gc.attr &= ~value;
}
} else if (end > 6 && strncasecmp(tmp, "width=", 6) == 0) {
n = strtonum(tmp + 6, 0, UINT_MAX, &errstr);
if (errstr != NULL)
goto error;
sy->width = (int)n;
if (end > 7 && tmp[end - 1] == '%') {
tmp[end - 1] = '\0';
n = strtonum(tmp + 6, 0, 100, &errstr);
if (errstr != NULL)
goto error;
sy->width = (int)n;
sy->width_percentage = 1;
} else {
n = strtonum(tmp + 6, 0, UINT_MAX, &errstr);
if (errstr != NULL)
goto error;
sy->width = (int)n;
sy->width_percentage = 0;
}
} else if (end > 4 && strncasecmp(tmp, "pad=", 4) == 0) {
n = strtonum(tmp + 4, 0, UINT_MAX, &errstr);
if (errstr != NULL)
@@ -343,13 +353,17 @@ style_tostring(struct style *sy)
comma = ",";
}
if (gc->attr != 0) {
xsnprintf(s + off, sizeof s - off, "%s%s", comma,
off += xsnprintf(s + off, sizeof s - off, "%s%s", comma,
attributes_tostring(gc->attr));
comma = ",";
}
if (sy->width >= 0) {
xsnprintf(s + off, sizeof s - off, "%swidth=%u", comma,
sy->width);
if (sy->width_percentage)
off += xsnprintf(s + off, sizeof s - off,
"%swidth=%u%%", comma, sy->width);
else
off += xsnprintf(s + off, sizeof s - off,
"%swidth=%u", comma, sy->width);
comma = ",";
}
if (sy->pad >= 0) {

70
tmux.1
View File

@@ -2700,7 +2700,7 @@ zooms the pane.
.Fl y
disables any confirmation prompts.
The following keys may be used in client mode:
.Bl -column "Key" "Function" -offset indent
.Bl -column "KeyXXXXXX" "Function" -offset indent
.It Sy "Key" Ta Sy "Function"
.It Li "Enter" Ta "Choose selected client"
.It Li "Up" Ta "Select previous client"
@@ -2721,6 +2721,7 @@ The following keys may be used in client mode:
.It Li "O" Ta "Change sort order"
.It Li "r" Ta "Reverse sort order"
.It Li "v" Ta "Toggle preview"
.It Li "F1 or C-h" Ta "Display help"
.It Li "q" Ta "Exit mode"
.El
.Pp
@@ -2779,7 +2780,7 @@ zooms the pane.
.Fl y
disables any confirmation prompts.
The following keys may be used in tree mode:
.Bl -column "Key" "Function" -offset indent
.Bl -column "KeyXXXXXX" "Function" -offset indent
.It Sy "Key" Ta Sy "Function"
.It Li "Enter" Ta "Choose selected item"
.It Li "Up" Ta "Select previous item"
@@ -2808,6 +2809,7 @@ The following keys may be used in tree mode:
.It Li "O" Ta "Change sort order"
.It Li "r" Ta "Reverse sort order"
.It Li "v" Ta "Toggle preview"
.It Li "F1 or C-h" Ta "Display help"
.It Li "q" Ta "Exit mode"
.El
.Pp
@@ -2859,7 +2861,7 @@ Option values in the list are shown for the active pane in the current window.
.Fl Z
zooms the pane.
The following keys may be used in customize mode:
.Bl -column "Key" "Function" -offset indent
.Bl -column "KeyXXXXXX" "Function" -offset indent
.It Sy "Key" Ta Sy "Function"
.It Li "Enter" Ta "Set pane, window, session or global option value"
.It Li "Up" Ta "Select previous item"
@@ -2883,6 +2885,7 @@ The following keys may be used in customize mode:
.It Li "C-t" Ta "Tag all items"
.It Li "f" Ta "Enter a format to filter items"
.It Li "v" Ta "Toggle option information"
.It Li "F1 or C-h" Ta "Display help"
.It Li "q" Ta "Exit mode"
.El
.Pp
@@ -4747,6 +4750,23 @@ For how to specify
see the
.Sx STYLES
section.
.It Ic message-format Ar string
Set the format string for the prompt and message area.
The special placeholder
.Ql #{message}
expands to the interactive prompt or message text and
.Ql #{command_prompt}
is set to 1 when the prompt is in command mode (vi).
Style directives like
.Ic fill ,
.Ic align ,
and
.Ic width
may be used in the format string.
The default uses a conditional to select between
.Ic message-style
and
.Ic message-command-style .
.It Xo Ic message-line
.Op Ic 0 | 1 | 2 | 3 | 4
.Xc
@@ -4754,6 +4774,23 @@ Set line on which status line messages and the command prompt are shown.
.It Ic message-style Ar style
Set status line message style.
This is used for messages and for the command prompt.
The message is drawn on top of the existing status line.
A
.Ic width
attribute (a fixed number of columns or a percentage such as
.Ql 50% )
constrains the prompt area width and an
.Ic align
attribute
.Pq Ic left , centre , right
sets its horizontal position.
When the width is less than the full terminal width, the normal status
bar content remains visible around the prompt area.
The
.Ic fill
attribute is used by the default
.Ic message-format
to clear the background.
For how to specify
.Ar style ,
see the
@@ -6127,6 +6164,21 @@ For example, to get a list of windows formatted like the status line:
#{W:#{E:window-status-format} ,#{E:window-status-current-format} }
.Ed
.Pp
Within the
.Ql W:\&
loop, user options
.Po
.Ql @name
.Pc
from neighboring windows are available with a
.Ql next_
or
.Ql prev_
prefix, for example a user option
.Ql @color
on the next window is available as
.Ql next_@color .
.Pp
.Ql N:\&
checks if a window (without any suffix or with the
.Ql w
@@ -6295,6 +6347,8 @@ The following variables are available, where appropriate:
.It Li "mouse_x" Ta "" Ta "Mouse X position, if any"
.It Li "mouse_y" Ta "" Ta "Mouse Y position, if any"
.It Li "next_session_id" Ta "" Ta "Unique session ID for next new session"
.It Li "next_window_active" Ta "" Ta "1 if next window in W: loop is active"
.It Li "next_window_index" Ta "" Ta "Index of next window in W: loop"
.It Li "origin_flag" Ta "" Ta "Pane origin flag"
.It Li "pane_active" Ta "" Ta "1 if active pane"
.It Li "pane_at_bottom" Ta "" Ta "1 if pane is at the bottom of window"
@@ -6339,6 +6393,8 @@ The following variables are available, where appropriate:
.It Li "pane_unseen_changes" Ta "" Ta "1 if there were changes in pane while in mode"
.It Li "pane_width" Ta "" Ta "Width of pane"
.It Li "pid" Ta "" Ta "Server PID"
.It Li "prev_window_active" Ta "" Ta "1 if previous window in W: loop is active"
.It Li "prev_window_index" Ta "" Ta "Index of previous window in W: loop"
.It Li "rectangle_toggle" Ta "" Ta "1 if rectangle selection is activated"
.It Li "scroll_position" Ta "" Ta "Scroll position in copy mode"
.It Li "scroll_region_lower" Ta "" Ta "Bottom of scroll region in pane"
@@ -6506,6 +6562,11 @@ is the terminal alternate character set.
Align text to the left, centre or right of the available space if appropriate.
.It Ic fill=colour
Fill the available space with a background colour if appropriate.
.It Ic width=N
Set the width of the styled area.
.Ar N
may be a column count or a percentage (for example
.Ql 50% ) .
.It Xo Ic list=on ,
.Ic list=focus ,
.Ic list=left-marker ,
@@ -7336,7 +7397,7 @@ zooms the pane.
.Fl y
disables any confirmation prompts.
The following keys may be used in buffer mode:
.Bl -column "Key" "Function" -offset indent
.Bl -column "KeyXXXXXX" "Function" -offset indent
.It Sy "Key" Ta Sy "Function"
.It Li "Enter" Ta "Paste selected buffer"
.It Li "Up" Ta "Select previous buffer"
@@ -7356,6 +7417,7 @@ The following keys may be used in buffer mode:
.It Li "O" Ta "Change sort order"
.It Li "r" Ta "Reverse sort order"
.It Li "v" Ta "Toggle preview"
.It Li "F1 or C-h" Ta "Display help"
.It Li "q" Ta "Exit mode"
.El
.Pp

10
tmux.h
View File

@@ -920,6 +920,7 @@ struct style {
char range_string[16];
int width;
int width_percentage;
int pad;
enum style_default_type default_type;
@@ -3084,9 +3085,9 @@ void input_free(struct input_ctx *);
void input_reset(struct input_ctx *, int);
struct evbuffer *input_pending(struct input_ctx *);
void input_parse_pane(struct window_pane *);
void input_parse_buffer(struct window_pane *, u_char *, size_t);
void input_parse_buffer(struct window_pane *, const u_char *, size_t);
void input_parse_screen(struct input_ctx *, struct screen *,
screen_write_init_ctx_cb, void *, u_char *, size_t);
screen_write_init_ctx_cb, void *, const u_char *, size_t);
void input_reply_clipboard(struct bufferevent *, const char *, size_t,
const char *, char);
void input_set_buffer_size(size_t);
@@ -3484,6 +3485,7 @@ typedef key_code (*mode_tree_key_cb)(void *, void *, u_int);
typedef int (*mode_tree_swap_cb)(void *, void *, struct sort_criteria *);
typedef void (*mode_tree_sort_cb)(struct sort_criteria *);
typedef void (*mode_tree_each_cb)(void *, void *, struct client *, key_code);
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 *);
@@ -3498,7 +3500,7 @@ int mode_tree_down(struct mode_tree_data *, int);
struct mode_tree_data *mode_tree_start(struct window_pane *, struct args *,
mode_tree_build_cb, mode_tree_draw_cb, mode_tree_search_cb,
mode_tree_menu_cb, mode_tree_height_cb, mode_tree_key_cb,
mode_tree_swap_cb, mode_tree_sort_cb, void *,
mode_tree_swap_cb, mode_tree_sort_cb, mode_tree_help_cb, void *,
const struct menu_item *, struct screen **);
void mode_tree_zoom(struct mode_tree_data *, struct args *);
void mode_tree_build(struct mode_tree_data *);
@@ -3717,6 +3719,7 @@ int menu_key_cb(struct client *, void *, struct key_event *);
#define POPUP_CLOSEEXITZERO 0x2
#define POPUP_INTERNAL 0x4
#define POPUP_CLOSEANYKEY 0x8
#define POPUP_NOJOB 0x10
typedef void (*popup_close_cb)(int, void *);
typedef void (*popup_finish_edit_cb)(char *, size_t, void *);
int popup_display(int, enum box_lines, struct cmdq_item *, u_int,
@@ -3724,6 +3727,7 @@ int popup_display(int, enum box_lines, struct cmdq_item *, u_int,
char **, const char *, const char *, struct client *,
struct session *, const char *, const char *,
popup_close_cb, void *);
void popup_write(struct client *, const char *, size_t);
int popup_editor(struct client *, const char *, size_t,
popup_finish_edit_cb, void *);
int popup_present(struct client *);

View File

@@ -329,6 +329,25 @@ window_buffer_sort(struct sort_criteria *sort_crit)
sort_crit->order = sort_crit->order_seq[0];
}
static const char* window_buffer_help_lines[] = {
"\r\033[1m Enter \033[0m\016x\017 \033[0mPaste selected %1\n",
"\r\033[1m p \033[0m\016x\017 \033[0mPaste selected %1\n",
"\r\033[1m P \033[0m\016x\017 \033[0mPaste tagged %1s\n",
"\r\033[1m d \033[0m\016x\017 \033[0mDelete selected %1\n",
"\r\033[1m D \033[0m\016x\017 \033[0mDelete tagged %1s\n",
"\r\033[1m e \033[0m\016x\017 \033[0mOpen %1 in editor\n",
"\r\033[1m f \033[0m\016x\017 \033[0mEnter a filter\n",
NULL
};
static const char**
window_buffer_help(u_int *width, const char **item)
{
*width = 0;
*item = "buffer";
return (window_buffer_help_lines);
}
static struct screen *
window_buffer_init(struct window_mode_entry *wme, struct cmd_find_state *fs,
struct args *args)
@@ -356,8 +375,8 @@ window_buffer_init(struct window_mode_entry *wme, struct cmd_find_state *fs,
data->data = mode_tree_start(wp, args, window_buffer_build,
window_buffer_draw, window_buffer_search, window_buffer_menu, NULL,
window_buffer_get_key, NULL, window_buffer_sort, data,
window_buffer_menu_items, &s);
window_buffer_get_key, NULL, window_buffer_sort, window_buffer_help,
data, window_buffer_menu_items, &s);
mode_tree_zoom(data->data, args);
mode_tree_build(data->data);

View File

@@ -240,6 +240,26 @@ window_client_sort(struct sort_criteria *sort_crit)
sort_crit->order = sort_crit->order_seq[0];
}
static const char* window_client_help_lines[] = {
"\r\033[1m Enter \033[0m\016x\017 \033[0mChoose selected %1\n",
"\r\033[1m d \033[0m\016x\017 \033[0mDetach selected %1\n",
"\r\033[1m D \033[0m\016x\017 \033[0mDetach tagged %1s\n",
"\r\033[1m x \033[0m\016x\017 \033[0mDetach selected %1\n",
"\r\033[1m X \033[0m\016x\017 \033[0mDetach tagged %1s\n",
"\r\033[1m z \033[0m\016x\017 \033[0mSuspend selected %1\n",
"\r\033[1m Z \033[0m\016x\017 \033[0mSuspend tagged %1s\n",
"\r\033[1m f \033[0m\016x\017 \033[0mEnter a filter\n",
NULL
};
static const char**
window_client_help(u_int *width, const char **item)
{
*width = 0;
*item = "client";
return (window_client_help_lines);
}
static struct screen *
window_client_init(struct window_mode_entry *wme,
__unused struct cmd_find_state *fs, struct args *args)
@@ -266,8 +286,8 @@ window_client_init(struct window_mode_entry *wme,
data->data = mode_tree_start(wp, args, window_client_build,
window_client_draw, NULL, window_client_menu, NULL,
window_client_get_key, NULL, window_client_sort, data,
window_client_menu_items, &s);
window_client_get_key, NULL, window_client_sort,
window_client_help, data, window_client_menu_items, &s);
mode_tree_zoom(data->data, args);
mode_tree_build(data->data);

View File

@@ -868,6 +868,27 @@ window_customize_height(__unused void *modedata, __unused u_int height)
return (12);
}
static const char* window_customize_help_lines[] = {
"\r\033[1m Enter, s \033[0m\016x\017 \033[0mSet %1 value\n",
"\r\033[1m S \033[0m\016x\017 \033[0mSet global %1 value\n",
"\r\033[1m w \033[0m\016x\017 \033[0mSet window %1 value\n",
"\r\033[1m d \033[0m\016x\017 \033[0mSet to default value\n",
"\r\033[1m D \033[0m\016x\017 \033[0mSet tagged %1s to default value\n",
"\r\033[1m u \033[0m\016x\017 \033[0mUnset an %1\n",
"\r\033[1m U \033[0m\016x\017 \033[0mUnset tagged %1s\n",
"\r\033[1m f \033[0m\016x\017 \033[0mEnter a filter\n",
"\r\033[1m v \033[0m\016x\017 \033[0mToggle information\n",
NULL
};
static const char**
window_customize_help(u_int *width, const char **item)
{
*width = 52;
*item = "option";
return (window_customize_help_lines);
}
static struct screen *
window_customize_init(struct window_mode_entry *wme, struct cmd_find_state *fs,
struct args *args)
@@ -891,8 +912,8 @@ window_customize_init(struct window_mode_entry *wme, struct cmd_find_state *fs,
data->data = mode_tree_start(wp, args, window_customize_build,
window_customize_draw, NULL, window_customize_menu,
window_customize_height, NULL, NULL, NULL, data,
window_customize_menu_items, &s);
window_customize_height, NULL, NULL, NULL, window_customize_help,
data, window_customize_menu_items, &s);
mode_tree_zoom(data->data, args);
mode_tree_build(data->data);

View File

@@ -860,6 +860,30 @@ window_tree_sort(struct sort_criteria *sort_crit)
sort_crit->order = sort_crit->order_seq[0];
}
static const char* window_tree_help_lines[] = {
"\r\033[1m Enter \033[0m\016x\017 \033[0mChoose selected item\n",
"\r\033[1m S-Up \033[0m\016x\017 \033[0mSwap current and previous window\n",
"\r\033[1m S-Down \033[0m\016x\017 \033[0mSwap current and next window\n",
"\r\033[1m x \033[0m\016x\017 \033[0mKill selected item\n",
"\r\033[1m X \033[0m\016x\017 \033[0mKill tagged items\n",
"\r\033[1m < \033[0m\016x\017 \033[0mScroll previews left\n",
"\r\033[1m > \033[0m\016x\017 \033[0mScroll previews right\n",
"\r\033[1m m \033[0m\016x\017 \033[0mSet the marked pane\n",
"\r\033[1m M \033[0m\016x\017 \033[0mClear the marked pane\n",
"\r\033[1m : \033[0m\016x\017 \033[0mRun a command for each tagged item\n",
"\r\033[1m f \033[0m\016x\017 \033[0mEnter a format\n",
"\r\033[1m H \033[0m\016x\017 \033[0mJump to the starting pane\n",
NULL
};
static const char**
window_tree_help(u_int *width, const char **item)
{
*width = 51;
*item = "item";
return (window_tree_help_lines);
}
static struct screen *
window_tree_init(struct window_mode_entry *wme, struct cmd_find_state *fs,
struct args *args)
@@ -898,8 +922,8 @@ window_tree_init(struct window_mode_entry *wme, struct cmd_find_state *fs,
data->data = mode_tree_start(wp, args, window_tree_build,
window_tree_draw, window_tree_search, window_tree_menu, NULL,
window_tree_get_key, window_tree_swap, window_tree_sort, data,
window_tree_menu_items, &s);
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_build(data->data);