Merge branch 'obsd-master'

This commit is contained in:
Thomas Adam
2026-02-12 11:10:01 +00:00
17 changed files with 204 additions and 98 deletions

View File

@@ -58,29 +58,31 @@ cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item)
struct args *args = cmd_get_args(self);
struct client *tc = cmdq_get_target_client(item);
struct paste_buffer *pb;
char *bufdata, *cause;
const char *bufname, *olddata;
size_t bufsize, newsize;
char *bufname, *bufdata = NULL, *cause = NULL;
const char *olddata;
size_t bufsize = 0, newsize;
bufname = args_get(args, 'b');
if (bufname == NULL)
if (args_get(args, 'b') == NULL)
pb = NULL;
else
else {
bufname = xstrdup(args_get(args, 'b'));
pb = paste_get_name(bufname);
}
if (cmd_get_entry(self) == &cmd_delete_buffer_entry) {
if (pb == NULL) {
if (bufname != NULL) {
cmdq_error(item, "unknown buffer: %s", bufname);
return (CMD_RETURN_ERROR);
goto fail;
}
pb = paste_get_top(&bufname);
}
if (pb == NULL) {
cmdq_error(item, "no buffer");
return (CMD_RETURN_ERROR);
goto fail;
}
paste_free(pb);
free(bufname);
return (CMD_RETURN_NORMAL);
}
@@ -88,32 +90,28 @@ cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item)
if (pb == NULL) {
if (bufname != NULL) {
cmdq_error(item, "unknown buffer: %s", bufname);
return (CMD_RETURN_ERROR);
goto fail;
}
pb = paste_get_top(&bufname);
}
if (pb == NULL) {
cmdq_error(item, "no buffer");
return (CMD_RETURN_ERROR);
goto fail;
}
if (paste_rename(bufname, args_get(args, 'n'), &cause) != 0) {
cmdq_error(item, "%s", cause);
free(cause);
return (CMD_RETURN_ERROR);
goto fail;
}
return (CMD_RETURN_NORMAL);
}
if (args_count(args) != 1) {
cmdq_error(item, "no data specified");
return (CMD_RETURN_ERROR);
goto fail;
}
if ((newsize = strlen(args_string(args, 0))) == 0)
return (CMD_RETURN_NORMAL);
bufsize = 0;
bufdata = NULL;
if (args_has(args, 'a') && pb != NULL) {
olddata = paste_buffer_data(pb, &bufsize);
bufdata = xmalloc(bufsize);
@@ -126,12 +124,16 @@ cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item)
if (paste_set(bufdata, bufsize, bufname, &cause) != 0) {
cmdq_error(item, "%s", cause);
free(bufdata);
free(cause);
return (CMD_RETURN_ERROR);
goto fail;
}
if (args_has(args, 'w') && tc != NULL)
tty_set_selection(&tc->tty, "", bufdata, bufsize);
return (CMD_RETURN_NORMAL);
fail:
free(bufdata);
free(bufname);
free(cause);
return (CMD_RETURN_ERROR);
}

View File

