Merge branch 'obsd-master'

This commit is contained in:
Thomas Adam
2026-01-23 10:50:55 +00:00
11 changed files with 270 additions and 48 deletions

View File

@@ -82,7 +82,7 @@ grid_view_clear_history(struct grid *gd, u_int bg)
/* Scroll the lines into the history. */ /* Scroll the lines into the history. */
for (yy = 0; yy < last; yy++) { for (yy = 0; yy < last; yy++) {
grid_collect_history(gd); grid_collect_history(gd, 0);
grid_scroll_history(gd, bg); grid_scroll_history(gd, bg);
} }
if (last < gd->sy) if (last < gd->sy)
@@ -107,7 +107,7 @@ grid_view_scroll_region_up(struct grid *gd, u_int rupper, u_int rlower,
u_int bg) u_int bg)
{ {
if (gd->flags & GRID_HISTORY) { if (gd->flags & GRID_HISTORY) {
grid_collect_history(gd); grid_collect_history(gd, 0);
if (rupper == 0 && rlower == gd->sy - 1) if (rupper == 0 && rlower == gd->sy - 1)
grid_scroll_history(gd, bg); grid_scroll_history(gd, bg);
else { else {

5
grid.c
View File

@@ -375,13 +375,16 @@ grid_trim_history(struct grid *gd, u_int ny)
* and shift up. * and shift up.
*/ */
void void
grid_collect_history(struct grid *gd) grid_collect_history(struct grid *gd, int all)
{ {
u_int ny; u_int ny;
if (gd->hsize == 0 || gd->hsize < gd->hlimit) if (gd->hsize == 0 || gd->hsize < gd->hlimit)
return; return;
if (all)
ny = gd->hsize - gd->hlimit;
else
ny = gd->hlimit / 10; ny = gd->hlimit / 10;
if (ny < 1) if (ny < 1)
ny = 1; ny = 1;

101
menu.c
View File

@@ -27,9 +27,13 @@ struct menu_data {
struct cmdq_item *item; struct cmdq_item *item;
int flags; int flags;
struct grid_cell style; char *style;
struct grid_cell border_style; char *border_style;
struct grid_cell selected_style; char *selected_style;
struct grid_cell style_gc;
struct grid_cell border_style_gc;
struct grid_cell selected_style_gc;
enum box_lines border_lines; enum box_lines border_lines;
struct cmd_find_state fs; struct cmd_find_state fs;
@@ -192,6 +196,60 @@ menu_check_cb(__unused struct client *c, void *data, u_int px, u_int py,
menu->count + 2, px, py, nx, r); menu->count + 2, px, py, nx, r);
} }
static void
menu_reapply_styles(struct menu_data *md, struct client *c)
{
struct session *s = c->session;
struct options *o;
struct format_tree *ft;
struct style sytmp;
if (s == NULL)
return;
o = s->curw->window->options;
ft = format_create_defaults(NULL, c, s, s->curw, NULL);
/* Reapply menu style from options. */
memcpy(&md->style_gc, &grid_default_cell, sizeof md->style_gc);
style_apply(&md->style_gc, o, "menu-style", ft);
if (md->style != NULL) {
style_set(&sytmp, &grid_default_cell);
if (style_parse(&sytmp, &md->style_gc, md->style) == 0) {
md->style_gc.fg = sytmp.gc.fg;
md->style_gc.bg = sytmp.gc.bg;
}
}
/* Reapply selected style from options. */
memcpy(&md->selected_style_gc, &grid_default_cell,
sizeof md->selected_style_gc);
style_apply(&md->selected_style_gc, o, "menu-selected-style", ft);
if (md->selected_style != NULL) {
style_set(&sytmp, &grid_default_cell);
if (style_parse(&sytmp, &md->selected_style_gc,
md->selected_style) == 0) {
md->selected_style_gc.fg = sytmp.gc.fg;
md->selected_style_gc.bg = sytmp.gc.bg;
}
}
/* Reapply border style from options. */
memcpy(&md->border_style_gc, &grid_default_cell,
sizeof md->border_style_gc);
style_apply(&md->border_style_gc, o, "menu-border-style", ft);
if (md->border_style != NULL) {
style_set(&sytmp, &grid_default_cell);
if (style_parse(&sytmp, &md->border_style_gc,
md->border_style) == 0) {
md->border_style_gc.fg = sytmp.gc.fg;
md->border_style_gc.bg = sytmp.gc.bg;
}
}
format_free(ft);
}
void void
menu_draw_cb(struct client *c, void *data, menu_draw_cb(struct client *c, void *data,
__unused struct screen_redraw_ctx *rctx) __unused struct screen_redraw_ctx *rctx)
@@ -203,16 +261,18 @@ menu_draw_cb(struct client *c, void *data,
struct screen_write_ctx ctx; struct screen_write_ctx ctx;
u_int i, px = md->px, py = md->py; u_int i, px = md->px, py = md->py;
menu_reapply_styles(md, c);
screen_write_start(&ctx, s); screen_write_start(&ctx, s);
screen_write_clearscreen(&ctx, 8); screen_write_clearscreen(&ctx, 8);
if (md->border_lines != BOX_LINES_NONE) { if (md->border_lines != BOX_LINES_NONE) {
screen_write_box(&ctx, menu->width + 4, menu->count + 2, screen_write_box(&ctx, menu->width + 4, menu->count + 2,
md->border_lines, &md->border_style, menu->title); md->border_lines, &md->border_style_gc, menu->title);
} }
screen_write_menu(&ctx, menu, md->choice, md->border_lines, screen_write_menu(&ctx, menu, md->choice, md->border_lines,
&md->style, &md->border_style, &md->selected_style); &md->style_gc, &md->border_style_gc, &md->selected_style_gc);
screen_write_stop(&ctx); screen_write_stop(&ctx);
for (i = 0; i < screen_size_y(&md->s); i++) { for (i = 0; i < screen_size_y(&md->s); i++) {
@@ -234,6 +294,9 @@ menu_free_cb(__unused struct client *c, void *data)
screen_free(&md->s); screen_free(&md->s);
menu_free(md->menu); menu_free(md->menu);
free(md->style);
free(md->selected_style);
free(md->border_style);
free(md); free(md);
} }
@@ -470,24 +533,6 @@ menu_resize_cb(struct client *c, void *data)
md->py = ny; md->py = ny;
} }
static void
menu_set_style(struct client *c, struct grid_cell *gc, const char *style,
const char *option)
{
struct style sytmp;
struct options *o = c->session->curw->window->options;
memcpy(gc, &grid_default_cell, sizeof *gc);
style_apply(gc, o, option, NULL);
if (style != NULL) {
style_set(&sytmp, &grid_default_cell);
if (style_parse(&sytmp, gc, style) == 0) {
gc->fg = sytmp.gc.fg;
gc->bg = sytmp.gc.bg;
}
}
}
struct menu_data * struct menu_data *
menu_prepare(struct menu *menu, int flags, int starting_choice, menu_prepare(struct menu *menu, int flags, int starting_choice,
struct cmdq_item *item, u_int px, u_int py, struct client *c, struct cmdq_item *item, u_int px, u_int py, struct client *c,
@@ -515,10 +560,12 @@ menu_prepare(struct menu *menu, int flags, int starting_choice,
md->flags = flags; md->flags = flags;
md->border_lines = lines; md->border_lines = lines;
menu_set_style(c, &md->style, style, "menu-style"); if (style != NULL)
menu_set_style(c, &md->selected_style, selected_style, md->style = xstrdup(style);
"menu-selected-style"); if (selected_style != NULL)
menu_set_style(c, &md->border_style, border_style, "menu-border-style"); md->selected_style = xstrdup(selected_style);
if (border_style != NULL)
md->border_style = xstrdup(border_style);
if (fs != NULL) if (fs != NULL)
cmd_find_copy_state(&md->fs, fs); cmd_find_copy_state(&md->fs, fs);

View File

@@ -1226,6 +1226,10 @@ options_push_changes(const char *name)
RB_FOREACH(wp, window_pane_tree, &all_window_panes) RB_FOREACH(wp, window_pane_tree, &all_window_panes)
wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED); wp->flags |= (PANE_STYLECHANGED|PANE_THEMECHANGED);
} }
if (*name == '@') {
RB_FOREACH(wp, window_pane_tree, &all_window_panes)
wp->flags |= PANE_STYLECHANGED;
}
if (strcmp(name, "pane-colours") == 0) { if (strcmp(name, "pane-colours") == 0) {
RB_FOREACH(wp, window_pane_tree, &all_window_panes) RB_FOREACH(wp, window_pane_tree, &all_window_panes)
colour_palette_from_option(&wp->palette, wp->options); colour_palette_from_option(&wp->palette, wp->options);
@@ -1248,6 +1252,10 @@ options_push_changes(const char *name)
utf8_update_width_cache(); utf8_update_width_cache();
if (strcmp(name, "input-buffer-size") == 0) if (strcmp(name, "input-buffer-size") == 0)
input_set_buffer_size(options_get_number(global_options, name)); input_set_buffer_size(options_get_number(global_options, name));
if (strcmp(name, "history-limit") == 0) {
RB_FOREACH(s, sessions, &sessions)
session_update_history(s);
}
RB_FOREACH(s, sessions, &sessions) RB_FOREACH(s, sessions, &sessions)
status_update_cache(s); status_update_cache(s);

61
popup.c
View File

@@ -32,6 +32,8 @@ struct popup_data {
int flags; int flags;
char *title; char *title;
char *style;
char *border_style;
struct grid_cell border_cell; struct grid_cell border_cell;
enum box_lines border_lines; enum box_lines border_lines;
@@ -98,6 +100,49 @@ static const struct menu_item popup_internal_menu_items[] = {
{ NULL, KEYC_NONE, NULL } { NULL, KEYC_NONE, NULL }
}; };
static void
popup_reapply_styles(struct popup_data *pd)
{
struct client *c = pd->c;
struct session *s = c->session;
struct options *o;
struct format_tree *ft;
struct style sytmp;
if (s == NULL)
return;
o = s->curw->window->options;
ft = format_create_defaults(NULL, c, s, s->curw, NULL);
/* Reapply popup style from options. */
memcpy(&pd->defaults, &grid_default_cell, sizeof pd->defaults);
style_apply(&pd->defaults, o, "popup-style", ft);
if (pd->style != NULL) {
style_set(&sytmp, &grid_default_cell);
if (style_parse(&sytmp, &pd->defaults, pd->style) == 0) {
pd->defaults.fg = sytmp.gc.fg;
pd->defaults.bg = sytmp.gc.bg;
}
}
pd->defaults.attr = 0;
/* Reapply border style from options. */
memcpy(&pd->border_cell, &grid_default_cell, sizeof pd->border_cell);
style_apply(&pd->border_cell, o, "popup-border-style", ft);
if (pd->border_style != NULL) {
style_set(&sytmp, &grid_default_cell);
if (style_parse(&sytmp, &pd->border_cell,
pd->border_style) == 0) {
pd->border_cell.fg = sytmp.gc.fg;
pd->border_cell.bg = sytmp.gc.bg;
}
}
pd->border_cell.attr = 0;
format_free(ft);
}
static void static void
popup_redraw_cb(const struct tty_ctx *ttyctx) popup_redraw_cb(const struct tty_ctx *ttyctx)
{ {
@@ -219,6 +264,8 @@ popup_draw_cb(struct client *c, void *data, struct screen_redraw_ctx *rctx)
struct colour_palette *palette = &pd->palette; struct colour_palette *palette = &pd->palette;
struct grid_cell defaults; struct grid_cell defaults;
popup_reapply_styles(pd);
screen_init(&s, pd->sx, pd->sy, 0); screen_init(&s, pd->sx, pd->sy, 0);
screen_write_start(&ctx, &s); screen_write_start(&ctx, &s);
screen_write_clearscreen(&ctx, 8); screen_write_clearscreen(&ctx, 8);
@@ -290,6 +337,8 @@ popup_free_cb(struct client *c, void *data)
colour_palette_free(&pd->palette); colour_palette_free(&pd->palette);
free(pd->title); free(pd->title);
free(pd->style);
free(pd->border_style);
free(pd); free(pd);
} }
@@ -658,6 +707,8 @@ popup_modify(struct client *c, const char *title, const char *style,
pd->title = xstrdup(title); pd->title = xstrdup(title);
} }
if (border_style != NULL) { if (border_style != NULL) {
free(pd->border_style);
pd->border_style = xstrdup(border_style);
style_set(&sytmp, &pd->border_cell); style_set(&sytmp, &pd->border_cell);
if (style_parse(&sytmp, &pd->border_cell, border_style) == 0) { if (style_parse(&sytmp, &pd->border_cell, border_style) == 0) {
pd->border_cell.fg = sytmp.gc.fg; pd->border_cell.fg = sytmp.gc.fg;
@@ -665,6 +716,8 @@ popup_modify(struct client *c, const char *title, const char *style,
} }
} }
if (style != NULL) { if (style != NULL) {
free(pd->style);
pd->style = xstrdup(style);
style_set(&sytmp, &pd->defaults); style_set(&sytmp, &pd->defaults);
if (style_parse(&sytmp, &pd->defaults, style) == 0) { if (style_parse(&sytmp, &pd->defaults, style) == 0) {
pd->defaults.fg = sytmp.gc.fg; pd->defaults.fg = sytmp.gc.fg;
@@ -675,7 +728,8 @@ popup_modify(struct client *c, const char *title, const char *style,
if (lines == BOX_LINES_NONE && pd->border_lines != lines) { if (lines == BOX_LINES_NONE && pd->border_lines != lines) {
screen_resize(&pd->s, pd->sx, pd->sy, 1); screen_resize(&pd->s, pd->sx, pd->sy, 1);
job_resize(pd->job, pd->sx, pd->sy); job_resize(pd->job, pd->sx, pd->sy);
} else if (pd->border_lines == BOX_LINES_NONE && pd->border_lines != lines) { } else if (pd->border_lines == BOX_LINES_NONE &&
pd->border_lines != lines) {
screen_resize(&pd->s, pd->sx - 2, pd->sy - 2, 1); screen_resize(&pd->s, pd->sx - 2, pd->sy - 2, 1);
job_resize(pd->job, pd->sx - 2, pd->sy - 2); job_resize(pd->job, pd->sx - 2, pd->sy - 2);
} }
@@ -725,8 +779,13 @@ popup_display(int flags, enum box_lines lines, struct cmdq_item *item, u_int px,
pd = xcalloc(1, sizeof *pd); pd = xcalloc(1, sizeof *pd);
pd->item = item; pd->item = item;
pd->flags = flags; pd->flags = flags;
if (title != NULL) if (title != NULL)
pd->title = xstrdup(title); pd->title = xstrdup(title);
if (style != NULL)
pd->style = xstrdup(style);
if (border_style != NULL)
pd->border_style = xstrdup(border_style);
pd->c = c; pd->c = c;
pd->c->references++; pd->c->references++;

View File

@@ -770,3 +770,74 @@ screen_mode_to_string(int mode)
tmp[strlen(tmp) - 1] = '\0'; tmp[strlen(tmp) - 1] = '\0';
return (tmp); return (tmp);
} }
const char *
screen_print(struct screen *s)
{
static char *buf;
static size_t len = 16384;
const char *acs;
u_int x, y;
int n;
size_t last = 0;
struct utf8_data ud;
struct grid_line *gl;
struct grid_cell_entry *gce;
if (buf == NULL)
buf = xmalloc(len);
for (y = 0; y < screen_hsize(s) + s->grid->sy; y++) {
n = snprintf(buf + last, len - last, "%.4d \"", y);
if (n <= 0 || (u_int)n >= len - last)
goto out;
last += n;
gl = &s->grid->linedata[y];
for (x = 0; x < gl->cellused; x++) {
gce = &gl->celldata[x];
if (gce->flags & GRID_FLAG_PADDING)
continue;
if (~gce->flags & GRID_FLAG_EXTENDED) {
if (last + 2 >= len)
goto out;
buf[last++] = gce->data.data;
} else if (gce->flags & GRID_FLAG_TAB) {
if (last + 2 >= len)
goto out;
buf[last++] = '\t';
} else if (gce->flags & GRID_ATTR_CHARSET) {
acs = tty_acs_get(NULL, gce->data.data);
if (acs != NULL)
n = strlen(acs);
else {
acs = &gce->data.data;
n = 1;
}
if (last + n + 1 >= len)
goto out;
memcpy(buf + last, acs, n);
last += n;
} else {
utf8_to_data(gl->extddata[gce->offset].data,
&ud);
if (ud.size > 0) {
if (last + ud.size + 1 >= len)
goto out;
memcpy(buf + last, ud.data, ud.size);
last += ud.size;
}
}
}
if (last + 3 >= len)
goto out;
buf[last++] = '"';
buf[last++] = '\n';
}
out:
buf[last] = '\0';
return (buf);
}

View File

@@ -403,13 +403,13 @@ server_client_set_session(struct client *c, struct session *s)
if (old != NULL && old->curw != NULL) if (old != NULL && old->curw != NULL)
window_update_focus(old->curw->window); window_update_focus(old->curw->window);
if (s != NULL) { if (s != NULL) {
s->curw->window->latest = c;
recalculate_sizes(); recalculate_sizes();
window_update_focus(s->curw->window); window_update_focus(s->curw->window);
session_update_activity(s, NULL); session_update_activity(s, NULL);
session_theme_changed(s); session_theme_changed(s);
gettimeofday(&s->last_attached_time, NULL); gettimeofday(&s->last_attached_time, NULL);
s->curw->flags &= ~WINLINK_ALERTFLAGS; s->curw->flags &= ~WINLINK_ALERTFLAGS;
s->curw->window->latest = c;
alerts_check_session(s); alerts_check_session(s);
tty_update_client_offset(c); tty_update_client_offset(c);
status_timer_start(c); status_timer_start(c);
@@ -2413,16 +2413,6 @@ server_client_key_callback(struct cmdq_item *item, void *data)
event->key = key; event->key = key;
} }
/* Handle theme reporting keys. */
if (key == KEYC_REPORT_LIGHT_THEME) {
server_client_report_theme(c, THEME_LIGHT);
goto out;
}
if (key == KEYC_REPORT_DARK_THEME) {
server_client_report_theme(c, THEME_DARK);
goto out;
}
/* Find affected pane. */ /* Find affected pane. */
if (!KEYC_IS_MOUSE(key) || cmd_find_from_mouse(&fs, m, 0) != 0) if (!KEYC_IS_MOUSE(key) || cmd_find_from_mouse(&fs, m, 0) != 0)
cmd_find_from_client(&fs, c, 0); cmd_find_from_client(&fs, c, 0);
@@ -2641,6 +2631,19 @@ server_client_handle_key(struct client *c, struct key_event *event)
if (s == NULL || (c->flags & CLIENT_UNATTACHEDFLAGS)) if (s == NULL || (c->flags & CLIENT_UNATTACHEDFLAGS))
return (0); return (0);
/*
* Handle theme reporting keys before overlays so they work even when a
* popup is open.
*/
if (event->key == KEYC_REPORT_LIGHT_THEME) {
server_client_report_theme(c, THEME_LIGHT);
return (0);
}
if (event->key == KEYC_REPORT_DARK_THEME) {
server_client_report_theme(c, THEME_DARK);
return (0);
}
/* /*
* Key presses in overlay mode and the command prompt are a special * Key presses in overlay mode and the command prompt are a special
* case. The queue might be blocked so they need to be processed * case. The queue might be blocked so they need to be processed

View File

@@ -766,3 +766,29 @@ session_theme_changed(struct session *s)
} }
} }
} }
/* Update history for all panes. */
void
session_update_history(struct session *s)
{
struct winlink *wl;
struct window_pane *wp;
struct grid *gd;
u_int limit, osize;
limit = options_get_number(s->options, "history-limit");
RB_FOREACH(wl, winlinks, &s->windows) {
TAILQ_FOREACH(wp, &wl->window->panes, entry) {
gd = wp->base.grid;
osize = gd->hsize;
gd->hlimit = limit;
grid_collect_history(gd, 1);
if (gd->hsize != osize) {
log_debug("%s: %%%u %u -> %u", __func__, wp->id,
osize, gd->hsize);
}
}
}
}

4
tmux.1
View File

@@ -4585,9 +4585,7 @@ If set to 0, messages and indicators are displayed until a key is pressed.
.Ar time .Ar time
is in milliseconds. is in milliseconds.
.It Ic history-limit Ar lines .It Ic history-limit Ar lines
Set the maximum number of lines held in window history. Set the maximum number of lines held in pane history.
This setting applies only to new windows - existing window histories are not
resized and retain the limit at the point they were created.
.It Ic initial-repeat-time Ar time .It Ic initial-repeat-time Ar time
Set the time in milliseconds for the initial repeat when a key is bound with the Set the time in milliseconds for the initial repeat when a key is bound with the
.Fl r .Fl r

4
tmux.h
View File

@@ -3047,7 +3047,7 @@ int grid_cells_look_equal(const struct grid_cell *,
struct grid *grid_create(u_int, u_int, u_int); struct grid *grid_create(u_int, u_int, u_int);
void grid_destroy(struct grid *); void grid_destroy(struct grid *);
int grid_compare(struct grid *, struct grid *); int grid_compare(struct grid *, struct grid *);
void grid_collect_history(struct grid *); void grid_collect_history(struct grid *, int);
void grid_remove_history(struct grid *, u_int ); void grid_remove_history(struct grid *, u_int );
void grid_scroll_history(struct grid *, u_int); void grid_scroll_history(struct grid *, u_int);
void grid_scroll_history_region(struct grid *, u_int, u_int, u_int); void grid_scroll_history_region(struct grid *, u_int, u_int, u_int);
@@ -3225,6 +3225,7 @@ void screen_select_cell(struct screen *, struct grid_cell *,
void screen_alternate_on(struct screen *, struct grid_cell *, int); void screen_alternate_on(struct screen *, struct grid_cell *, int);
void screen_alternate_off(struct screen *, struct grid_cell *, int); void screen_alternate_off(struct screen *, struct grid_cell *, int);
const char *screen_mode_to_string(int); const char *screen_mode_to_string(int);
const char *screen_print(struct screen *);
/* window.c */ /* window.c */
extern struct windows windows; extern struct windows windows;
@@ -3533,6 +3534,7 @@ u_int session_group_count(struct session_group *);
u_int session_group_attached_count(struct session_group *); u_int session_group_attached_count(struct session_group *);
void session_renumber_windows(struct session *); void session_renumber_windows(struct session *);
void session_theme_changed(struct session *); void session_theme_changed(struct session *);
void session_update_history(struct session *);
/* utf8.c */ /* utf8.c */
enum utf8_state utf8_towc (const struct utf8_data *, wchar_t *); enum utf8_state utf8_towc (const struct utf8_data *, wchar_t *);

View File

@@ -2708,6 +2708,11 @@ window_copy_cmd_refresh_from_pane(struct window_copy_cmd_state *cs)
data->backing = window_copy_clone_screen(&wp->base, &data->screen, NULL, data->backing = window_copy_clone_screen(&wp->base, &data->screen, NULL,
NULL, wme->swp != wme->wp); NULL, wme->swp != wme->wp);
if (data->oy > screen_hsize(data->backing)) {
data->cy = 0;
data->oy = screen_hsize(data->backing);
}
window_copy_size_changed(wme); window_copy_size_changed(wme);
return (WINDOW_COPY_CMD_REDRAW); return (WINDOW_COPY_CMD_REDRAW);
} }