mirror of
https://github.com/tmux/tmux.git
synced 2026-09-05 13:10:45 +00:00
Merge branch 'master' into no_more_overlays
# Conflicts: # cmd-display-menu.c # popup.c # screen-write.c
This commit is contained in:
3
.github/workflows/lock.yml
vendored
3
.github/workflows/lock.yml
vendored
@@ -17,8 +17,9 @@ jobs:
|
||||
action:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository == 'tmux/tmux'
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: dessant/lock-threads@v6
|
||||
- uses: dessant/lock-threads@89ae32b08ed1a541efecbab17912962a5e38981c # v6
|
||||
with:
|
||||
github-token: ${{ github.token }}
|
||||
issue-inactive-days: '30'
|
||||
|
||||
6
.github/workflows/regress.yml
vendored
6
.github/workflows/regress.yml
vendored
@@ -38,7 +38,9 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: dependencies
|
||||
if: runner.os == 'Linux'
|
||||
@@ -81,7 +83,7 @@ jobs:
|
||||
|
||||
- name: logs
|
||||
if: failure()
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
||||
with:
|
||||
name: regress-logs-${{ matrix.name }}
|
||||
path: regress/logs/*.log
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: arguments.c,v 1.66 2026/06/26 09:54:56 nicm Exp $ */
|
||||
/* $OpenBSD: arguments.c,v 1.67 2026/08/25 06:04:33 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2010 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -762,8 +762,6 @@ args_make_commands_now(struct cmd *self, struct cmdq_item *item, u_int idx,
|
||||
cmdq_error(item, "%s", error);
|
||||
free(error);
|
||||
}
|
||||
else
|
||||
cmdlist->references++;
|
||||
args_make_commands_free(state);
|
||||
return (cmdlist);
|
||||
}
|
||||
@@ -827,8 +825,10 @@ args_make_commands(struct args_command_state *state, int argc, char **argv,
|
||||
int i;
|
||||
|
||||
if (state->cmdlist != NULL) {
|
||||
if (argc == 0)
|
||||
if (argc == 0) {
|
||||
state->cmdlist->references++;
|
||||
return (state->cmdlist);
|
||||
}
|
||||
return (cmd_list_copy(state->cmdlist, argc, argv));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: cmd-command-prompt.c,v 1.75 2026/06/25 11:39:11 nicm Exp $ */
|
||||
/* $OpenBSD: cmd-command-prompt.c,v 1.76 2026/08/25 06:04:33 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -242,9 +242,11 @@ cmd_command_prompt_callback(struct client *c, void *data, const char *s,
|
||||
} else if (item == NULL) {
|
||||
new_item = cmdq_get_command(cmdlist, NULL);
|
||||
cmdq_append(c, new_item);
|
||||
cmd_list_free(cmdlist);
|
||||
} else {
|
||||
new_item = cmdq_get_command(cmdlist, cmdq_get_state(item));
|
||||
cmdq_insert_after(item, new_item);
|
||||
cmd_list_free(cmdlist);
|
||||
}
|
||||
cmd_free_argv(argc, argv);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: cmd-display-menu.c,v 1.52 2026/07/14 19:07:03 nicm Exp $ */
|
||||
/* $OpenBSD: cmd-display-menu.c,v 1.53 2026/08/31 07:46:55 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -412,7 +412,8 @@ cmd_display_popup_exec(struct cmd *self, struct cmdq_item *item)
|
||||
server_kill_pane(w->modal);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
if (tc->flags & CLIENT_CONTROL)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
if (w->modal != NULL)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: cmd-if-shell.c,v 1.86 2025/08/01 09:05:51 nicm Exp $ */
|
||||
/* $OpenBSD: cmd-if-shell.c,v 1.87 2026/08/25 06:04:33 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
|
||||
@@ -98,6 +98,7 @@ cmd_if_shell_exec(struct cmd *self, struct cmdq_item *item)
|
||||
return (CMD_RETURN_ERROR);
|
||||
new_item = cmdq_get_command(cmdlist, cmdq_get_state(item));
|
||||
cmdq_insert_after(item, new_item);
|
||||
cmd_list_free(cmdlist);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
@@ -164,9 +165,11 @@ cmd_if_shell_callback(struct job *job)
|
||||
} else if (item == NULL) {
|
||||
new_item = cmdq_get_command(cmdlist, NULL);
|
||||
cmdq_append(c, new_item);
|
||||
cmd_list_free(cmdlist);
|
||||
} else {
|
||||
new_item = cmdq_get_command(cmdlist, cmdq_get_state(item));
|
||||
cmdq_insert_after(item, new_item);
|
||||
cmd_list_free(cmdlist);
|
||||
}
|
||||
|
||||
out:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: cmd-parse.y,v 1.58 2026/04/27 12:31:11 nicm Exp $ */
|
||||
/* $OpenBSD: cmd-parse.y,v 1.59 2026/08/31 07:51:56 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2019 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -802,6 +802,7 @@ cmd_parse_expand_alias(struct cmd_parse_command *cmd,
|
||||
if (last == NULL) {
|
||||
pr->status = CMD_PARSE_SUCCESS;
|
||||
pr->cmdlist = cmd_list_new();
|
||||
cmd_parse_free_commands(cmds);
|
||||
return (1);
|
||||
}
|
||||
|
||||
@@ -814,6 +815,7 @@ cmd_parse_expand_alias(struct cmd_parse_command *cmd,
|
||||
pi->flags |= CMD_PARSE_NOALIAS;
|
||||
cmd_parse_build_commands(cmds, pi, pr);
|
||||
pi->flags &= ~CMD_PARSE_NOALIAS;
|
||||
cmd_parse_free_commands(cmds);
|
||||
return (1);
|
||||
}
|
||||
|
||||
|
||||
15
cmd-queue.c
15
cmd-queue.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: cmd-queue.c,v 1.122 2026/08/03 13:38:42 nicm Exp $ */
|
||||
/* $OpenBSD: cmd-queue.c,v 1.123 2026/08/24 20:34:26 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -850,7 +850,18 @@ cmdq_error(struct cmdq_item *item, const char *fmt, ...)
|
||||
|
||||
if (c == NULL) {
|
||||
cmd_get_source(cmd, &file, &line);
|
||||
cfg_add_cause("%s:%u: %s", file, line, msg);
|
||||
if (!cfg_finished) {
|
||||
if (file != NULL)
|
||||
cfg_add_cause("%s:%u: %s", file, line, msg);
|
||||
else
|
||||
cfg_add_cause("%s", msg);
|
||||
} else {
|
||||
if (file != NULL) {
|
||||
server_add_message("message: %s:%u: %s", file,
|
||||
line, msg);
|
||||
} else
|
||||
server_add_message("message: %s", msg);
|
||||
}
|
||||
} else if (c->session == NULL || (c->flags & CLIENT_CONTROL)) {
|
||||
server_add_message("%s message: %s", c->name, msg);
|
||||
if (~c->flags & CLIENT_UTF8) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: cmd-resize-pane.c,v 1.67 2026/07/10 13:38:45 nicm Exp $ */
|
||||
/* $OpenBSD: cmd-resize-pane.c,v 1.68 2026/08/31 07:44:39 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -92,6 +92,7 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
server_unzoom_window(w);
|
||||
lc = wp->layout_cell; /* may have been replaced by unzoom */
|
||||
|
||||
if (args_has(args, 'x')) {
|
||||
x = args_percentage(args, 'x', 0, PANE_MAXIMUM, w->sx, &cause);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: cmd-run-shell.c,v 1.93 2026/07/17 12:42:51 nicm Exp $ */
|
||||
/* $OpenBSD: cmd-run-shell.c,v 1.94 2026/08/25 06:04:33 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Tiago Cunha <me@tiagocunha.org>
|
||||
@@ -233,9 +233,11 @@ cmd_run_shell_timer(__unused int fd, __unused short events, void* arg)
|
||||
} else if (item == NULL) {
|
||||
new_item = cmdq_get_command(cmdlist, NULL);
|
||||
cmdq_append(c, new_item);
|
||||
cmd_list_free(cmdlist);
|
||||
} else {
|
||||
new_item = cmdq_get_command(cmdlist, cmdq_get_state(item));
|
||||
cmdq_insert_after(item, new_item);
|
||||
cmd_list_free(cmdlist);
|
||||
}
|
||||
|
||||
if (cdata->item != NULL)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: cmd-set-buffer.c,v 1.37 2026/02/15 17:43:26 nicm Exp $ */
|
||||
/* $OpenBSD: cmd-set-buffer.c,v 1.38 2026/08/24 07:05:23 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -100,6 +100,7 @@ cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item)
|
||||
cmdq_error(item, "%s", cause);
|
||||
goto fail;
|
||||
}
|
||||
free(bufname);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
@@ -107,8 +108,10 @@ cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item)
|
||||
cmdq_error(item, "no data specified");
|
||||
goto fail;
|
||||
}
|
||||
if ((newsize = strlen(args_string(args, 0))) == 0)
|
||||
if ((newsize = strlen(args_string(args, 0))) == 0) {
|
||||
free(bufname);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
}
|
||||
|
||||
if (args_has(args, 'a') && pb != NULL) {
|
||||
olddata = paste_buffer_data(pb, &bufsize);
|
||||
@@ -127,6 +130,7 @@ cmd_set_buffer_exec(struct cmd *self, struct cmdq_item *item)
|
||||
if (args_has(args, 'w') && tc != NULL)
|
||||
tty_set_selection(&tc->tty, "", bufdata, bufsize);
|
||||
|
||||
free(bufname);
|
||||
return (CMD_RETURN_NORMAL);
|
||||
|
||||
fail:
|
||||
|
||||
60
format.c
60
format.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: format.c,v 1.412 2026/08/05 07:31:08 nicm Exp $ */
|
||||
/* $OpenBSD: format.c,v 1.415 2026/08/31 19:34:09 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2011 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -1887,6 +1887,37 @@ format_cb_cursor_blinking(struct format_tree *ft)
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Callback for history_added. */
|
||||
static void *
|
||||
format_cb_history_added(struct format_tree *ft)
|
||||
{
|
||||
if (ft->wp != NULL)
|
||||
return (format_printf("%u", ft->wp->base.grid->scroll_added));
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Callback for history_collected. */
|
||||
static void *
|
||||
format_cb_history_collected(struct format_tree *ft)
|
||||
{
|
||||
struct window_pane *wp = ft->wp;
|
||||
|
||||
if (wp != NULL)
|
||||
return (format_printf("%u", wp->base.grid->scroll_collected));
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Callback for history_generation. */
|
||||
static void *
|
||||
format_cb_history_generation(struct format_tree *ft)
|
||||
{
|
||||
struct window_pane *wp = ft->wp;
|
||||
|
||||
if (wp != NULL)
|
||||
return (format_printf("%u", wp->base.grid->scroll_generation));
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Callback for history_limit. */
|
||||
static void *
|
||||
format_cb_history_limit(struct format_tree *ft)
|
||||
@@ -2276,6 +2307,19 @@ format_cb_pane_last_output_time(struct format_tree *ft)
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Callback for pane_output_generation. */
|
||||
static void *
|
||||
format_cb_pane_output_generation(struct format_tree *ft)
|
||||
{
|
||||
unsigned long long value;
|
||||
|
||||
if (ft->wp != NULL) {
|
||||
value = ft->wp->output_generation;
|
||||
return (format_printf("%llu", value));
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
/* Callback for pane_last_prompt_time. */
|
||||
static void *
|
||||
format_cb_pane_last_prompt_time(struct format_tree *ft)
|
||||
@@ -3663,12 +3707,21 @@ static const struct format_table_entry format_table[] = {
|
||||
{ "cursor_y", FORMAT_TABLE_STRING,
|
||||
format_cb_cursor_y
|
||||
},
|
||||
{ "history_added", FORMAT_TABLE_STRING,
|
||||
format_cb_history_added
|
||||
},
|
||||
{ "history_all_bytes", FORMAT_TABLE_STRING,
|
||||
format_cb_history_all_bytes
|
||||
},
|
||||
{ "history_bytes", FORMAT_TABLE_STRING,
|
||||
format_cb_history_bytes
|
||||
},
|
||||
{ "history_collected", FORMAT_TABLE_STRING,
|
||||
format_cb_history_collected
|
||||
},
|
||||
{ "history_generation", FORMAT_TABLE_STRING,
|
||||
format_cb_history_generation
|
||||
},
|
||||
{ "history_limit", FORMAT_TABLE_STRING,
|
||||
format_cb_history_limit
|
||||
},
|
||||
@@ -3849,6 +3902,9 @@ static const struct format_table_entry format_table[] = {
|
||||
{ "pane_mode", FORMAT_TABLE_STRING,
|
||||
format_cb_pane_mode
|
||||
},
|
||||
{ "pane_output_generation", FORMAT_TABLE_STRING,
|
||||
format_cb_pane_output_generation
|
||||
},
|
||||
{ "pane_path", FORMAT_TABLE_STRING,
|
||||
format_cb_pane_path
|
||||
},
|
||||
@@ -4387,7 +4443,7 @@ format_quote_shell(const char *s)
|
||||
|
||||
at = out = xmalloc(strlen(s) * 2 + 1);
|
||||
for (cp = s; *cp != '\0'; cp++) {
|
||||
if (strchr("|&;<>()$`\\\"'*?[# =%\n\t", *cp) != NULL)
|
||||
if (strchr("|&;<>(){}$`\\\"'*?[# =%\n\t", *cp) != NULL)
|
||||
*at++ = '\\';
|
||||
*at++ = *cp;
|
||||
}
|
||||
|
||||
38
grid.c
38
grid.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: grid.c,v 1.156 2026/08/03 12:58:53 nicm Exp $ */
|
||||
/* $OpenBSD: grid.c,v 1.158 2026/09/01 12:49:49 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -1635,7 +1635,7 @@ grid_wrap_position(struct grid *gd, u_int px, u_int py, u_int *wx, u_int *wy)
|
||||
void
|
||||
grid_unwrap_position(struct grid *gd, u_int *px, u_int *py, u_int wx, u_int wy)
|
||||
{
|
||||
u_int yy, ay = 0;
|
||||
u_int yy, ay = 0, ey = gd->hsize + gd->sy - 1;
|
||||
|
||||
for (yy = 0; yy < gd->hsize + gd->sy - 1; yy++) {
|
||||
if (ay == wy)
|
||||
@@ -1649,7 +1649,7 @@ grid_unwrap_position(struct grid *gd, u_int *px, u_int *py, u_int wx, u_int wy)
|
||||
* until we find the end or the line now containing wx.
|
||||
*/
|
||||
if (wx == UINT_MAX) {
|
||||
while (gd->linedata[yy].flags & GRID_LINE_WRAPPED)
|
||||
while (yy < ey && gd->linedata[yy].flags & GRID_LINE_WRAPPED)
|
||||
yy++;
|
||||
wx = gd->linedata[yy].cellused;
|
||||
} else {
|
||||
@@ -1711,21 +1711,29 @@ grid_in_set(struct grid *gd, u_int px, u_int py, const char *set)
|
||||
{
|
||||
struct grid_cell gc, tmp_gc;
|
||||
u_int pxx;
|
||||
int has_tab, has_space;
|
||||
|
||||
has_tab = (strchr(set, '\t') != NULL);
|
||||
has_space = (strchr(set, ' ') != NULL);
|
||||
|
||||
grid_get_cell(gd, px, py, &gc);
|
||||
if (strchr(set, '\t')) {
|
||||
if (gc.flags & GRID_FLAG_PADDING) {
|
||||
pxx = px;
|
||||
do
|
||||
grid_get_cell(gd, --pxx, py, &tmp_gc);
|
||||
while (pxx > 0 && tmp_gc.flags & GRID_FLAG_PADDING);
|
||||
if (tmp_gc.flags & GRID_FLAG_TAB)
|
||||
return (tmp_gc.data.width - (px - pxx));
|
||||
} else if (gc.flags & GRID_FLAG_TAB)
|
||||
return (gc.data.width);
|
||||
}
|
||||
if (gc.flags & GRID_FLAG_PADDING)
|
||||
if (gc.flags & GRID_FLAG_PADDING) {
|
||||
if (!has_tab && !has_space)
|
||||
return (0);
|
||||
pxx = px;
|
||||
do
|
||||
grid_get_cell(gd, --pxx, py, &tmp_gc);
|
||||
while (pxx > 0 && tmp_gc.flags & GRID_FLAG_PADDING);
|
||||
if (((has_tab || has_space) &&
|
||||
(tmp_gc.flags & GRID_FLAG_TAB)) ||
|
||||
(has_space && utf8_has_whitespace(&tmp_gc.data)))
|
||||
return (tmp_gc.data.width - (px - pxx));
|
||||
return (0);
|
||||
}
|
||||
if ((has_tab || has_space) && (gc.flags & GRID_FLAG_TAB))
|
||||
return (gc.data.width);
|
||||
if (has_space && utf8_has_whitespace(&gc.data))
|
||||
return (gc.data.width == 0 ? 1 : gc.data.width);
|
||||
return (utf8_cstrhas(set, &gc.data));
|
||||
}
|
||||
|
||||
|
||||
5
image.c
5
image.c
@@ -84,6 +84,11 @@ image_fallback(char **ret, u_int sx, u_int sy)
|
||||
char *buf, *label;
|
||||
u_int py, size, lsize;
|
||||
|
||||
if (sy == 0) {
|
||||
*ret = xstrdup("");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Allocate first line. */
|
||||
lsize = xasprintf(&label, "SIXEL IMAGE (%ux%u)\r\n", sx, sy) + 1;
|
||||
if (sx < lsize - 3)
|
||||
|
||||
3
input.c
3
input.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: input.c,v 1.270 2026/08/17 20:04:00 nicm Exp $ */
|
||||
/* $OpenBSD: input.c,v 1.271 2026/08/31 19:34:09 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -1047,6 +1047,7 @@ input_parse_buffer(struct window_pane *wp, const u_char *buf, size_t len)
|
||||
if (len == 0)
|
||||
return;
|
||||
|
||||
wp->output_generation++;
|
||||
window_update_activity(wp->window);
|
||||
if (~wp->flags & PANE_ACTIVITY) {
|
||||
wp->flags |= PANE_ACTIVITY;
|
||||
|
||||
39
layout.c
39
layout.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: layout.c,v 1.97 2026/08/20 09:19:24 nicm Exp $ */
|
||||
/* $OpenBSD: layout.c,v 1.98 2026/08/25 18:38:05 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -539,6 +539,10 @@ layout_resize_check(struct window *w, struct layout_cell *lc,
|
||||
|
||||
status = window_get_pane_status(w);
|
||||
|
||||
/* Floating cells do not take space from the tiled layout. */
|
||||
if (!layout_cell_is_tiled(lc) && !layout_cell_has_tiled_child(lc))
|
||||
return (0);
|
||||
|
||||
if (lc->type == LAYOUT_WINDOWPANE) {
|
||||
/* Space available in this cell only. */
|
||||
if (type == LAYOUT_LEFTRIGHT) {
|
||||
@@ -568,6 +572,9 @@ layout_resize_check(struct window *w, struct layout_cell *lc,
|
||||
/* Different type: minimum of available space in child cells. */
|
||||
minimum = UINT_MAX;
|
||||
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
|
||||
if (!layout_cell_is_tiled(lcchild) &&
|
||||
!layout_cell_has_tiled_child(lcchild))
|
||||
continue;
|
||||
available = layout_resize_check(w, lcchild, type);
|
||||
if (available < minimum)
|
||||
minimum = available;
|
||||
@@ -661,7 +668,7 @@ layout_resize_set_size(struct window *w, struct layout_cell *lc,
|
||||
|
||||
/* Find and return the nearest neighbour to a cell in a specific direction. */
|
||||
static struct layout_cell *
|
||||
layout_cell_get_neighbour_direction(struct layout_cell *lc, int direction)
|
||||
layout_cell_get_neighbour_dir(struct layout_cell *lc, int direction)
|
||||
{
|
||||
struct layout_cell *lcn = lc;
|
||||
|
||||
@@ -695,9 +702,9 @@ layout_cell_get_neighbour(struct layout_cell *lc)
|
||||
if (lc == TAILQ_LAST(&lcparent->cells, layout_cells))
|
||||
direction = !direction;
|
||||
|
||||
lcother = layout_cell_get_neighbour_direction(lc, direction);
|
||||
lcother = layout_cell_get_neighbour_dir(lc, direction);
|
||||
if (lcother == NULL)
|
||||
lcother = layout_cell_get_neighbour_direction(lc, !direction);
|
||||
lcother = layout_cell_get_neighbour_dir(lc, !direction);
|
||||
|
||||
return (lcother);
|
||||
}
|
||||
@@ -860,7 +867,7 @@ layout_resize_pane_to(struct window_pane *wp, enum layout_type type,
|
||||
size = lc->g.sx;
|
||||
else
|
||||
size = lc->g.sy;
|
||||
if (lc == TAILQ_LAST(&lcparent->cells, layout_cells))
|
||||
if (layout_cell_is_last_tiled(lc))
|
||||
change = size - new_size;
|
||||
else
|
||||
change = new_size - size;
|
||||
@@ -985,11 +992,11 @@ layout_resize_pane(struct window_pane *wp, enum layout_type type, int change,
|
||||
if (lcparent == NULL)
|
||||
return;
|
||||
|
||||
/* If this is the last cell, move back one. */
|
||||
if (lc == TAILQ_LAST(&lcparent->cells, layout_cells)) {
|
||||
do
|
||||
lc = TAILQ_PREV(lc, layout_cells, entry);
|
||||
while (lc->flags & LAYOUT_CELL_FLOATING);
|
||||
/* If this is the last tiled cell, move back one. */
|
||||
if (layout_cell_is_last_tiled(lc)) {
|
||||
lc = layout_cell_get_neighbour_dir(lc, 0);
|
||||
if (lc == NULL)
|
||||
return;
|
||||
}
|
||||
|
||||
layout_resize_layout(wp->window, lc, type, change, opposite);
|
||||
@@ -1007,22 +1014,22 @@ layout_resize_pane_grow(struct window *w, struct layout_cell *lc,
|
||||
lcadd = lc;
|
||||
|
||||
/* Look towards the tail for a suitable cell for reduction. */
|
||||
lcremove = TAILQ_NEXT(lc, entry);
|
||||
lcremove = layout_cell_get_neighbour_dir(lc, 1);
|
||||
while (lcremove != NULL) {
|
||||
size = layout_resize_check(w, lcremove, type);
|
||||
if (size > 0)
|
||||
break;
|
||||
lcremove = TAILQ_NEXT(lcremove, entry);
|
||||
lcremove = layout_cell_get_neighbour_dir(lcremove, 1);
|
||||
}
|
||||
|
||||
/* If none found, look towards the head. */
|
||||
if (opposite && lcremove == NULL) {
|
||||
lcremove = TAILQ_PREV(lc, layout_cells, entry);
|
||||
lcremove = layout_cell_get_neighbour_dir(lc, 0);
|
||||
while (lcremove != NULL) {
|
||||
size = layout_resize_check(w, lcremove, type);
|
||||
if (size > 0)
|
||||
break;
|
||||
lcremove = TAILQ_PREV(lcremove, layout_cells, entry);
|
||||
lcremove = layout_cell_get_neighbour_dir(lcremove, 0);
|
||||
}
|
||||
}
|
||||
if (lcremove == NULL)
|
||||
@@ -1050,13 +1057,13 @@ layout_resize_pane_shrink(struct window *w, struct layout_cell *lc,
|
||||
size = layout_resize_check(w, lcremove, type);
|
||||
if (size != 0)
|
||||
break;
|
||||
lcremove = TAILQ_PREV(lcremove, layout_cells, entry);
|
||||
lcremove = layout_cell_get_neighbour_dir(lcremove, 0);
|
||||
} while (lcremove != NULL);
|
||||
if (lcremove == NULL)
|
||||
return (0);
|
||||
|
||||
/* And add onto the next cell (from the original cell). */
|
||||
lcadd = TAILQ_NEXT(lc, entry);
|
||||
lcadd = layout_cell_get_neighbour_dir(lc, 1);
|
||||
if (lcadd == NULL)
|
||||
return (0);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: options-table.c,v 1.242 2026/07/27 08:03:01 nicm Exp $ */
|
||||
/* $OpenBSD: options-table.c,v 1.244 2026/09/01 12:49:49 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2011 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -305,6 +305,16 @@ const struct options_table_entry options_table[] = {
|
||||
"When this is reached, the oldest buffer is deleted."
|
||||
},
|
||||
|
||||
{ .name = "clear-on-attach",
|
||||
.type = OPTIONS_TABLE_FLAG,
|
||||
.scope = OPTIONS_TABLE_SERVER,
|
||||
.default_num = 1,
|
||||
.text = "Whether to use the alternate screen and clear it when "
|
||||
"a client is attached. When disabled, tmux does not "
|
||||
"enter the alternate screen on attach so terminal "
|
||||
"content before tmux remains in scrollback."
|
||||
},
|
||||
|
||||
{ .name = "command-alias",
|
||||
.type = OPTIONS_TABLE_STRING,
|
||||
.scope = OPTIONS_TABLE_SERVER,
|
||||
@@ -1240,7 +1250,8 @@ const struct options_table_entry options_table[] = {
|
||||
* underscore.
|
||||
*/
|
||||
.default_str = "!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~",
|
||||
.text = "Characters considered to separate words."
|
||||
.text = "Characters considered to separate words; a space matches "
|
||||
"any character with the Unicode White_Space property."
|
||||
},
|
||||
|
||||
/* Window options. */
|
||||
|
||||
@@ -28,7 +28,7 @@ $TMUX kill-server 2>/dev/null
|
||||
|
||||
TMP=$(mktemp)
|
||||
TMP2=$(mktemp)
|
||||
trap 'rm -f "$TMP" "$TMP2"; $TMUX kill-server 2>/dev/null' 0 1 15
|
||||
trap 'rm -f "$TMP" "$TMP2" "$TMP".*; $TMUX kill-server 2>/dev/null' 0 1 15
|
||||
|
||||
# check_ok $cmd...
|
||||
#
|
||||
@@ -270,6 +270,27 @@ if [ $? -eq 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# A write error after a successful open must be reported to the server.
|
||||
dd if=/dev/zero of="$TMP.big" bs=100000 count=1 2>/dev/null
|
||||
check_ok load-buffer -b write-error "$TMP.big"
|
||||
mkfifo "$TMP.fifo" || exit 1
|
||||
dd if="$TMP.fifo" of="$TMP.got" bs=1 count=8 2>/dev/null &
|
||||
reader=$!
|
||||
exec 3>"$TMP.fifo"
|
||||
out=$($TMUX save-buffer -b write-error "$TMP.fifo" 3>&- 2>&1)
|
||||
status=$?
|
||||
exec 3>&-
|
||||
wait "$reader"
|
||||
if [ $status -eq 0 ]; then
|
||||
echo "save-buffer after write error succeeded."
|
||||
exit 1
|
||||
fi
|
||||
if [ "$(wc -c <"$TMP.got")" -ne 8 ]; then
|
||||
echo "save-buffer write error test wrote wrong amount."
|
||||
exit 1
|
||||
fi
|
||||
check_ok delete-buffer -b write-error
|
||||
|
||||
# save-buffer - writes to stdout and load-buffer - reads from stdin.
|
||||
out=$($TMUX save-buffer -b sb -)
|
||||
if [ "$out" != "data" ]; then
|
||||
|
||||
163
regress/copy-mode-unicode-whitespace.sh
Executable file
163
regress/copy-mode-unicode-whitespace.sh
Executable file
@@ -0,0 +1,163 @@
|
||||
#!/bin/sh
|
||||
|
||||
PATH=/bin:/usr/bin
|
||||
TERM=screen
|
||||
|
||||
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
|
||||
|
||||
fail()
|
||||
{
|
||||
echo "$1"
|
||||
[ -z "$TMUX" ] || $TMUX kill-server 2>/dev/null
|
||||
exit 1
|
||||
}
|
||||
|
||||
goto_cell()
|
||||
{
|
||||
row=$1
|
||||
column=$2
|
||||
|
||||
$TMUX send-keys -X history-top || fail "$mode: history-top failed"
|
||||
$TMUX send-keys -X start-of-line || fail "$mode: start-of-line failed"
|
||||
[ "$row" -eq 0 ] ||
|
||||
$TMUX send-keys -X -N "$row" cursor-down ||
|
||||
fail "$mode: cursor-down failed"
|
||||
[ "$column" -eq 0 ] ||
|
||||
$TMUX send-keys -X -N "$column" cursor-right ||
|
||||
fail "$mode: cursor-right failed"
|
||||
}
|
||||
|
||||
check_cursor()
|
||||
{
|
||||
expected=$1
|
||||
actual=$($TMUX display-message -p '#{copy_cursor_x},#{copy_cursor_y}')
|
||||
[ "$actual" = "$expected" ] ||
|
||||
fail "$mode: expected cursor $expected, got $actual"
|
||||
}
|
||||
|
||||
check_word()
|
||||
{
|
||||
row=$1
|
||||
column=$2
|
||||
expected=$3
|
||||
|
||||
goto_cell "$row" "$column"
|
||||
$TMUX set-buffer sentinel || fail "$mode: set-buffer failed"
|
||||
$TMUX send-keys -X select-word || fail "$mode: select-word failed"
|
||||
$TMUX send-keys -X copy-selection || fail "$mode: copy-selection failed"
|
||||
actual=$($TMUX show-buffer 2>/dev/null)
|
||||
[ "$actual" = "$expected" ] ||
|
||||
fail "$mode: expected word '$expected', got '$actual'"
|
||||
}
|
||||
|
||||
check_next_word()
|
||||
{
|
||||
row=$1
|
||||
expected=$2
|
||||
|
||||
goto_cell "$row" 0
|
||||
$TMUX send-keys -X next-word || fail "$mode: next-word failed"
|
||||
$TMUX set-buffer sentinel || fail "$mode: set-buffer failed"
|
||||
$TMUX send-keys -X select-word || fail "$mode: select-word failed"
|
||||
$TMUX send-keys -X copy-selection || fail "$mode: copy-selection failed"
|
||||
actual=$($TMUX show-buffer 2>/dev/null)
|
||||
[ "$actual" = "$expected" ] ||
|
||||
fail "$mode: expected next word '$expected', got '$actual'"
|
||||
}
|
||||
|
||||
for mode in emacs vi; do
|
||||
TMUX="$TEST_TMUX -Lunicode-whitespace-$mode-$$ -f/dev/null"
|
||||
$TMUX kill-server 2>/dev/null
|
||||
$TMUX new-session -d -x16 -y20 \
|
||||
"printf 'aa bb\naa\tbb\naa\302\240bb\naa\343\200\200bb\naa:bb\naaaaaaaaaaaaaaa\302\240b\nabcdefghijklmnopq\nhardone\nhardtwo\naa\341\232\200bb\naa\342\200\200bb\naa\342\200\250bb\naa\342\200\251bb\naa\342\200\257bb\naa\342\201\237bb\nxa\302\205b c\n'; exec cat" ||
|
||||
fail "$mode: new-session failed"
|
||||
$TMUX set-option -g window-size manual || fail "$mode: set size failed"
|
||||
$TMUX set-window-option -g mode-keys "$mode" ||
|
||||
fail "$mode: set mode-keys failed"
|
||||
$TMUX set-window-option -g word-separators "" ||
|
||||
fail "$mode: clear word-separators failed"
|
||||
$TMUX copy-mode || fail "$mode: copy-mode failed"
|
||||
|
||||
# ASCII space and TAB retain their existing behaviour.
|
||||
goto_cell 0 0
|
||||
$TMUX send-keys -X next-space || fail "$mode: ASCII next-space failed"
|
||||
check_cursor 3,0
|
||||
goto_cell 1 0
|
||||
$TMUX send-keys -X next-space || fail "$mode: TAB next-space failed"
|
||||
check_cursor 8,1
|
||||
$TMUX send-keys -X previous-space ||
|
||||
fail "$mode: TAB previous-space failed"
|
||||
check_cursor 0,1
|
||||
|
||||
# NBSP is whitespace for selection and word movement.
|
||||
goto_cell 2 0
|
||||
$TMUX send-keys -X next-word || fail "$mode: NBSP next-word failed"
|
||||
check_cursor 3,2
|
||||
$TMUX send-keys -X previous-word ||
|
||||
fail "$mode: NBSP previous-word failed"
|
||||
check_cursor 0,2
|
||||
check_word 2 0 aa
|
||||
goto_cell 2 0
|
||||
$TMUX send-keys -X next-word-end ||
|
||||
fail "$mode: NBSP next-word-end failed"
|
||||
if [ "$mode" = emacs ]; then
|
||||
check_cursor 2,2
|
||||
else
|
||||
check_cursor 1,2
|
||||
fi
|
||||
|
||||
# U+3000 is two columns wide; both its leading and padding cells must be
|
||||
# skipped as one whitespace character in either direction.
|
||||
goto_cell 3 0
|
||||
$TMUX send-keys -X next-word || fail "$mode: U+3000 next-word failed"
|
||||
check_cursor 4,3
|
||||
$TMUX send-keys -X previous-word ||
|
||||
fail "$mode: U+3000 previous-word failed"
|
||||
check_cursor 0,3
|
||||
goto_cell 3 0
|
||||
$TMUX send-keys -X next-space-end ||
|
||||
fail "$mode: U+3000 next-space-end failed"
|
||||
if [ "$mode" = emacs ]; then
|
||||
check_cursor 2,3
|
||||
else
|
||||
check_cursor 1,3
|
||||
fi
|
||||
|
||||
# Other characters in word-separators remain literal when space enables
|
||||
# Unicode whitespace matching.
|
||||
$TMUX set-window-option -g word-separators ': ' ||
|
||||
fail "$mode: set custom word-separators failed"
|
||||
goto_cell 4 0
|
||||
$TMUX send-keys -X next-word || fail "$mode: literal next-word failed"
|
||||
check_cursor 2,4
|
||||
$TMUX set-window-option -g word-separators "" ||
|
||||
fail "$mode: restore word-separators failed"
|
||||
|
||||
# Whitespace in the last column remains a boundary across a soft wrap.
|
||||
goto_cell 5 0
|
||||
$TMUX send-keys -X next-space ||
|
||||
fail "$mode: wrapped NBSP next-space failed"
|
||||
check_cursor 0,6
|
||||
|
||||
# A word split only by a soft wrap remains one word, while a hard line
|
||||
# boundary still terminates selection.
|
||||
check_word 7 0 abcdefghijklmnopq
|
||||
check_word 9 0 hardone
|
||||
|
||||
# Check the remaining representative White_Space ranges and U+0085
|
||||
# combined into a cell with another character.
|
||||
check_next_word 11 bb
|
||||
check_next_word 12 bb
|
||||
check_next_word 13 bb
|
||||
check_next_word 14 bb
|
||||
check_next_word 15 bb
|
||||
check_next_word 16 bb
|
||||
goto_cell 17 0
|
||||
$TMUX send-keys -X next-word ||
|
||||
fail "$mode: combined U+0085 next-word failed"
|
||||
check_cursor 2,17
|
||||
|
||||
$TMUX kill-server 2>/dev/null
|
||||
done
|
||||
|
||||
exit 0
|
||||
@@ -199,5 +199,74 @@ 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
|
||||
|
||||
# --- Tiled pane resize with floating cells in the layout ---
|
||||
|
||||
$TMUX set-option -w -u pane-border-lines || exit 1
|
||||
base=$($TMUX display-message -p '#{pane_id}')
|
||||
|
||||
# A floating cell after the last tiled cell must not become the recipient of a
|
||||
# relative or absolute resize. This is the sequence from GitHub issue 5135.
|
||||
floating=$($TMUX new-pane -dPF '#{pane_id}' -t "$base" \
|
||||
-x 50% -y 50% -X 50% -Y 50% 'sleep 100') ||
|
||||
fail "new-pane for tiled resize test failed"
|
||||
lower=$($TMUX split-window -dPF '#{pane_id}' -t "$base" 'sleep 100') ||
|
||||
fail "split-window for tiled resize test failed"
|
||||
|
||||
$TMUX resize-pane -t "$lower" -U 5 || fail "relative tiled resize failed"
|
||||
must_equal "$($TMUX display-message -p -t "$base" '#{pane_height}')" 7
|
||||
must_equal "$($TMUX display-message -p -t "$lower" '#{pane_top}')" 8
|
||||
must_equal "$($TMUX display-message -p -t "$lower" '#{pane_height}')" 16
|
||||
must_equal "$($TMUX display-message -p -t "$floating" '#{pane_top}')" 13
|
||||
must_equal "$($TMUX display-message -p -t "$floating" '#{pane_height}')" 10
|
||||
|
||||
$TMUX resize-pane -t "$lower" -y 11 || fail "absolute tiled reset failed"
|
||||
$TMUX resize-pane -t "$lower" -y 16 || fail "absolute tiled resize failed"
|
||||
must_equal "$($TMUX display-message -p -t "$base" '#{pane_height}')" 7
|
||||
must_equal "$($TMUX display-message -p -t "$lower" '#{pane_top}')" 8
|
||||
must_equal "$($TMUX display-message -p -t "$lower" '#{pane_height}')" 16
|
||||
must_equal "$($TMUX display-message -p -t "$floating" '#{pane_height}')" 10
|
||||
|
||||
$TMUX kill-pane -t "$floating" || exit 1
|
||||
$TMUX kill-pane -t "$lower" || exit 1
|
||||
|
||||
# A floating cell between tiled siblings must be skipped when finding the cell
|
||||
# which donates space to a resize.
|
||||
lower=$($TMUX split-window -dPF '#{pane_id}' -t "$base" 'sleep 100') ||
|
||||
fail "split-window for middle floating cell test failed"
|
||||
floating=$($TMUX new-pane -dPF '#{pane_id}' -t "$base" \
|
||||
-x 20 -y 8 -X 30 -Y 8 'sleep 100') ||
|
||||
fail "new-pane for middle floating cell test failed"
|
||||
|
||||
$TMUX resize-pane -t "$base" -D 3 || fail "resize past floating cell failed"
|
||||
must_equal "$($TMUX display-message -p -t "$base" '#{pane_height}')" 15
|
||||
must_equal "$($TMUX display-message -p -t "$lower" '#{pane_top}')" 16
|
||||
must_equal "$($TMUX display-message -p -t "$lower" '#{pane_height}')" 8
|
||||
must_equal "$($TMUX display-message -p -t "$floating" '#{pane_height}')" 6
|
||||
|
||||
$TMUX kill-pane -t "$floating" || exit 1
|
||||
$TMUX kill-pane -t "$lower" || exit 1
|
||||
|
||||
# A small floating child must not limit the available tiled space in a nested
|
||||
# layout with a different split direction.
|
||||
lower=$($TMUX split-window -dPF '#{pane_id}' -t "$base" 'sleep 100') ||
|
||||
fail "split-window for nested floating cell test failed"
|
||||
right=$($TMUX split-window -dhPF '#{pane_id}' -t "$lower" 'sleep 100') ||
|
||||
fail "horizontal split for nested floating cell test failed"
|
||||
floating=$($TMUX new-pane -dPF '#{pane_id}' -t "$lower" \
|
||||
-x 20 -y 3 -X 30 -Y 10 'sleep 100') ||
|
||||
fail "new-pane for nested floating cell test failed"
|
||||
|
||||
$TMUX resize-pane -t "$base" -D 3 || fail "nested tiled resize failed"
|
||||
must_equal "$($TMUX display-message -p -t "$base" '#{pane_height}')" 15
|
||||
must_equal "$($TMUX display-message -p -t "$lower" '#{pane_top}')" 16
|
||||
must_equal "$($TMUX display-message -p -t "$lower" '#{pane_height}')" 8
|
||||
must_equal "$($TMUX display-message -p -t "$right" '#{pane_top}')" 16
|
||||
must_equal "$($TMUX display-message -p -t "$right" '#{pane_height}')" 8
|
||||
must_equal "$($TMUX display-message -p -t "$floating" '#{pane_height}')" 1
|
||||
|
||||
$TMUX kill-pane -t "$floating" || exit 1
|
||||
$TMUX kill-pane -t "$right" || exit 1
|
||||
$TMUX kill-pane -t "$lower" || exit 1
|
||||
|
||||
$TMUX kill-server 2>/dev/null
|
||||
exit 0
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: screen-write.c,v 1.288 2026/08/21 09:53:04 nicm Exp $ */
|
||||
/* $OpenBSD: screen-write.c,v 1.290 2026/08/24 15:05:26 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -305,11 +305,13 @@ screen_write_initctx(struct screen_write_ctx *ctx, struct tty_ctx *ttyctx,
|
||||
|
||||
if (~ctx->flags & SCREEN_WRITE_SYNC) {
|
||||
/*
|
||||
* For the active pane, only use synchronized updates if
|
||||
* requested (commands that move the cursor); for other panes,
|
||||
* always use it, since the cursor will have to move.
|
||||
* For the active pane showing its base screen, only use
|
||||
* synchronized updates if requested (commands that move the
|
||||
* cursor); for other panes or a pane in a mode, always use it,
|
||||
* since the cursor will have to move.
|
||||
*/
|
||||
if (ctx->wp != NULL && ctx->wp != ctx->wp->window->active)
|
||||
if (ctx->wp != NULL && (ctx->wp != ctx->wp->window->active ||
|
||||
ctx->wp->screen != &ctx->wp->base))
|
||||
ttyctx->flags |= TTY_CTX_SYNC;
|
||||
else if (is_sync)
|
||||
ttyctx->flags |= TTY_CTX_SYNC;
|
||||
@@ -333,10 +335,18 @@ screen_write_make_list(struct screen *s)
|
||||
void
|
||||
screen_write_free_list(struct screen *s)
|
||||
{
|
||||
u_int y;
|
||||
struct screen_write_cline *cl;
|
||||
struct screen_write_citem *ci, *ci1;
|
||||
u_int y;
|
||||
|
||||
for (y = 0; y < screen_size_y(s); y++)
|
||||
free(s->write_list[y].data);
|
||||
for (y = 0; y < screen_size_y(s); y++) {
|
||||
cl = &s->write_list[y];
|
||||
TAILQ_FOREACH_SAFE(ci, &cl->items, entry, ci1) {
|
||||
TAILQ_REMOVE(&cl->items, ci, entry);
|
||||
screen_write_free_citem(ci);
|
||||
}
|
||||
free(cl->data);
|
||||
}
|
||||
free(s->write_list);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: server-client.c,v 1.505 2026/08/20 09:19:24 nicm Exp $ */
|
||||
/* $OpenBSD: server-client.c,v 1.509 2026/08/28 07:36:01 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -406,7 +406,10 @@ server_client_lost(struct client *c)
|
||||
input_cancel_requests(c);
|
||||
|
||||
free(c->title);
|
||||
free(c->path);
|
||||
free((void *)c->cwd);
|
||||
free(c->exit_session);
|
||||
free(c->exit_message);
|
||||
|
||||
evtimer_del(&c->repeat_timer);
|
||||
evtimer_del(&c->click_timer);
|
||||
@@ -1378,6 +1381,10 @@ server_client_key_callback(struct cmdq_item *item, void *data)
|
||||
TAILQ_EMPTY(&wp->modes))
|
||||
goto forward_key;
|
||||
|
||||
/* Focus events are not keys and cannot be bound. */
|
||||
if (key == KEYC_FOCUS_IN || key == KEYC_FOCUS_OUT)
|
||||
goto forward_key;
|
||||
|
||||
/*
|
||||
* Work out the current key table. If the pane is in a mode, use
|
||||
* the mode table instead of the default key table.
|
||||
@@ -2269,8 +2276,6 @@ server_client_check_exit(struct client *c, int force)
|
||||
proc_send(c->peer, c->exit_msgtype, -1, name, strlen(name) + 1);
|
||||
break;
|
||||
}
|
||||
free(c->exit_session);
|
||||
free(c->exit_message);
|
||||
}
|
||||
|
||||
/* Redraw timer callback. */
|
||||
@@ -2345,7 +2350,7 @@ server_client_check_redraw(struct client *c)
|
||||
|
||||
/* Work out if a redraw is actually needed. */
|
||||
needed = 0;
|
||||
if (c->flags & CLIENT_ALLREDRAWFLAGS)
|
||||
if (c->flags & (CLIENT_ALLREDRAWFLAGS|CLIENT_REDRAWSCROLLBARS))
|
||||
needed = 1;
|
||||
else if (server_client_any_pane_redraw(c))
|
||||
needed = 1;
|
||||
@@ -2371,8 +2376,14 @@ server_client_check_redraw(struct client *c)
|
||||
log_debug("redraw timer started");
|
||||
evtimer_add(&ev, &tv);
|
||||
}
|
||||
if (server_client_any_pane_redraw(c))
|
||||
c->flags |= CLIENT_REDRAWWINDOW;
|
||||
TAILQ_FOREACH(wp, &w->panes, entry) {
|
||||
if (wp->flags & PANE_REDRAW) {
|
||||
c->flags |= CLIENT_REDRAWWINDOW;
|
||||
break;
|
||||
}
|
||||
if (wp->flags & PANE_REDRAWSCROLLBAR)
|
||||
c->flags |= CLIENT_REDRAWSCROLLBARS;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2391,7 +2402,8 @@ server_client_check_redraw(struct client *c)
|
||||
log_debug("%s: redraw pane %%%u", __func__,
|
||||
wp->id);
|
||||
redraw_pane(c, wp);
|
||||
} else if (wp->flags & PANE_REDRAWSCROLLBAR) {
|
||||
} else if ((wp->flags & PANE_REDRAWSCROLLBAR) ||
|
||||
(c->flags & CLIENT_REDRAWSCROLLBARS)) {
|
||||
log_debug("%s: redraw scrollbar %%%u", __func__,
|
||||
wp->id);
|
||||
redraw_pane_scrollbar(c, wp);
|
||||
@@ -2421,7 +2433,8 @@ server_client_check_redraw(struct client *c)
|
||||
* All the redraw flags can now be cleared. Also record how many bytes
|
||||
* were written.
|
||||
*/
|
||||
c->flags &= ~(CLIENT_ALLREDRAWFLAGS|CLIENT_STATUSFORCE);
|
||||
c->flags &= ~(CLIENT_ALLREDRAWFLAGS|CLIENT_REDRAWSCROLLBARS|
|
||||
CLIENT_STATUSFORCE);
|
||||
c->redraw = EVBUFFER_LENGTH(tty->out);
|
||||
log_debug("%s: redraw added %zu bytes", c->name, c->redraw);
|
||||
}
|
||||
|
||||
4
sort.c
4
sort.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: sort.c,v 1.9 2026/06/29 07:45:09 nicm Exp $ */
|
||||
/* $OpenBSD: sort.c,v 1.10 2026/08/25 07:23:30 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2026 Dane Jensen <dhcjensen@gmail.com>
|
||||
@@ -32,7 +32,7 @@ sort_qsort(void *l, u_int len, u_int size, int (*cmp)(const void *,
|
||||
u_int i;
|
||||
void *tmp, **ll;
|
||||
|
||||
if (sort_crit->order == SORT_END)
|
||||
if (len < 2 || sort_crit->order == SORT_END)
|
||||
return;
|
||||
|
||||
if (sort_crit->order == SORT_ORDER) {
|
||||
|
||||
34
tmux.1
34
tmux.1
@@ -1,4 +1,4 @@
|
||||
.\" $OpenBSD: tmux.1,v 1.1158 2026/08/20 09:19:24 nicm Exp $
|
||||
.\" $OpenBSD: tmux.1,v 1.1163 2026/09/01 12:49:49 nicm Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
.\"
|
||||
@@ -14,7 +14,7 @@
|
||||
.\" IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
||||
.\" OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
.\"
|
||||
.Dd $Mdocdate: August 20 2026 $
|
||||
.Dd $Mdocdate: September 1 2026 $
|
||||
.Dt TMUX 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@@ -2208,14 +2208,14 @@ Move to the end of the next word.
|
||||
.Xc
|
||||
Same as
|
||||
.Ic next\-word
|
||||
but use a space alone as the word separator.
|
||||
but treat all non-whitespace characters as part of a word.
|
||||
.It Xo
|
||||
.Ic next\-space\-end
|
||||
(vi: E)
|
||||
.Xc
|
||||
Same as
|
||||
.Ic next\-word\-end
|
||||
but use a space alone as the word separator.
|
||||
but treat all non-whitespace characters as part of a word.
|
||||
.It Xo
|
||||
.Ic other\-end
|
||||
(vi: o)
|
||||
@@ -2289,7 +2289,7 @@ Move to the previous word.
|
||||
.Xc
|
||||
Same as
|
||||
.Ic previous\-word
|
||||
but use a space alone as the word separator.
|
||||
but treat all non-whitespace characters as part of a word.
|
||||
.It Xo
|
||||
.Ic rectangle\-on
|
||||
.Xc
|
||||
@@ -2574,8 +2574,8 @@ Word separators can be customized with the
|
||||
session option.
|
||||
Next word moves to the start of the next word, next word end to the end of the
|
||||
next word and previous word to the start of the previous word.
|
||||
The three next and previous space keys work similarly but use a space alone as
|
||||
the word separator.
|
||||
The three next and previous space keys work similarly but treat all
|
||||
non-whitespace characters as part of a word.
|
||||
Setting
|
||||
.Em word\-separators
|
||||
to the empty string makes next/previous word equivalent to next/previous space.
|
||||
@@ -4754,6 +4754,15 @@ for backspace.
|
||||
Set the number of buffers; as new buffers are added to the top of the stack,
|
||||
old ones are removed from the bottom if necessary to maintain this maximum
|
||||
length.
|
||||
.It Xo Ic clear\-on\-attach
|
||||
.Op Ic on | off
|
||||
.Xc
|
||||
When enabled (the default), the client terminal switches to the alternate
|
||||
screen and clears it when a client is attached.
|
||||
When disabled,
|
||||
.Nm
|
||||
does not enter the alternate screen; instead the existing terminal content is
|
||||
scrolled into the scrollback buffer so it remains accessible.
|
||||
.It Xo Ic command\-alias[]
|
||||
.Ar name=value
|
||||
.Xc
|
||||
@@ -5104,6 +5113,8 @@ Supports
|
||||
title setting.
|
||||
.It usstyle
|
||||
Allows underscore style and colour to be set.
|
||||
.It utf8
|
||||
Supports UTF\-8 output.
|
||||
.El
|
||||
.It Ic terminal\-overrides[] Ar string
|
||||
Allow terminal descriptions read using
|
||||
@@ -5644,6 +5655,11 @@ If set to both, a bell and a message are produced.
|
||||
Sets the session's conception of what characters are considered word
|
||||
separators, for the purposes of the next and previous word commands in
|
||||
copy mode.
|
||||
A space in
|
||||
.Ar string
|
||||
matches any character with the Unicode
|
||||
.Em White_Space
|
||||
property.
|
||||
.El
|
||||
.Pp
|
||||
Available window options are:
|
||||
@@ -7271,7 +7287,10 @@ The following variables are available, where appropriate:
|
||||
.It Li "cursor_very_visible" Ta "" Ta "1 if the cursor is in very visible mode"
|
||||
.It Li "cursor_x" Ta "" Ta "Cursor X position in pane"
|
||||
.It Li "cursor_y" Ta "" Ta "Cursor Y position in pane"
|
||||
.It Li "history_added" Ta "" Ta "Number of lines scrolled into pane history"
|
||||
.It Li "history_bytes" Ta "" Ta "Number of bytes in window history"
|
||||
.It Li "history_collected" Ta "" Ta "Number of oldest pane history lines discarded at the history limit"
|
||||
.It Li "history_generation" Ta "" Ta "Generation incremented when pane history is cleared or reflowed"
|
||||
.It Li "history_limit" Ta "" Ta "Maximum window history lines"
|
||||
.It Li "history_size" Ta "" Ta "Size of history in lines"
|
||||
.It Li "hook" Ta "" Ta "Name of running hook, if any"
|
||||
@@ -7370,6 +7389,7 @@ The following variables are available, where appropriate:
|
||||
.It Li "pane_marked_set" Ta "" Ta "1 if a marked pane is set"
|
||||
.It Li "pane_modal_flag" Ta "" Ta "1 if pane is modal"
|
||||
.It Li "pane_mode" Ta "" Ta "Name of pane mode, if any"
|
||||
.It Li "pane_output_generation" Ta "" Ta "Generation incremented when pane output is processed"
|
||||
.It Li "pane_path" Ta "" Ta "Path of pane (can be set by application)"
|
||||
.It Li "pane_pid" Ta "" Ta "PID of first process in pane"
|
||||
.It Li "pane_pipe" Ta "" Ta "1 if pane is being piped"
|
||||
|
||||
9
tmux.h
9
tmux.h
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: tmux.h,v 1.1429 2026/08/20 09:19:24 nicm Exp $ */
|
||||
/* $OpenBSD: tmux.h,v 1.1433 2026/09/01 12:49:49 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -483,6 +483,7 @@ enum tty_code_code {
|
||||
TTYC_ICH1,
|
||||
TTYC_IL,
|
||||
TTYC_IL1,
|
||||
TTYC_IND,
|
||||
TTYC_INDN,
|
||||
TTYC_INVIS,
|
||||
TTYC_KCBT,
|
||||
@@ -1356,9 +1357,10 @@ struct window_pane {
|
||||
char tty[TTY_NAME_MAX];
|
||||
int status;
|
||||
struct timeval dead_time;
|
||||
struct cmdq_item *wait_item; /* new-pane -W: waiting for pane exit */
|
||||
struct cmdq_item *wait_item;
|
||||
struct spawn_editor_state *editor;
|
||||
|
||||
uint64_t output_generation;
|
||||
time_t last_output_time;
|
||||
time_t last_prompt_time;
|
||||
time_t cmd_start_time;
|
||||
@@ -2279,7 +2281,7 @@ struct client {
|
||||
#define CLIENT_STARTSERVER 0x10000000
|
||||
#define CLIENT_REDRAWMENU 0x20000000
|
||||
#define CLIENT_NOFORK 0x40000000
|
||||
/* 0x80000000ULL unused */
|
||||
#define CLIENT_REDRAWSCROLLBARS 0x80000000ULL
|
||||
#define CLIENT_CONTROL_PAUSEAFTER 0x100000000ULL
|
||||
#define CLIENT_CONTROL_WAITEXIT 0x200000000ULL
|
||||
#define CLIENT_WINDOWSIZECHANGED 0x400000000ULL
|
||||
@@ -4076,6 +4078,7 @@ void session_update_history(struct session *);
|
||||
/* utf8.c */
|
||||
enum utf8_state utf8_towc (const struct utf8_data *, wchar_t *);
|
||||
enum utf8_state utf8_fromwc(wchar_t wc, struct utf8_data *);
|
||||
int utf8_has_whitespace(const struct utf8_data *);
|
||||
void utf8_update_width_cache(void);
|
||||
utf8_char utf8_build_one(u_char);
|
||||
enum utf8_state utf8_from_data(const struct utf8_data *, utf8_char *);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: tty-features.c,v 1.42 2026/08/17 14:47:41 nicm Exp $ */
|
||||
/* $OpenBSD: tty-features.c,v 1.43 2026/08/31 12:41:03 kirill Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2020 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -368,6 +368,13 @@ static const struct tty_feature tty_feature_progressbar = {
|
||||
0
|
||||
};
|
||||
|
||||
/* Terminal supports UTF-8. */
|
||||
static const struct tty_feature tty_feature_utf8 = {
|
||||
"utf8",
|
||||
NULL,
|
||||
0
|
||||
};
|
||||
|
||||
/* Available terminal features. */
|
||||
static const struct tty_feature *const tty_features[] = {
|
||||
&tty_feature_256,
|
||||
@@ -390,7 +397,8 @@ static const struct tty_feature *const tty_features[] = {
|
||||
&tty_feature_strikethrough,
|
||||
&tty_feature_sync,
|
||||
&tty_feature_title,
|
||||
&tty_feature_usstyle
|
||||
&tty_feature_usstyle,
|
||||
&tty_feature_utf8
|
||||
};
|
||||
|
||||
/* Parse features for client. */
|
||||
@@ -473,6 +481,9 @@ tty_feature_present(struct tty_term *term, const char *name)
|
||||
u_int i;
|
||||
char *copy;
|
||||
|
||||
if (strcmp(name, "utf8") == 0)
|
||||
return ((term->tty->client->flags & CLIENT_UTF8) != 0);
|
||||
|
||||
for (i = 0; i < nitems(tty_features); i++) {
|
||||
tf = tty_features[i];
|
||||
if (strcmp(tf->name, name) == 0) {
|
||||
@@ -486,7 +497,8 @@ tty_feature_present(struct tty_term *term, const char *name)
|
||||
* We don't just have the feature flag set. Check if the capabilities
|
||||
* supported by the client are actual set instead.
|
||||
*/
|
||||
if (tf == NULL || strcmp(name, "ignorefkeys") == 0)
|
||||
if (tf == NULL || tf->capabilities == NULL ||
|
||||
strcmp(name, "ignorefkeys") == 0)
|
||||
return (0);
|
||||
if (tf->flags != 0 && (term->flags & tf->flags) != tf->flags)
|
||||
return (0);
|
||||
@@ -534,6 +546,8 @@ tty_apply_features(struct tty_term *term)
|
||||
}
|
||||
}
|
||||
term->flags |= tf->flags;
|
||||
if (tf == &tty_feature_utf8)
|
||||
c->flags |= CLIENT_UTF8;
|
||||
}
|
||||
if ((term->applied_features|feat) == term->applied_features)
|
||||
return (0);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: tty-term.c,v 1.108 2026/08/17 14:47:41 nicm Exp $ */
|
||||
/* $OpenBSD: tty-term.c,v 1.109 2026/08/25 08:37:08 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -111,6 +111,7 @@ static const struct tty_term_code_entry tty_term_codes[] = {
|
||||
[TTYC_ICH] = { TTYCODE_STRING, "ich" },
|
||||
[TTYC_IL1] = { TTYCODE_STRING, "il1" },
|
||||
[TTYC_IL] = { TTYCODE_STRING, "il" },
|
||||
[TTYC_IND] = { TTYCODE_STRING, "ind" },
|
||||
[TTYC_INDN] = { TTYCODE_STRING, "indn" },
|
||||
[TTYC_INVIS] = { TTYCODE_STRING, "invis" },
|
||||
[TTYC_KCBT] = { TTYCODE_STRING, "kcbt" },
|
||||
|
||||
28
tty.c
28
tty.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: tty.c,v 1.479 2026/08/18 09:01:20 nicm Exp $ */
|
||||
/* $OpenBSD: tty.c,v 1.480 2026/08/25 08:37:08 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -337,6 +337,7 @@ tty_start_tty(struct tty *tty)
|
||||
{
|
||||
struct client *c = tty->client;
|
||||
struct termios tio;
|
||||
u_int i;
|
||||
|
||||
setblocking(c->fd, 0);
|
||||
event_add(&tty->event_in, NULL);
|
||||
@@ -352,10 +353,21 @@ tty_start_tty(struct tty *tty)
|
||||
if (tcsetattr(c->fd, TCSANOW, &tio) == 0)
|
||||
tcflush(c->fd, TCOFLUSH);
|
||||
|
||||
tty_putcode(tty, TTYC_SMCUP);
|
||||
|
||||
if (options_get_number(global_options, "clear-on-attach")) {
|
||||
tty_putcode(tty, TTYC_SMCUP);
|
||||
tty_putcode(tty, TTYC_CLEAR);
|
||||
} else {
|
||||
tty_putcode_ii(tty, TTYC_CSR, 0, tty->sy - 1);
|
||||
tty_putcode_ii(tty, TTYC_CUP, 0, tty->sy - 1);
|
||||
if (tty_term_has(tty->term, TTYC_INDN))
|
||||
tty_putcode_i(tty, TTYC_INDN, tty->sy + 1);
|
||||
else if (tty_term_has(tty->term, TTYC_IND)) {
|
||||
for (i = 0; i < tty->sy + 1; i++)
|
||||
tty_putcode(tty, TTYC_IND);
|
||||
} else
|
||||
tty_putcode(tty, TTYC_CLEAR);
|
||||
}
|
||||
tty_putcode(tty, TTYC_SMKX);
|
||||
tty_putcode(tty, TTYC_CLEAR);
|
||||
|
||||
if (tty_acs_needed(tty)) {
|
||||
log_debug("%s: using capabilities for ACS", c->name);
|
||||
@@ -471,7 +483,8 @@ tty_stop_tty(struct tty *tty)
|
||||
tty_raw(tty, tty_term_string(tty->term, TTYC_RMACS));
|
||||
tty_raw(tty, tty_term_string(tty->term, TTYC_SGR0));
|
||||
tty_raw(tty, tty_term_string(tty->term, TTYC_RMKX));
|
||||
tty_raw(tty, tty_term_string(tty->term, TTYC_CLEAR));
|
||||
if (options_get_number(global_options, "clear-on-attach"))
|
||||
tty_raw(tty, tty_term_string(tty->term, TTYC_CLEAR));
|
||||
if (tty->cstyle != SCREEN_CURSOR_DEFAULT) {
|
||||
if (tty_term_has(tty->term, TTYC_SE))
|
||||
tty_raw(tty, tty_term_string(tty->term, TTYC_SE));
|
||||
@@ -496,7 +509,10 @@ tty_stop_tty(struct tty *tty)
|
||||
|
||||
if (tty_use_margin(tty))
|
||||
tty_raw(tty, tty_term_string(tty->term, TTYC_DSMG));
|
||||
tty_raw(tty, tty_term_string(tty->term, TTYC_RMCUP));
|
||||
if (options_get_number(global_options, "clear-on-attach"))
|
||||
tty_raw(tty, tty_term_string(tty->term, TTYC_RMCUP));
|
||||
else
|
||||
tty_raw(tty, tty_term_string(tty->term, TTYC_CLEAR));
|
||||
|
||||
if (tty->term->flags & TERM_VT100LIKE)
|
||||
tty_raw(tty, "\033[?2031l");
|
||||
|
||||
68
utf8.c
68
utf8.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: utf8.c,v 1.71 2026/05/12 09:37:25 nicm Exp $ */
|
||||
/* $OpenBSD: utf8.c,v 1.72 2026/09/01 12:49:49 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -603,6 +603,72 @@ utf8_towc(const struct utf8_data *ud, wchar_t *wc)
|
||||
return (UTF8_DONE);
|
||||
}
|
||||
|
||||
/* Check for a Unicode whitespace character. */
|
||||
int
|
||||
utf8_has_whitespace(const struct utf8_data *ud)
|
||||
{
|
||||
struct utf8_data tmp;
|
||||
wchar_t wc;
|
||||
u_int offset = 0, size;
|
||||
u_char ch;
|
||||
|
||||
while (offset < ud->size) {
|
||||
ch = ud->data[offset];
|
||||
if (ch < 0x80) {
|
||||
wc = ch;
|
||||
size = 1;
|
||||
} else {
|
||||
if (ch >= 0xc2 && ch <= 0xdf)
|
||||
size = 2;
|
||||
else if (ch >= 0xe0 && ch <= 0xef)
|
||||
size = 3;
|
||||
else if (ch >= 0xf0 && ch <= 0xf4)
|
||||
size = 4;
|
||||
else
|
||||
return (0);
|
||||
if (size > ud->size - offset)
|
||||
return (0);
|
||||
|
||||
memset(&tmp, 0, sizeof tmp);
|
||||
memcpy(tmp.data, ud->data + offset, size);
|
||||
tmp.size = tmp.have = size;
|
||||
if (utf8_towc(&tmp, &wc) != UTF8_DONE)
|
||||
return (0);
|
||||
}
|
||||
offset += size;
|
||||
|
||||
switch (wc) {
|
||||
case 0x0009:
|
||||
case 0x000A:
|
||||
case 0x000B:
|
||||
case 0x000C:
|
||||
case 0x000D:
|
||||
case 0x0020:
|
||||
case 0x0085:
|
||||
case 0x00A0:
|
||||
case 0x1680:
|
||||
case 0x2000:
|
||||
case 0x2001:
|
||||
case 0x2002:
|
||||
case 0x2003:
|
||||
case 0x2004:
|
||||
case 0x2005:
|
||||
case 0x2006:
|
||||
case 0x2007:
|
||||
case 0x2008:
|
||||
case 0x2009:
|
||||
case 0x200A:
|
||||
case 0x2028:
|
||||
case 0x2029:
|
||||
case 0x202F:
|
||||
case 0x205F:
|
||||
case 0x3000:
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Convert wide character to UTF-8 character. */
|
||||
enum utf8_state
|
||||
utf8_fromwc(wchar_t wc, struct utf8_data *ud)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: window-buffer.c,v 1.51 2026/07/15 12:45:39 nicm Exp $ */
|
||||
/* $OpenBSD: window-buffer.c,v 1.52 2026/08/24 21:19:40 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -567,9 +567,7 @@ window_buffer_edit_close_cb(char *buf, size_t len, void *arg)
|
||||
}
|
||||
|
||||
oldbuf = paste_buffer_data(pb, &oldlen);
|
||||
if (oldlen != '\0' &&
|
||||
oldbuf[oldlen - 1] != '\n' &&
|
||||
buf[len - 1] == '\n')
|
||||
if (oldlen != 0 && oldbuf[oldlen - 1] != '\n' && buf[len - 1] == '\n')
|
||||
len--;
|
||||
if (len != 0)
|
||||
paste_replace(pb, buf, len);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: window-client.c,v 1.48 2026/08/05 08:54:56 nicm Exp $ */
|
||||
/* $OpenBSD: window-client.c,v 1.49 2026/08/31 12:41:03 kirill Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -102,7 +102,8 @@ static const char *window_client_info_lines[] = {
|
||||
WINDOW_CLIENT_FEATURE(sync) " "
|
||||
WINDOW_CLIENT_FEATURE(title),
|
||||
" #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
WINDOW_CLIENT_FEATURE(usstyle),
|
||||
WINDOW_CLIENT_FEATURE(usstyle) " "
|
||||
WINDOW_CLIENT_FEATURE(utf8),
|
||||
"#[#{E:tree-mode-border-style},acs]qqqqqqqqqqqqqqn#{R:q,#{window_width}}#[default]",
|
||||
|
||||
"#[fg=themelightgrey]prefix #[#{E:tree-mode-border-style},acs]x#[default] "
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: window-copy.c,v 1.426 2026/08/19 19:55:04 nicm Exp $ */
|
||||
/* $OpenBSD: window-copy.c,v 1.429 2026/09/01 13:04:29 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -2207,15 +2207,76 @@ window_copy_cmd_selection_mode(struct window_copy_cmd_state *cs)
|
||||
struct window_mode_entry *wme = cs->wme;
|
||||
struct options *so = cs->s->options;
|
||||
struct window_copy_mode_data *data = wme->data;
|
||||
struct grid_reader gr;
|
||||
const char *s = args_string(cs->wargs, 0);
|
||||
u_int sx, sy, ex, ey, fx, fy, x, y;
|
||||
|
||||
if (s == NULL || strcasecmp(s, "char") == 0 || strcasecmp(s, "c") == 0)
|
||||
data->selflag = SEL_CHAR;
|
||||
else if (strcasecmp(s, "word") == 0 || strcasecmp(s, "w") == 0) {
|
||||
data->separators = options_get_string(so, "word-separators");
|
||||
data->selflag = SEL_WORD;
|
||||
} else if (strcasecmp(s, "line") == 0 || strcasecmp(s, "l") == 0)
|
||||
} else if (strcasecmp(s, "line") == 0 || strcasecmp(s, "l") == 0) {
|
||||
data->selflag = SEL_LINE;
|
||||
if (data->screen.sel == NULL)
|
||||
return (WINDOW_COPY_CMD_MOVE);
|
||||
|
||||
/*
|
||||
* Line selection normally starts with select-line, which sets
|
||||
* up the reset positions used when the cursor changes
|
||||
* direction. Do the same when changing an existing selection
|
||||
* to line mode.
|
||||
*/
|
||||
if (data->cursordrag == CURSORDRAG_SEL) {
|
||||
fx = data->endselx;
|
||||
fy = data->endsely;
|
||||
} else {
|
||||
fx = data->selx;
|
||||
fy = data->sely;
|
||||
}
|
||||
|
||||
sx = data->selx;
|
||||
sy = data->sely;
|
||||
ex = data->endselx;
|
||||
ey = data->endsely;
|
||||
if (ey < sy || (ey == sy && ex < sx)) {
|
||||
x = sx; sx = ex; ex = x;
|
||||
y = sy; sy = ey; ey = y;
|
||||
}
|
||||
grid_reader_start(&gr, data->backing->grid, sx, sy);
|
||||
grid_reader_cursor_start_of_line(&gr, 1);
|
||||
grid_reader_get_cursor(&gr, &sx, &sy);
|
||||
grid_reader_start(&gr, data->backing->grid, ex, ey);
|
||||
grid_reader_cursor_end_of_line(&gr, 1, 0);
|
||||
grid_reader_get_cursor(&gr, &ex, &ey);
|
||||
|
||||
data->rectflag = 0;
|
||||
data->selrx = data->selx = sx;
|
||||
data->selry = data->sely = sy;
|
||||
data->endselrx = data->endselx = ex;
|
||||
data->endselry = data->endsely = ey;
|
||||
|
||||
x = data->cx;
|
||||
y = screen_hsize(data->backing) + data->cy - data->oy;
|
||||
data->dx = fx;
|
||||
data->dy = fy;
|
||||
if (data->cursordrag != CURSORDRAG_NONE &&
|
||||
(y < fy || (y == fy && x < fx))) {
|
||||
data->lineflag = LINE_SEL_RIGHT_LEFT;
|
||||
data->cursordrag = CURSORDRAG_SEL;
|
||||
window_copy_scroll_to(wme, sx, sy, 1);
|
||||
} else {
|
||||
data->lineflag = LINE_SEL_LEFT_RIGHT;
|
||||
if (data->cursordrag != CURSORDRAG_NONE) {
|
||||
data->cursordrag = CURSORDRAG_ENDSEL;
|
||||
x = window_copy_cursor_limit(wme, ey, 0);
|
||||
window_copy_scroll_to(wme, x, ey, 1);
|
||||
}
|
||||
}
|
||||
if (data->cursordrag == CURSORDRAG_NONE)
|
||||
window_copy_set_selection(wme, 0, 0);
|
||||
return (WINDOW_COPY_CMD_REDRAW);
|
||||
}
|
||||
return (WINDOW_COPY_CMD_MOVE);
|
||||
}
|
||||
|
||||
@@ -4301,7 +4362,7 @@ window_copy_stringify(struct grid *gd, u_int py, u_int first, u_int last,
|
||||
}
|
||||
if (dlen == 1)
|
||||
buf[bx++] = *d;
|
||||
else {
|
||||
else if (dlen != 0) {
|
||||
memcpy(buf + bx, d, dlen);
|
||||
bx += dlen;
|
||||
}
|
||||
@@ -4851,6 +4912,8 @@ window_copy_search_marks(struct window_mode_entry *wme, struct screen *ssp,
|
||||
cflags |= REG_ICASE;
|
||||
if (regcomp(®, sbuf, cflags) != 0) {
|
||||
free(sbuf);
|
||||
free(data->searchmark);
|
||||
data->searchmark = NULL;
|
||||
return (0);
|
||||
}
|
||||
free(sbuf);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: window-panes.c,v 1.4 2026/07/29 14:06:32 nicm Exp $ */
|
||||
/* $OpenBSD: window-panes.c,v 1.5 2026/08/25 06:04:33 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2026 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -1009,6 +1009,7 @@ window_panes_run_command(struct window_panes_modedata *data, struct client *c,
|
||||
} else {
|
||||
new_item = cmdq_get_command(cmdlist, NULL);
|
||||
cmdq_append(c, new_item);
|
||||
cmd_list_free(cmdlist);
|
||||
}
|
||||
free(expanded);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: window-switch.c,v 1.2 2026/07/14 17:17:18 nicm Exp $ */
|
||||
/* $OpenBSD: window-switch.c,v 1.3 2026/08/25 07:23:30 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2026 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -227,7 +227,8 @@ window_switch_build(struct window_switch_modedata *data)
|
||||
m = xreallocarray(m, n + 1, sizeof *m);
|
||||
m[n++] = item;
|
||||
}
|
||||
qsort(m, n, sizeof *m, window_switch_compare);
|
||||
if (n > 1)
|
||||
qsort(m, n, sizeof *m, window_switch_compare);
|
||||
|
||||
free(data->matches);
|
||||
data->matches = m;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: window-tree.c,v 1.94 2026/07/14 17:17:18 nicm Exp $ */
|
||||
/* $OpenBSD: window-tree.c,v 1.96 2026/08/25 07:23:30 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2017 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -642,6 +642,7 @@ window_tree_draw_session(struct window_tree_modedata *data, struct session *s,
|
||||
}
|
||||
free(label);
|
||||
}
|
||||
format_free(ft);
|
||||
|
||||
if (loop != end - 1) {
|
||||
screen_write_cursormove(ctx, cx + offset + width, cy,
|
||||
@@ -790,6 +791,7 @@ window_tree_draw_window(struct window_tree_modedata *data, struct session *s,
|
||||
}
|
||||
free(label);
|
||||
}
|
||||
format_free(ft);
|
||||
|
||||
if (loop != end - 1) {
|
||||
screen_write_cursormove(ctx, cx + offset + width, cy,
|
||||
@@ -1020,6 +1022,10 @@ window_tree_swap(void *cur_itemdata, void *other_itemdata,
|
||||
window_tree_pull_item(other, &other_session, &other_winlink,
|
||||
&other_pane);
|
||||
|
||||
if (cur_session == NULL || cur_winlink == NULL)
|
||||
return (0);
|
||||
if (other_session == NULL || other_winlink == NULL)
|
||||
return (0);
|
||||
if (cur_session != other_session)
|
||||
return (0);
|
||||
|
||||
|
||||
8
window.c
8
window.c
@@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: window.c,v 1.370 2026/08/20 09:19:24 nicm Exp $ */
|
||||
/* $OpenBSD: window.c,v 1.373 2026/08/24 21:17:19 nicm Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
|
||||
@@ -1477,6 +1477,8 @@ window_pane_scrollbar_overlay_visible(struct window_pane *wp)
|
||||
void
|
||||
window_pane_scrollbar_redraw(struct window_pane *wp)
|
||||
{
|
||||
if (!window_pane_scrollbar_visible(wp))
|
||||
return;
|
||||
if (window_pane_scrollbar_overlay_visible(wp)) {
|
||||
wp->flags |= PANE_REDRAW;
|
||||
return;
|
||||
@@ -1544,16 +1546,16 @@ window_pane_free(struct window_pane *wp)
|
||||
log_debug("pane %%%u freed (%d references)", wp->id, wp->references);
|
||||
|
||||
free(wp->searchstr);
|
||||
|
||||
screen_free(&wp->status_screen);
|
||||
screen_free(&wp->base);
|
||||
|
||||
free(wp->r.ranges);
|
||||
options_free(wp->options);
|
||||
free((void *)wp->cwd);
|
||||
free(wp->shell);
|
||||
cmd_free_argv(wp->argc, wp->argv);
|
||||
colour_palette_free(&wp->palette);
|
||||
style_ranges_free(&wp->border_status_line.ranges);
|
||||
free(wp->border_status_line.expanded);
|
||||
free(wp);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user