@@ -610,7 +610,7 @@ control_append_data(struct client *c, struct control_pane *cp, uint64_t age,
struct evbuffer *message, struct window_pane *wp, size_t size)
{
u_char *new_data;
size_t new_size;
size_t new_size, start;
u_int i;
if (message == NULL) {
@@ -629,10 +629,16 @@ control_append_data(struct client *c, struct control_pane *cp, uint64_t age,
if (new_size < size)
fatalx("not enough data: %zu < %zu", new_size, size);
for (i = 0; i < size; i++) {
if (new_data[i] < ' ' || new_data[i] == '\\')
if (new_data[i] < ' ' || new_data[i] == '\\') {
evbuffer_add_printf(message, "\\%03o", new_data[i]);
else
evbuffer_add_printf(message, "%c", new_data[i]);
} else {
start = i;
while (i + 1 < size &&
new_data[i + 1] >= ' ' &&
new_data[i + 1] != '\\')
i++;
evbuffer_add(message, new_data + start, i - start + 1);
}
}
window_pane_update_used_data(wp, &cp->offset, size);
return (message);

View File

@@ -2012,8 +2012,10 @@ format_cb_pane_bottom(struct format_tree *ft)
static void *
format_cb_pane_dead(struct format_tree *ft)
{
if (ft->wp != NULL) {
if (ft->wp->fd == -1)
struct window_pane *wp = ft->wp;
if (wp != NULL) {
if (wp->fd == -1 && (wp->flags & PANE_STATUSREADY))
return (xstrdup("1"));
return (xstrdup("0"));
}

91
input.c
View File

@@ -101,6 +101,7 @@ struct input_ctx {
struct bufferevent *event;
struct screen_write_ctx ctx;
struct colour_palette *palette;
struct client *c;
struct input_cell cell;
struct input_cell old_cell;
@@ -854,7 +855,7 @@ input_restore_state(struct input_ctx *ictx)
/* Initialise input parser. */
struct input_ctx *
input_init(struct window_pane *wp, struct bufferevent *bev,
struct colour_palette *palette)
struct colour_palette *palette, struct client *c)
{
struct input_ctx *ictx;
@@ -862,6 +863,7 @@ input_init(struct window_pane *wp, struct bufferevent *bev,
ictx->wp = wp;
ictx->event = bev;
ictx->palette = palette;
ictx->c = c;
ictx->input_space = INPUT_BUF_START;
ictx->input_buf = xmalloc(INPUT_BUF_START);
@@ -3110,31 +3112,28 @@ input_osc_52_reply(struct input_ctx *ictx)
input_add_request(ictx, INPUT_REQUEST_CLIPBOARD, ictx->input_end);
}
/* Handle the OSC 52 sequence for setting the clipboard. */
static void
input_osc_52(struct input_ctx *ictx, const char *p)
/*
* Parse and decode OSC 52 clipboard data. Returns 0 on failure or if handled
* as a query. On success, returns 1 and sets *out, *outlen, and *flags (caller
* must free *out).
*/
static int
input_osc_52_parse(struct input_ctx *ictx, const char *p, u_char **out,
int *outlen, char *flags)
{
struct window_pane *wp = ictx->wp;
size_t len;
char *end;
u_char *out;
int outlen, state;
struct screen_write_ctx ctx;
const char* allow = "cpqs01234567";
char flags[sizeof "cpqs01234567"] = "";
u_int i, j = 0;
char *end;
size_t len;
const char *allow = "cpqs01234567";
u_int i, j = 0;
if (wp == NULL)
return;
state = options_get_number(global_options, "set-clipboard");
if (state != 2)
return;
if (options_get_number(global_options, "set-clipboard") != 2)
return (0);
if ((end = strchr(p, ';')) == NULL)
return;
return (0);
end++;
if (*end == '\0')
return;
return (0);
log_debug("%s: %s", __func__, end);
for (i = 0; p + i != end; i++) {
@@ -3145,25 +3144,53 @@ input_osc_52(struct input_ctx *ictx, const char *p)
if (strcmp(end, "?") == 0) {
input_osc_52_reply(ictx);
return;
return (0);
}
len = (strlen(end) / 4) * 3;
if (len == 0)
return;
return (0);
out = xmalloc(len);
if ((outlen = b64_pton(end, out, len)) == -1) {
free(out);
return;
*out = xmalloc(len);
if ((*outlen = b64_pton(end, *out, len)) == -1) {
free(*out);
*out = NULL;
return (0);
}
screen_write_start_pane(&ctx, wp, NULL);
screen_write_setselection(&ctx, flags, out, outlen);
screen_write_stop(&ctx);
notify_pane("pane-set-clipboard", wp);
return (1);
}
paste_add(NULL, out, outlen);
/* Handle the OSC 52 sequence for setting the clipboard. */
static void
input_osc_52(struct input_ctx *ictx, const char *p)
{
struct window_pane *wp = ictx->wp;
struct screen_write_ctx ctx;
u_char *out;
int outlen;
char flags[sizeof "cpqs01234567"] = "";
if (!input_osc_52_parse(ictx, p, &out, &outlen, flags))
return;
if (wp == NULL) {
/* Popup window. */
if (ictx->c == NULL) {
free(out);
return;
}
tty_set_selection(&ictx->c->tty, flags, out, outlen);
paste_add(NULL, out, outlen);
} else {
/* Normal window. */
screen_write_start_pane(&ctx, wp, NULL);
screen_write_setselection(&ctx, flags, out, outlen);
screen_write_stop(&ctx);
notify_pane("pane-set-clipboard", wp);
paste_add(NULL, out, outlen);
}
free(out);
}
/* Handle the OSC 104 sequence for unsetting (multiple) palette entries. */
@@ -3434,7 +3461,7 @@ input_cancel_requests(struct client *c)
{
struct input_request *ir, *ir1;
TAILQ_FOREACH_SAFE(ir, &c->input_requests, entry, ir1)
TAILQ_FOREACH_SAFE(ir, &c->input_requests, centry, ir1)
input_free_request(ir);
}

View File

@@ -297,12 +297,12 @@ key_bindings_remove_table(const char *name)
table = key_bindings_get_table(name, 0);
if (table != NULL) {
RB_REMOVE(key_tables, &key_tables, table);
TAILQ_FOREACH(c, &clients, entry) {
if (c->keytable == table)
server_client_set_key_table(c, NULL);
}
key_bindings_unref_table(table);
}
TAILQ_FOREACH(c, &clients, entry) {
if (c->keytable == table)
server_client_set_key_table(c, NULL);
}
}
void

View File

@@ -106,7 +106,7 @@ paste_is_empty(void)
/* Get the most recent automatic buffer. */
struct paste_buffer *
paste_get_top(const char **name)
paste_get_top(char **name)
{
struct paste_buffer *pb;
@@ -116,7 +116,7 @@ paste_get_top(const char **name)
if (pb == NULL)
return (NULL);
if (name != NULL)
*name = pb->name;
*name = xstrdup(pb->name);
return (pb);
}

View File

@@ -850,7 +850,7 @@ popup_display(int flags, enum box_lines lines, struct cmdq_item *item, u_int px,
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);
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);

View File

@@ -250,7 +250,7 @@ skip:
/* Return whether a suitable size was found. */
if (type == WINDOW_SIZE_MANUAL) {
log_debug("%s: type is manual", __func__);
return (1);
return (w != NULL);
}
if (type == WINDOW_SIZE_LARGEST) {
log_debug("%s: type is largest", __func__);

View File

@@ -2705,18 +2705,31 @@ server_client_handle_key(struct client *c, struct key_event *event)
void
server_client_loop(void)
{
struct client *c;
struct window *w;
struct window_pane *wp;
struct client *c;
struct window *w;
struct window_pane *wp;
struct window_mode_entry *wme;
/* Check for window resize. This is done before redrawing. */
RB_FOREACH(w, windows, &windows)
server_client_check_window_resize(w);
/* Notify modes that pane styles may have changed. */
RB_FOREACH(w, windows, &windows) {
TAILQ_FOREACH(wp, &w->panes, entry) {
if (wp->flags & PANE_STYLECHANGED) {
wme = TAILQ_FIRST(&wp->modes);
if (wme != NULL &&
wme->mode->style_changed != NULL)
wme->mode->style_changed(wme);
}
}
}
/* Check clients. */
TAILQ_FOREACH(c, &clients, entry) {
server_client_check_exit(c);
if (c->session != NULL) {
if (c->session != NULL && c->session->curw != NULL) {
server_client_check_modes(c);
server_client_check_redraw(c);
server_client_reset_state(c);

40
sort.c
View File

@@ -197,23 +197,25 @@ sort_pane_cmp(const void *a0, const void *b0)
case SORT_CREATION:
result = a->id - b->id;
break;
case SORT_INDEX:
case SORT_NAME:
case SORT_ORDER:
case SORT_SIZE:
case SORT_END:
result = a->sx * a->sy - b->sx * b->sy;
break;
}
if (result == 0) {
/*
* Panes don't have names, so use number order for any other
* sort field.
*/
case SORT_INDEX:
window_pane_index(a, &ai);
window_pane_index(b, &bi);
result = ai - bi;
break;
case SORT_NAME:
result = strcmp(a->screen->title, b->screen->title);
break;
case SORT_ORDER:
case SORT_END:
break;
}
if (result == 0)
result = strcmp(a->screen->title, b->screen->title);
if (sort_crit->reversed)
result = -result;
return (result);
@@ -235,6 +237,16 @@ sort_winlink_cmp(const void *a0, const void *b0)
case SORT_INDEX:
result = wla->idx - wlb->idx;
break;
case SORT_CREATION:
if (timercmp(&wa->creation_time, &wb->creation_time, >)) {
result = -1;
break;
}
if (timercmp(&wa->creation_time, &wb->creation_time, <)) {
result = 1;
break;
}
break;
case SORT_ACTIVITY:
if (timercmp(&wa->activity_time, &wb->activity_time, >)) {
result = -1;
@@ -248,9 +260,10 @@ sort_winlink_cmp(const void *a0, const void *b0)
case SORT_NAME:
result = strcmp(wa->name, wb->name);
break;
case SORT_CREATION:
case SORT_ORDER:
case SORT_SIZE:
result = wa->sx * wa->sy - wb->sx * wb->sy;
break;
case SORT_ORDER:
case SORT_END:
break;
}
@@ -295,7 +308,8 @@ sort_order_from_string(const char* order)
return (SORT_CREATION);
if (strcasecmp(order, "index") == 0)
return (SORT_INDEX);
if (strcasecmp(order, "name") == 0)
if (strcasecmp(order, "name") == 0 ||
strcasecmp(order, "title") == 0)
return (SORT_NAME);
if (strcasecmp(order, "order") == 0)
return (SORT_ORDER);

10
tmux.1
View File

@@ -3092,7 +3092,11 @@ See the
section.
.Fl O
specifies the sort order: one of
.Ql name ,
.Ql name
(title),
.Ql index ,
.Ql size
(area),
.Ql creation
(time), or
.Ql activity
@@ -3125,6 +3129,10 @@ section.
specifies the sort order: one of
.Ql index ,
.Ql name ,
.Ql size
(area),
.Ql creation
(time),
or
.Ql activity
(time).

6
tmux.h
View File

@@ -1101,6 +1101,7 @@ struct window_mode {
void (*free)(struct window_mode_entry *);
void (*resize)(struct window_mode_entry *, u_int, u_int);
void (*update)(struct window_mode_entry *);
void (*style_changed)(struct window_mode_entry *);
void (*key)(struct window_mode_entry *, struct client *,
struct session *, struct winlink *, key_code,
struct mouse_event *);
@@ -1285,6 +1286,7 @@ struct window {
struct event offset_timer;
struct timeval activity_time;
struct timeval creation_time;
struct window_pane *active;
struct window_panes last_panes;
@@ -2353,7 +2355,7 @@ time_t paste_buffer_created(struct paste_buffer *);
const char *paste_buffer_data(struct paste_buffer *, size_t *);
struct paste_buffer *paste_walk(struct paste_buffer *);
int paste_is_empty(void);
struct paste_buffer *paste_get_top(const char **);
struct paste_buffer *paste_get_top(char **);
struct paste_buffer *paste_get_name(const char *);
void paste_free(struct paste_buffer *);
void paste_add(const char *, char *, size_t);
@@ -3055,7 +3057,7 @@ void recalculate_sizes_now(int);
/* input.c */
#define INPUT_BUF_DEFAULT_SIZE 1048576
struct input_ctx *input_init(struct window_pane *, struct bufferevent *,
struct colour_palette *);
struct colour_palette *, struct client *);
void input_free(struct input_ctx *);
void input_reset(struct input_ctx *, int);
struct evbuffer *input_pending(struct input_ctx *);

View File

@@ -262,10 +262,12 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx,
else
next_state = TTY_DRAW_LINE_NEW1;
}
log_debug("%s: cell %u empty %u, bg %u; state: current %s, "
"next %s", __func__, px + i, empty, gcp->bg,
tty_draw_line_states[current_state],
tty_draw_line_states[next_state]);
if (log_get_level() != 0) {
log_debug("%s: cell %u empty %u, bg %u; state: "
"current %s, next %s", __func__, px + i, empty,
gcp->bg, tty_draw_line_states[current_state],
tty_draw_line_states[next_state]);
}
/* If the state has changed, flush any collected data. */
if (next_state != current_state) {

View File

@@ -1377,6 +1377,10 @@ tty_keys_clipboard(struct tty *tty, const char *buf, size_t len, size_t *size)
/* Convert from base64. */
needed = (end / 4) * 3;
if (needed == 0) {
free(copy);
return (0);
}
out = xmalloc(needed);
if ((outlen = b64_pton(copy, out, len)) == -1) {
free(out);
@@ -1612,8 +1616,10 @@ tty_keys_extended_device_attributes(struct tty *tty, const char *buf,
}
if (i == (sizeof tmp) - 1)
return (-1);
tmp[i - 1] = '\0';
*size = 5 + i;
if (i == 0)
return (0);
tmp[i - 1] = '\0';
/* Add terminal features. */
if (strncmp(tmp, "iTerm2 ", 7) == 0)
@@ -1686,11 +1692,13 @@ tty_keys_colours(struct tty *tty, const char *buf, size_t len, size_t *size,
}
if (i == (sizeof tmp) - 1)
return (-1);
*size = 6 + i;
if (i == 0)
return (0);
if (tmp[i - 1] == '\033')
tmp[i - 1] = '\0';
else
tmp[i] = '\0';
*size = 6 + i;
/* Work out the colour. */
n = colour_parseX11(tmp);
@@ -1755,11 +1763,13 @@ tty_keys_palette(struct tty *tty, const char *buf, size_t len, size_t *size)
}
if (i == (sizeof tmp) - 1)
return (-1);
*size = 5 + i;
if (i == 0)
return (0);
if (tmp[i - 1] == '\033')
tmp[i - 1] = '\0';
else
tmp[i] = '\0';
*size = 5 + i;
/* Parse index. */
idx = strtol(tmp, &endptr, 10);

4
tty.c
View File

@@ -633,7 +633,8 @@ tty_add(struct tty *tty, const char *buf, size_t len)
if (tty_log_fd != -1)
write(tty_log_fd, buf, len);
if (tty->flags & TTY_STARTED)
if ((tty->flags & TTY_STARTED) &&
!event_pending(&tty->event_out, EV_WRITE, NULL))
event_add(&tty->event_out, NULL);
}
@@ -2185,7 +2186,6 @@ tty_cell(struct tty *tty, const struct grid_cell *gc,
/* If it is a single character, write with putc to handle ACS. */
if (gcp->data.size == 1) {
tty_attributes(tty, gcp, defaults, palette, hl);
if (*gcp->data.data < 0x20 || *gcp->data.data == 0x7f)
return;
tty_putc(tty, *gcp->data.data);

View File

@@ -51,6 +51,7 @@ static void window_copy_redraw_selection(struct window_mode_entry *, u_int);
static void window_copy_redraw_lines(struct window_mode_entry *, u_int,
u_int);
static void window_copy_redraw_screen(struct window_mode_entry *);
static void window_copy_style_changed(struct window_mode_entry *);
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 *,
@@ -158,6 +159,7 @@ const struct window_mode window_copy_mode = {
.init = window_copy_init,
.free = window_copy_free,
.resize = window_copy_resize,
.style_changed = window_copy_style_changed,
.key_table = window_copy_key_table,
.command = window_copy_command,
.formats = window_copy_formats,
@@ -170,6 +172,7 @@ const struct window_mode window_view_mode = {
.init = window_copy_view_init,
.free = window_copy_free,
.resize = window_copy_resize,
.style_changed = window_copy_style_changed,
.key_table = window_copy_key_table,
.command = window_copy_command,
.formats = window_copy_formats,
@@ -491,7 +494,7 @@ window_copy_view_init(struct window_mode_entry *wme,
data->backing = xmalloc(sizeof *data->backing);
screen_init(data->backing, sx, screen_size_y(base), UINT_MAX);
data->ictx = input_init(NULL, NULL, NULL);
data->ictx = input_init(NULL, NULL, NULL, NULL);
data->mx = data->cx;
data->my = screen_hsize(data->backing) + data->cy - data->oy;
data->showmark = 0;
@@ -4268,6 +4271,9 @@ window_copy_clear_marks(struct window_mode_entry *wme)
{
struct window_copy_mode_data *data = wme->data;
data->searchcount = -1;
data->searchmore = 0;
free(data->searchmark);
data->searchmark = NULL;
}
@@ -4595,6 +4601,16 @@ window_copy_redraw_screen(struct window_mode_entry *wme)
window_copy_redraw_lines(wme, 0, screen_size_y(&data->screen));
}
static void
window_copy_style_changed(struct window_mode_entry *wme)
{
struct window_copy_mode_data *data = wme->data;
if (data->screen.sel != NULL)
window_copy_set_selection(wme, 0, 1);
window_copy_redraw_screen(wme);
}
static void
window_copy_synchronize_cursor_end(struct window_mode_entry *wme, int begin,
int no_reset)
@@ -5036,9 +5052,9 @@ static void
window_copy_append_selection(struct window_mode_entry *wme)
{
struct window_pane *wp = wme->wp;
char *buf;
char *buf, *bufname = NULL;
struct paste_buffer *pb;
const char *bufdata, *bufname = NULL;
const char *bufdata;
size_t len, bufsize;
struct screen_write_ctx ctx;
@@ -5063,6 +5079,7 @@ window_copy_append_selection(struct window_mode_entry *wme)
}
if (paste_set(buf, len, bufname, NULL) != 0)
free(buf);
free(bufname);
}
static void

View File

@@ -328,6 +328,9 @@ window_create(u_int sx, u_int sy, u_int xpixel, u_int ypixel)
RB_INSERT(windows, &windows, w);
window_set_fill_character(w);
if (gettimeofday(&w->creation_time, NULL) != 0)
fatal("gettimeofday failed");
window_update_activity(w);
log_debug("%s: @%u create %ux%u (%ux%u)", __func__, w->id, sx, sy,
@@ -1068,7 +1071,7 @@ window_pane_set_event(struct window_pane *wp)
NULL, window_pane_error_callback, wp);
if (wp->event == NULL)
fatalx("out of memory");
wp->ictx = input_init(wp, wp->event, &wp->palette);
wp->ictx = input_init(wp, wp->event, &wp->palette, NULL);
bufferevent_enable(wp->event, EV_READ|EV_WRITE);
}