Merge branch 'master' into floating_panes

This commit is contained in:
Nicholas Marriott
2026-05-18 11:10:09 +01:00
14 changed files with 347 additions and 258 deletions

View File

@@ -70,12 +70,6 @@ const struct cmd_entry cmd_split_window_entry = {
.exec = cmd_split_window_exec .exec = cmd_split_window_exec
}; };
enum new_pane_mode {
FLOATING,
TILED,
NONE,
};
static struct layout_cell * static struct layout_cell *
cmd_split_window_get_floating_layout_cell(struct cmdq_item *item, cmd_split_window_get_floating_layout_cell(struct cmdq_item *item,
struct args *args, struct window *w) struct args *args, struct window *w)
@@ -163,53 +157,23 @@ cmd_split_window_get_tiled_layout_cell(struct cmdq_item *item,
struct layout_cell *lc = NULL; struct layout_cell *lc = NULL;
char *cause = NULL; char *cause = NULL;
int size; int size;
u_int curval = 0;
if (wp->flags & PANE_FLOATING) { if (wp->flags & PANE_FLOATING) {
cmdq_error(item, "can't split a floating pane"); cmdq_error(item, "can't split a floating pane");
return (NULL); return (NULL);
} }
type = LAYOUT_TOPBOTTOM; if (window_pane_tile_geometry(w, wp, &size, &flags, &type, item, args,
if (args_has(args, 'h')) &cause) != 0) {
type = LAYOUT_LEFTRIGHT; cmdq_error(item, "invalid tiled geometry %s", cause);
/* If the 'p' flag is dropped then this bit can be moved into 'l'. */
if (args_has(args, 'l') || args_has(args, 'p')) {
if (args_has(args, 'f')) {
if (type == LAYOUT_TOPBOTTOM)
curval = w->sy;
else
curval = w->sx;
} else {
if (type == LAYOUT_TOPBOTTOM)
curval = wp->sy;
else
curval = wp->sx;
}
}
size = -1;
if (args_has(args, 'l')) {
size = args_percentage_and_expand(args, 'l', 0, INT_MAX, curval,
item, &cause);
} else if (args_has(args, 'p')) {
size = args_strtonum_and_expand(args, 'p', 0, 100, item,
&cause);
if (cause == NULL)
size = curval * size / 100;
}
if (cause != NULL) {
cmdq_error(item, "size %s", cause);
free(cause); free(cause);
return (NULL); return (NULL);
} }
window_push_zoom(wp->window, 1, args_has(args, 'Z')); window_push_zoom(wp->window, 1, args_has(args, 'Z'));
lc = layout_split_pane(wp, type, size, flags); lc = layout_split_pane(wp, type, size, flags);
if (lc == NULL) if (lc == NULL)
cmdq_error(item, "no space for new pane"); cmdq_error(item, "no space for new pane");
return (lc); return (lc);
} }
@@ -232,7 +196,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
char *cause = NULL, *cp; char *cause = NULL, *cp;
struct args_value *av; struct args_value *av;
u_int count = args_count(args); u_int count = args_count(args);
enum new_pane_mode pane_mode = NONE; enum { FLOATING, TILED, NONE } pane_mode;
if (args_has(args, 'M')) { if (args_has(args, 'M')) {
if (strcasecmp(args_get(args, 'M'), "f") == 0) if (strcasecmp(args_get(args, 'M'), "f") == 0)
@@ -250,7 +214,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
input = (args_has(args, 'I') && count == 0); input = (args_has(args, 'I') && count == 0);
flags = pane_mode == FLOATING ? SPAWN_FLOATING : 0; flags = (pane_mode == FLOATING) ? SPAWN_FLOATING : 0;
if (args_has(args, 'b')) if (args_has(args, 'b'))
flags |= SPAWN_BEFORE; flags |= SPAWN_BEFORE;
if (args_has(args, 'f')) if (args_has(args, 'f'))
@@ -258,13 +222,12 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
if (input || (count == 1 && *args_string(args, 0) == '\0')) if (input || (count == 1 && *args_string(args, 0) == '\0'))
flags |= SPAWN_EMPTY; flags |= SPAWN_EMPTY;
if (pane_mode == FLOATING) if (pane_mode == FLOATING)
lc = cmd_split_window_get_floating_layout_cell(item, args, w); lc = cmd_split_window_get_floating_layout_cell(item, args, w);
else if (pane_mode == TILED) else if (pane_mode == TILED) {
lc = cmd_split_window_get_tiled_layout_cell(item, args, w, wp, lc = cmd_split_window_get_tiled_layout_cell(item, args, w, wp,
flags); flags);
else { } else {
cmdq_error(item, "unrecognized pane mode '%s'", cmdq_error(item, "unrecognized pane mode '%s'",
args_get(args, 'M')); args_get(args, 'M'));
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
@@ -315,7 +278,8 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
} }
options_set_string(new_wp->options, "window-active-style", 0, options_set_string(new_wp->options, "window-active-style", 0,
"%s", style); "%s", style);
new_wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED|PANE_THEMECHANGED); new_wp->flags |= (PANE_REDRAW|PANE_STYLECHANGED|
PANE_THEMECHANGED);
} }
style = args_get(args, 'S'); style = args_get(args, 'S');
if (style != NULL) { if (style != NULL) {
@@ -329,7 +293,8 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
if (style != NULL) { if (style != NULL) {
if (options_set_string(new_wp->options, "pane-border-style", 0, if (options_set_string(new_wp->options, "pane-border-style", 0,
"%s", style) == NULL) { "%s", style) == NULL) {
cmdq_error(item, "bad inactive border style: %s", style); cmdq_error(item, "bad inactive border style: %s",
style);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} }

8
file.c
View File

@@ -399,6 +399,10 @@ file_read(struct client *c, const char *path, client_file_cb cb, void *cbdata)
} }
for (;;) { for (;;) {
size = fread(buffer, 1, sizeof buffer, f); size = fread(buffer, 1, sizeof buffer, f);
if (ferror(f)) {
cf->error = errno;
goto done;
}
if (evbuffer_add(cf->buffer, buffer, size) != 0) { if (evbuffer_add(cf->buffer, buffer, size) != 0) {
cf->error = ENOMEM; cf->error = ENOMEM;
goto done; goto done;
@@ -671,7 +675,7 @@ file_write_close(struct client_files *files, struct imsg *imsg)
/* Client file read error callback. */ /* Client file read error callback. */
static void static void
file_read_error_callback(__unused struct bufferevent *bev, __unused short what, file_read_error_callback(__unused struct bufferevent *bev, short what,
void *arg) void *arg)
{ {
struct client_file *cf = arg; struct client_file *cf = arg;
@@ -680,7 +684,7 @@ file_read_error_callback(__unused struct bufferevent *bev, __unused short what,
log_debug("read error file %d", cf->stream); log_debug("read error file %d", cf->stream);
msg.stream = cf->stream; msg.stream = cf->stream;
msg.error = 0; msg.error = (what & EVBUFFER_ERROR) ? EIO : 0;
proc_send(cf->peer, MSG_READ_DONE, -1, &msg, sizeof msg); proc_send(cf->peer, MSG_READ_DONE, -1, &msg, sizeof msg);
bufferevent_free(cf->event); bufferevent_free(cf->event);

View File

@@ -2059,8 +2059,10 @@ format_cb_pane_at_right(struct format_tree *ft)
static void * static void *
format_cb_pane_bottom(struct format_tree *ft) format_cb_pane_bottom(struct format_tree *ft)
{ {
if (ft->wp != NULL) struct window_pane *wp = ft->wp;
return (format_printf("%d", ft->wp->yoff + (int)ft->wp->sy - 1));
if (wp != NULL)
return (format_printf("%d", wp->yoff + (int)wp->sy - 1));
return (NULL); return (NULL);
} }
@@ -2357,8 +2359,10 @@ format_cb_pane_pb_state(struct format_tree *ft)
static void * static void *
format_cb_pane_right(struct format_tree *ft) format_cb_pane_right(struct format_tree *ft)
{ {
if (ft->wp != NULL) struct window_pane *wp = ft->wp;
return (format_printf("%d", ft->wp->xoff + (int)ft->wp->sx - 1));
if (wp != NULL)
return (format_printf("%d", wp->xoff + (int)wp->sx - 1));
return (NULL); return (NULL);
} }

View File

@@ -45,15 +45,20 @@ grid_reader_line_length(struct grid_reader *gr)
/* Move cursor forward one position. */ /* Move cursor forward one position. */
void void
grid_reader_cursor_right(struct grid_reader *gr, int wrap, int all) grid_reader_cursor_right(struct grid_reader *gr, int wrap, int all, int onemore)
{ {
u_int px; u_int px;
struct grid_cell gc; struct grid_cell gc;
if (all) if (all)
px = gr->gd->sx; px = gr->gd->sx;
else else if (onemore)
px = grid_reader_line_length(gr); px = grid_reader_line_length(gr);
else {
px = grid_reader_line_length(gr);
if (px != 0)
px--;
}
if (wrap && gr->cx >= px && gr->cy < gr->gd->hsize + gr->gd->sy - 1) { if (wrap && gr->cx >= px && gr->cy < gr->gd->hsize + gr->gd->sy - 1) {
grid_reader_cursor_start_of_line(gr, 0); grid_reader_cursor_start_of_line(gr, 0);

View File

@@ -62,29 +62,26 @@ char *
layout_dump(struct window *w, struct layout_cell *root) layout_dump(struct window *w, struct layout_cell *root)
{ {
char layout[8192], *out; char layout[8192], *out;
int braket; int bracket = 0;
struct window_pane *wp; struct window_pane *wp;
*layout = '\0'; *layout = '\0';
if (layout_append(root, layout, sizeof layout) != 0) if (layout_append(root, layout, sizeof layout) != 0)
return (NULL); return (NULL);
braket = 0;
TAILQ_FOREACH(wp, &w->z_index, zentry) { TAILQ_FOREACH(wp, &w->z_index, zentry) {
if (~wp->flags & PANE_FLOATING) if (~wp->flags & PANE_FLOATING)
break; break;
if (!braket) { if (!bracket) {
strcat(layout, "<"); strlcat(layout, "<", sizeof layout);
braket = 1; bracket = 1;
} }
if (layout_append(wp->layout_cell, layout, sizeof layout) != 0) if (layout_append(wp->layout_cell, layout, sizeof layout) != 0)
return (NULL); return (NULL);
strcat(layout, ","); strlcat(layout, ",", sizeof layout);
} }
if (braket) { if (bracket)
/* Overwrite the trailing ','. */
layout[strlen(layout) - 1] = '>'; layout[strlen(layout) - 1] = '>';
}
xasprintf(&out, "%04hx,%s", layout_checksum(layout), layout); xasprintf(&out, "%04hx,%s", layout_checksum(layout), layout);
return (out); return (out);
@@ -146,8 +143,8 @@ layout_check(struct layout_cell *lc)
u_int n = 0; u_int n = 0;
switch (lc->type) { switch (lc->type) {
case LAYOUT_WINDOWPANE:
case LAYOUT_FLOATING: case LAYOUT_FLOATING:
case LAYOUT_WINDOWPANE:
break; break;
case LAYOUT_LEFTRIGHT: case LAYOUT_LEFTRIGHT:
TAILQ_FOREACH(lcchild, &lc->cells, entry) { TAILQ_FOREACH(lcchild, &lc->cells, entry) {
@@ -213,10 +210,11 @@ layout_parse(struct window *w, const char *layout, char **cause)
} }
/* Check this window will fit into the layout. */ /* Check this window will fit into the layout. */
npanes = window_count_panes(w, 1);
for (;;) { for (;;) {
npanes = window_count_panes(w, 1);
ncells = layout_count_cells(tiled_lc); ncells = layout_count_cells(tiled_lc);
ncells += layout_count_cells(floating_lc); if (floating_lc != NULL)
ncells += layout_count_cells(floating_lc);
if (npanes > ncells) { if (npanes > ncells) {
/* Modify this to open a new pane */ /* Modify this to open a new pane */
xasprintf(cause, "have %u panes but need %u", npanes, xasprintf(cause, "have %u panes but need %u", npanes,
@@ -228,9 +226,9 @@ layout_parse(struct window *w, const char *layout, char **cause)
/* /*
* Fewer panes than cells - close floating panes first * Fewer panes than cells - close floating panes first
* then close the bottom right until. * then close the bottom right until none remain.
*/ */
if (floating_lc && ! TAILQ_EMPTY(&floating_lc->cells)) { if (floating_lc != NULL && !TAILQ_EMPTY(&floating_lc->cells)) {
lcchild = TAILQ_FIRST(&floating_lc->cells); lcchild = TAILQ_FIRST(&floating_lc->cells);
layout_destroy_cell(w, lcchild, &floating_lc); layout_destroy_cell(w, lcchild, &floating_lc);
} else { } else {
@@ -266,8 +264,6 @@ layout_parse(struct window *w, const char *layout, char **cause)
} }
if (tiled_lc->type != LAYOUT_WINDOWPANE && if (tiled_lc->type != LAYOUT_WINDOWPANE &&
(tiled_lc->sx != sx || tiled_lc->sy != sy)) { (tiled_lc->sx != sx || tiled_lc->sy != sy)) {
log_debug("fix layout %u,%u to %u,%u", tiled_lc->sx,
tiled_lc->sy, sx,sy);
layout_print_cell(tiled_lc, __func__, 0); layout_print_cell(tiled_lc, __func__, 0);
tiled_lc->sx = sx - 1; tiled_lc->sy = sy - 1; tiled_lc->sx = sx - 1; tiled_lc->sy = sy - 1;
} }
@@ -288,27 +284,29 @@ layout_parse(struct window *w, const char *layout, char **cause)
/* Assign the panes into the cells. */ /* Assign the panes into the cells. */
wp = TAILQ_FIRST(&w->panes); wp = TAILQ_FIRST(&w->panes);
layout_assign(&wp, tiled_lc, 0); if (tiled_lc != NULL)
layout_assign(&wp, floating_lc, 1); layout_assign(&wp, tiled_lc, 0);
if (floating_lc != NULL)
layout_assign(&wp, floating_lc, PANE_FLOATING);
/* Fix z_indexes. */ /* Fix z indexes. */
while (!TAILQ_EMPTY(&w->z_index)) { while (!TAILQ_EMPTY(&w->z_index)) {
wp = TAILQ_FIRST(&w->z_index); wp = TAILQ_FIRST(&w->z_index);
TAILQ_REMOVE(&w->z_index, wp, zentry); TAILQ_REMOVE(&w->z_index, wp, zentry);
} }
layout_fix_zindexes(w, floating_lc); if (floating_lc != NULL)
layout_fix_zindexes(w, floating_lc);
layout_fix_zindexes(w, tiled_lc); layout_fix_zindexes(w, tiled_lc);
/* Update pane offsets and sizes. */ /* Update pane offsets and sizes. */
layout_fix_offsets(w); layout_fix_offsets(w);
layout_fix_panes(w, NULL); layout_fix_panes(w, NULL);
recalculate_sizes(); recalculate_sizes();
layout_print_cell(tiled_lc, __func__, 0); layout_print_cell(tiled_lc, __func__, 0);
layout_print_cell(floating_lc, __func__, 0);
/* Free the floating layout cell, no longer needed. */ /* Free the floating layout cell, no longer needed. */
layout_free_cell(floating_lc); if (floating_lc != NULL)
layout_free_cell(floating_lc);
notify_window("window-layout-changed", w); notify_window("window-layout-changed", w);
@@ -322,7 +320,7 @@ fail:
/* Assign panes into cells. */ /* Assign panes into cells. */
static void static void
layout_assign(struct window_pane **wp, struct layout_cell *lc, int floating) layout_assign(struct window_pane **wp, struct layout_cell *lc, int flags)
{ {
struct layout_cell *lcchild; struct layout_cell *lcchild;
@@ -332,16 +330,14 @@ layout_assign(struct window_pane **wp, struct layout_cell *lc, int floating)
switch (lc->type) { switch (lc->type) {
case LAYOUT_WINDOWPANE: case LAYOUT_WINDOWPANE:
layout_make_leaf(lc, *wp); layout_make_leaf(lc, *wp);
if (floating) { (*wp)->flags |= flags;
(*wp)->flags |= PANE_FLOATING;
}
*wp = TAILQ_NEXT(*wp, entry); *wp = TAILQ_NEXT(*wp, entry);
return; return;
case LAYOUT_LEFTRIGHT: case LAYOUT_LEFTRIGHT:
case LAYOUT_TOPBOTTOM: case LAYOUT_TOPBOTTOM:
case LAYOUT_FLOATING: case LAYOUT_FLOATING:
TAILQ_FOREACH(lcchild, &lc->cells, entry) TAILQ_FOREACH(lcchild, &lc->cells, entry)
layout_assign(wp, lcchild, 1); layout_assign(wp, lcchild, PANE_FLOATING);
return; return;
} }
} }
@@ -394,7 +390,6 @@ layout_construct_cell(struct layout_cell *lcparent, const char **layout)
return (lc); return (lc);
} }
/* /*
* Given a character string layout, recursively construct cells. * Given a character string layout, recursively construct cells.
* Possible return values: * Possible return values:

View File

@@ -50,6 +50,7 @@ static struct layout_cell *layout_active_neighbour(struct layout_cell *, int);
void layout_redistribute_cells(struct window *, struct layout_cell *, void layout_redistribute_cells(struct window *, struct layout_cell *,
enum layout_type); enum layout_type);
/* Create a new layout cell. */
struct layout_cell * struct layout_cell *
layout_create_cell(struct layout_cell *lcparent) layout_create_cell(struct layout_cell *lcparent)
{ {
@@ -72,6 +73,7 @@ layout_create_cell(struct layout_cell *lcparent)
return (lc); return (lc);
} }
/* Free a layout cell. */
void void
layout_free_cell(struct layout_cell *lc) layout_free_cell(struct layout_cell *lc)
{ {
@@ -87,11 +89,11 @@ layout_free_cell(struct layout_cell *lc)
} }
break; break;
case LAYOUT_FLOATING: case LAYOUT_FLOATING:
/* A Floating layout cell is only used temporarily /*
* while select-layout constructs a layout. * A floating layout cell is only used temporarily while
* Cleave the children from the temp layout, then * select-layout constructs a layout. Remove the children from
* free temp floating layout cell. Each floating * the temporary layout, then free temporary floating layout
* pane has stub layout. * cell. Each floating pane has stub layout.
*/ */
while (!TAILQ_EMPTY(&lc->cells)) { while (!TAILQ_EMPTY(&lc->cells)) {
lcchild = TAILQ_FIRST(&lc->cells); lcchild = TAILQ_FIRST(&lc->cells);
@@ -110,6 +112,7 @@ layout_free_cell(struct layout_cell *lc)
free(lc); free(lc);
} }
/* Log a cell. */
void void
layout_print_cell(struct layout_cell *lc, const char *hdr, u_int n) layout_print_cell(struct layout_cell *lc, const char *hdr, u_int n)
{ {
@@ -151,6 +154,7 @@ layout_print_cell(struct layout_cell *lc, const char *hdr, u_int n)
} }
} }
/* Search for a cell by the border position. */
struct layout_cell * struct layout_cell *
layout_search_by_border(struct layout_cell *lc, u_int x, u_int y) layout_search_by_border(struct layout_cell *lc, u_int x, u_int y)
{ {
@@ -192,9 +196,9 @@ layout_search_by_border(struct layout_cell *lc, u_int x, u_int y)
return (NULL); return (NULL);
} }
/* Set cell size. */
void void
layout_set_size(struct layout_cell *lc, u_int sx, u_int sy, int xoff, layout_set_size(struct layout_cell *lc, u_int sx, u_int sy, int xoff, int yoff)
int yoff)
{ {
lc->sx = sx; lc->sx = sx;
lc->sy = sy; lc->sy = sy;
@@ -203,6 +207,7 @@ layout_set_size(struct layout_cell *lc, u_int sx, u_int sy, int xoff,
lc->yoff = yoff; lc->yoff = yoff;
} }
/* Make a cell a leaf cell. */
void void
layout_make_leaf(struct layout_cell *lc, struct window_pane *wp) layout_make_leaf(struct layout_cell *lc, struct window_pane *wp)
{ {
@@ -214,6 +219,7 @@ layout_make_leaf(struct layout_cell *lc, struct window_pane *wp)
lc->wp = wp; lc->wp = wp;
} }
/* Make a cell a node cell. */
void void
layout_make_node(struct layout_cell *lc, enum layout_type type) layout_make_node(struct layout_cell *lc, enum layout_type type)
{ {
@@ -372,7 +378,7 @@ layout_fix_panes(struct window *w, struct window_pane *skip)
sx = lc->sx; sx = lc->sx;
sy = lc->sy; sy = lc->sy;
if (~wp->flags & PANE_FLOATING && if ((~wp->flags & PANE_FLOATING) &&
layout_add_horizontal_border(w, lc, status)) { layout_add_horizontal_border(w, lc, status)) {
if (status == PANE_STATUS_TOP) if (status == PANE_STATUS_TOP)
wp->yoff++; wp->yoff++;
@@ -412,7 +418,7 @@ u_int
layout_count_cells(struct layout_cell *lc) layout_count_cells(struct layout_cell *lc)
{ {
struct layout_cell *lcchild; struct layout_cell *lcchild;
u_int count; u_int count = 0;
switch (lc->type) { switch (lc->type) {
case LAYOUT_WINDOWPANE: case LAYOUT_WINDOWPANE:
@@ -420,7 +426,6 @@ layout_count_cells(struct layout_cell *lc)
case LAYOUT_LEFTRIGHT: case LAYOUT_LEFTRIGHT:
case LAYOUT_TOPBOTTOM: case LAYOUT_TOPBOTTOM:
case LAYOUT_FLOATING: case LAYOUT_FLOATING:
count = 0;
TAILQ_FOREACH(lcchild, &lc->cells, entry) TAILQ_FOREACH(lcchild, &lc->cells, entry)
count += layout_count_cells(lcchild); count += layout_count_cells(lcchild);
return (count); return (count);
@@ -637,6 +642,13 @@ layout_destroy_cell(struct window *w, struct layout_cell *lc,
return; return;
} }
/* A floating cell need only be removed from the parent. */
if (lcparent->type == LAYOUT_FLOATING) {
TAILQ_REMOVE(&lcparent->cells, lc, entry);
layout_free_cell(lc);
return;
}
/* In tiled layouts, merge the space into the previous or next cell. */ /* In tiled layouts, merge the space into the previous or next cell. */
if (lcparent->type != LAYOUT_FLOATING) { if (lcparent->type != LAYOUT_FLOATING) {
is_minimised = (lc->wp != NULL && (lc->wp->flags & PANE_MINIMISED)); is_minimised = (lc->wp != NULL && (lc->wp->flags & PANE_MINIMISED));
@@ -668,12 +680,14 @@ layout_destroy_cell(struct window *w, struct layout_cell *lc,
lc->parent = lcparent->parent; lc->parent = lcparent->parent;
if (lc->parent == NULL) { if (lc->parent == NULL) {
lc->xoff = 0; lc->yoff = 0; lc->xoff = 0;
lc->yoff = 0;
/* /*
* If the sole remaining child is a minimised * If the sole remaining child is a minimised
* WINDOWPANE, its stored size may be stale (it never * WINDOWPANE, its stored size may be stale (it never
* received the space that was given to the removed * received the space that was given to the removed
* cell). Restore the full window size so that * cell). Restore the full window size so that
* unminimise can reclaim the correct amount. * unminimise can reclaim the correct amount.
*/ */
if (lc->type == LAYOUT_WINDOWPANE && if (lc->type == LAYOUT_WINDOWPANE &&
@@ -754,6 +768,7 @@ layout_unminimise_cell(struct window *w, struct layout_cell *lc)
layout_redistribute_cells(w, lcparent, lcparent->type); layout_redistribute_cells(w, lcparent, lcparent->type);
} }
/* Initialize layout for pane. */
void void
layout_init(struct window *w, struct window_pane *wp) layout_init(struct window *w, struct window_pane *wp)
{ {
@@ -765,6 +780,7 @@ layout_init(struct window *w, struct window_pane *wp)
layout_fix_panes(w, NULL); layout_fix_panes(w, NULL);
} }
/* Free layout for pane. */
void void
layout_free(struct window *w) layout_free(struct window *w)
{ {

View File

@@ -1066,6 +1066,7 @@ server_client_is_bracket_paste(struct client *c, key_code key)
{ {
if ((key & KEYC_MASK_KEY) == KEYC_PASTE_START) { if ((key & KEYC_MASK_KEY) == KEYC_PASTE_START) {
c->flags |= CLIENT_BRACKETPASTING; c->flags |= CLIENT_BRACKETPASTING;
c->paste_time = current_time;
log_debug("%s: bracket paste on", c->name); log_debug("%s: bracket paste on", c->name);
return (0); return (0);
} }
@@ -1099,6 +1100,7 @@ server_client_is_assume_paste(struct client *c)
if (c->flags & CLIENT_ASSUMEPASTING) if (c->flags & CLIENT_ASSUMEPASTING)
return (1); return (1);
c->flags |= CLIENT_ASSUMEPASTING; c->flags |= CLIENT_ASSUMEPASTING;
c->paste_time = current_time;
log_debug("%s: assume paste on", c->name); log_debug("%s: assume paste on", c->name);
return (0); return (0);
} }
@@ -2591,6 +2593,13 @@ server_client_dispatch_identify(struct client *c, struct imsg *imsg)
c->out_fd = -1; c->out_fd = -1;
} }
/* If pasting has taken too long, turn it off. */
if (c->flags & (CLIENT_BRACKETPASTING|CLIENT_ASSUMEPASTING) &&
current_time - c->paste_time > CLIENT_PASTE_TIME_LIMIT) {
log_debug("%s: paste time limit exceeded", c->name);
c->flags &= ~(CLIENT_BRACKETPASTING|CLIENT_ASSUMEPASTING);
}
/* /*
* If this is the first client, load configuration files. Any later * If this is the first client, load configuration files. Any later
* clients are allowed to continue with their command even if the * clients are allowed to continue with their command even if the

20
sort.c
View File

@@ -56,8 +56,8 @@ sort_buffer_cmp(const void *a0, const void *b0)
struct sort_criteria *sort_crit = sort_criteria; struct sort_criteria *sort_crit = sort_criteria;
const struct paste_buffer *const *a = a0; const struct paste_buffer *const *a = a0;
const struct paste_buffer *const *b = b0; const struct paste_buffer *const *b = b0;
const struct paste_buffer *pa = *a; const struct paste_buffer *pa = *a;
const struct paste_buffer *pb = *b; const struct paste_buffer *pb = *b;
int result = 0; int result = 0;
switch (sort_crit->order) { switch (sort_crit->order) {
@@ -92,8 +92,8 @@ sort_client_cmp(const void *a0, const void *b0)
struct sort_criteria *sort_crit = sort_criteria; struct sort_criteria *sort_crit = sort_criteria;
const struct client *const *a = a0; const struct client *const *a = a0;
const struct client *const *b = b0; const struct client *const *b = b0;
const struct client *ca = *a; const struct client *ca = *a;
const struct client *cb = *b; const struct client *cb = *b;
int result = 0; int result = 0;
switch (sort_crit->order) { switch (sort_crit->order) {
@@ -425,7 +425,11 @@ sort_get_clients(u_int *n, struct sort_criteria *sort_crit)
i = 0; i = 0;
TAILQ_FOREACH(c, &clients, entry) { TAILQ_FOREACH(c, &clients, entry) {
if (lsz <= i) { if (c->flags & CLIENT_UNATTACHEDFLAGS)
continue;
if (~c->flags & CLIENT_ATTACHED)
continue;
if (lsz <= i) {
lsz += 100; lsz += 100;
l = xreallocarray(l, lsz, sizeof *l); l = xreallocarray(l, lsz, sizeof *l);
} }
@@ -468,7 +472,7 @@ sort_get_panes(u_int *n, struct sort_criteria *sort_crit)
struct winlink *wl; struct winlink *wl;
struct window *w; struct window *w;
struct window_pane *wp; struct window_pane *wp;
u_int i; u_int i;
static struct window_pane **l = NULL; static struct window_pane **l = NULL;
static u_int lsz = 0; static u_int lsz = 0;
@@ -499,7 +503,7 @@ sort_get_panes_session(struct session *s, u_int *n,
struct winlink *wl = NULL; struct winlink *wl = NULL;
struct window *w = NULL; struct window *w = NULL;
struct window_pane *wp = NULL; struct window_pane *wp = NULL;
u_int i; u_int i;
static struct window_pane **l = NULL; static struct window_pane **l = NULL;
static u_int lsz = 0; static u_int lsz = 0;
@@ -526,7 +530,7 @@ sort_get_panes_window(struct window *w, u_int *n,
struct sort_criteria *sort_crit) struct sort_criteria *sort_crit)
{ {
struct window_pane *wp; struct window_pane *wp;
u_int i; u_int i;
static struct window_pane **l = NULL; static struct window_pane **l = NULL;
static u_int lsz = 0; static u_int lsz = 0;

163
tmux.1
View File

@@ -940,6 +940,37 @@ or
.Ic list\-panes .Ic list\-panes
commands. commands.
.Pp .Pp
.Em target\-session ,
.Em target\-window
or
.Em target\-pane
each denote the
.Ql type
of target the command needs to work on.
If a target is not explicitly qualified using
.Ql \&:
and
.Ql \&. ,
.Nm
will pick what seems to be the best choice available.
For example, if a
.Em target-pane
of
.Ql 1
is used with a current window that has only one pane,
.Nm
knows that the
.Ql 1
cannot mean a pane, so it will look for the active pane in window 1, or the
active pane in the current window in session 1.
Only if none of these are present will it report an error.
If it is important that a specific pane, window or session always be used,
such as from a script, the target should be fully qualified (for example a
.Em target-pane
of
.Ql -t:.1 ) ,
or pane, window or session IDs should be used.
.Pp
.Ar shell\-command .Ar shell\-command
arguments are arguments are
.Xr sh 1 .Xr sh 1
@@ -3329,46 +3360,22 @@ but a different format may be specified with
.Tg newp .Tg newp
.It Xo Ic new\-pane .It Xo Ic new\-pane
.Op Fl bdefhIkPvZ .Op Fl bdefhIkPvZ
.Op Fl c Ar start-directory .Op Fl c Ar start\-directory
.Op Fl e Ar environment .Op Fl e Ar environment
.Op Fl F Ar format .Op Fl F Ar format
.Op Fl l Ar size .Op Fl l Ar size
.Op Fl m Ar message .Op Fl m Ar message
.Op Fl M Ar mode
.Op Fl p Ar percentage .Op Fl p Ar percentage
.Op Fl R Ar inactive-border-style .Op Fl R Ar inactive\-border\-style
.Op Fl s Ar style .Op Fl s Ar style
.Op Fl S Ar active-border-style .Op Fl S Ar active\-border\-style
.Op Fl t Ar target-pane .Op Fl t Ar target\-pane
.Op Fl x Ar width .Op Ar shell\-command Op Ar argument ...
.Op Fl X Ar x-position
.Op Fl y Ar height
.Op Fl Y Ar y-position
.Op Ar shell-command Op Ar argument ...
.Xc .Xc
.D1 Pq alias: Ic newp .D1 Pq alias: Ic newp
Create a new pane. Create a new pane.
A The new pane is created by splitting
.Ar mode .Ar target\-pane .
may be specified with the
.Fl M
option and must be followed by one of the following special values:
.Bl -column "XXXXX" -offset indent
.It Sy "Value" Ta Sy "Meaning"
.It Li "f" Ta "floating pane above the current layout"
.It Li "t" Ta "tiled into the layout by splitting a pane"
.El
.Pp
If no
.Ar mode
is specified,
.Ic f
is assumed.
When creating a tiled pane, a target pane may be specified with
.Fl t .
Note that some options will only affect one
.Ar mode .
.Pp
If If
.Fl d .Fl d
is given, the session does not make the new pane the current pane. is given, the session does not make the new pane the current pane.
@@ -3381,48 +3388,7 @@ sets the border style when the pane is active and
.Fl R .Fl R
sets the border style when the pane is inactive (see sets the border style when the pane is inactive (see
.Sx STYLES ) . .Sx STYLES ) .
.Fl k
keeps the pane open after the optional
.Ar shell-command
exits and waits for a keypress (any non-mouse key) before closing it.
The message shown is controlled by the
.Ic remain-on-exit-format
option.
.Fl m Ar message
is equivalent to
.Fl k
but also sets the
.Ic remain-on-exit-format
option for this pane to
.Ar message .
An empty
.Ar shell-command
(\[aq]\[aq]) will create a pane with no command running in it.
The
.Fl I
flag (if
.Ar shell-command
is not specified or empty)
will create an empty pane and forward any output from stdin to it.
For example:
.Bd -literal -offset indent
$ make 2>&1|tmux splitw \-dI &
.Ed
.Pp .Pp
For floating panes, the following options are availible:
The
.Fl x ,
.Fl y ,
.Fl X ,
and
.Fl Y
options set the width, height, and position of the pane.
If not given, the pane is sized to half the window dimensions and offset from
the previous floating pane.
These four options may be followed by '%' to specify a percentage of the
current window dimensions.
.Pp
For tiled panes, the following options are availible:
.Fl h .Fl h
does a horizontal split and does a horizontal split and
.Fl v .Fl v
@@ -3437,6 +3403,8 @@ columns (for horizontal split);
may be followed by may be followed by
.Ql % .Ql %
to specify a percentage of the available space. to specify a percentage of the available space.
.Fl p
is a shorthand option for this.
The The
.Fl b .Fl b
option causes the new pane to be created to the left of or above option causes the new pane to be created to the left of or above
@@ -3449,9 +3417,37 @@ or full window width (with
.Fl v ) , .Fl v ) ,
instead of splitting the active pane. instead of splitting the active pane.
.Pp .Pp
.Fl k
keeps the pane open after the optional
.Ar shell\-command
exits and waits for a key to be pressed before closing it.
The message shown is controlled by the
.Ic remain\-on\-exit\-format
option.
.Fl m Ar message
is equivalent to
.Fl k
but also sets the
.Ic remain\-on\-exit\-format
option for this pane to
.Ar message .
.Pp
An empty
.Ar shell\-command
(\[aq]\[aq]) will create a pane with no command running in it.
The
.Fl I
flag (if
.Ar shell\-command
is not specified or empty)
will create an empty pane and forward any output from stdin to it.
For example:
.Bd -literal -offset indent
$ make 2>&1|tmux splitw \-dI &
.Ed
.Pp
All other options have the same meaning as for the All other options have the same meaning as for the
.Ic new-window .Ic new\-window
command.
.Tg nextl .Tg nextl
.It Ic next\-layout Op Fl t Ar target\-window .It Ic next\-layout Op Fl t Ar target\-window
.D1 Pq alias: Ic nextl .D1 Pq alias: Ic nextl
@@ -3777,26 +3773,21 @@ the command behaves like
.Tg splitw .Tg splitw
.It Xo Ic split\-window .It Xo Ic split\-window
.Op Fl bdefhIkPvZ .Op Fl bdefhIkPvZ
.Op Fl c Ar start-directory .Op Fl c Ar start\-directory
.Op Fl e Ar environment .Op Fl e Ar environment
.Op Fl F Ar format .Op Fl F Ar format
.Op Fl l Ar size .Op Fl l Ar size
.Op Fl m Ar message .Op Fl m Ar message
.Op Fl M Ar mode
.Op Fl p Ar percentage .Op Fl p Ar percentage
.Op Fl R Ar inactive-border-style .Op Fl R Ar inactive\-border\-style
.Op Fl s Ar style .Op Fl s Ar style
.Op Fl S Ar active-border-style .Op Fl S Ar active\-border\-style
.Op Fl t Ar target-pane .Op Fl t Ar target\-pane
.Op Fl x Ar width .Op Ar shell\-command Op Ar argument ...
.Op Fl X Ar x-position
.Op Fl y Ar height
.Op Fl Y Ar y-position
.Op Ar shell-command Op Ar argument ...
.Xc .Xc
.D1 Pq alias: Ic splitw .D1 Pq alias: Ic splitw
Creates a new pane. Creates a new pane by splitting
Default behavior is to split the pane in a tiled layout. .Ar target\-pane .
Shares behavior with Shares behavior with
.Ic new\-pane . .Ic new\-pane .
.Pp .Pp

15
tmux.h
View File

@@ -1347,7 +1347,7 @@ struct window_pane {
TAILQ_ENTRY(window_pane) entry; /* link in list of all panes */ TAILQ_ENTRY(window_pane) entry; /* link in list of all panes */
TAILQ_ENTRY(window_pane) sentry; /* link in list of last visited */ TAILQ_ENTRY(window_pane) sentry; /* link in list of last visited */
TAILQ_ENTRY(window_pane) zentry; /* z-index link in list of all panes */ TAILQ_ENTRY(window_pane) zentry; /* z-index link in list of all panes */
RB_ENTRY(window_pane) tree_entry; RB_ENTRY(window_pane) tree_entry;
}; };
TAILQ_HEAD(window_panes, window_pane); TAILQ_HEAD(window_panes, window_pane);
@@ -1371,7 +1371,7 @@ struct window {
struct window_pane *active; struct window_pane *active;
struct window_panes last_panes; struct window_panes last_panes;
struct window_panes z_index; struct window_panes z_index;
struct window_panes panes; struct window_panes panes;
int lastlayout; int lastlayout;
@@ -2000,6 +2000,9 @@ struct client_window {
}; };
RB_HEAD(client_windows, client_window); RB_HEAD(client_windows, client_window);
/* Maximum time to be pasting. */
#define CLIENT_PASTE_TIME_LIMIT 5
/* Client connection. */ /* Client connection. */
typedef int (*prompt_input_cb)(struct client *, void *, const char *, int); typedef int (*prompt_input_cb)(struct client *, void *, const char *, int);
typedef void (*prompt_free_cb)(void *); typedef void (*prompt_free_cb)(void *);
@@ -2139,6 +2142,7 @@ struct client {
struct key_table *keytable; struct key_table *keytable;
key_code last_key; key_code last_key;
time_t paste_time;
uint64_t redraw_panes; uint64_t redraw_panes;
uint64_t redraw_scrollbars; uint64_t redraw_scrollbars;
@@ -3225,7 +3229,7 @@ void grid_reader_start(struct grid_reader *, struct grid *, u_int, u_int);
void grid_reader_get_cursor(struct grid_reader *, u_int *, u_int *); void grid_reader_get_cursor(struct grid_reader *, u_int *, u_int *);
u_int grid_reader_line_length(struct grid_reader *); u_int grid_reader_line_length(struct grid_reader *);
int grid_reader_in_set(struct grid_reader *, const char *); int grid_reader_in_set(struct grid_reader *, const char *);
void grid_reader_cursor_right(struct grid_reader *, int, int); void grid_reader_cursor_right(struct grid_reader *, int, int, int);
void grid_reader_cursor_left(struct grid_reader *, int); void grid_reader_cursor_left(struct grid_reader *, int);
void grid_reader_cursor_down(struct grid_reader *); void grid_reader_cursor_down(struct grid_reader *);
void grid_reader_cursor_up(struct grid_reader *); void grid_reader_cursor_up(struct grid_reader *);
@@ -3487,6 +3491,9 @@ enum client_theme window_pane_get_theme(struct window_pane *);
void window_pane_send_theme_update(struct window_pane *); void window_pane_send_theme_update(struct window_pane *);
struct style_range *window_pane_border_status_get_range(struct window_pane *, struct style_range *window_pane_border_status_get_range(struct window_pane *,
u_int, u_int); u_int, u_int);
int window_pane_tile_geometry(struct window *,
struct window_pane *, int *, int *, enum layout_type *,
struct cmdq_item *, struct args *, char **);
/* layout.c */ /* layout.c */
u_int layout_count_cells(struct layout_cell *); u_int layout_count_cells(struct layout_cell *);
@@ -3502,7 +3509,7 @@ void layout_redistribute_cells(struct window *, struct layout_cell *,
void layout_resize_layout(struct window *, struct layout_cell *, void layout_resize_layout(struct window *, struct layout_cell *,
enum layout_type, int, int); enum layout_type, int, int);
struct layout_cell *layout_search_by_border(struct layout_cell *, u_int, u_int); struct layout_cell *layout_search_by_border(struct layout_cell *, u_int, u_int);
void layout_set_size(struct layout_cell *, u_int, u_int, int, int); void layout_set_size(struct layout_cell *, u_int, u_int, int, int);
void layout_make_leaf(struct layout_cell *, struct window_pane *); void layout_make_leaf(struct layout_cell *, struct window_pane *);
void layout_make_node(struct layout_cell *, enum layout_type); void layout_make_node(struct layout_cell *, enum layout_type);
void layout_fix_zindexes(struct window *, struct layout_cell *); void layout_fix_zindexes(struct window *, struct layout_cell *);

View File

@@ -29,7 +29,6 @@ enum tty_draw_line_state {
TTY_DRAW_LINE_NEW2, TTY_DRAW_LINE_NEW2,
TTY_DRAW_LINE_EMPTY, TTY_DRAW_LINE_EMPTY,
TTY_DRAW_LINE_SAME, TTY_DRAW_LINE_SAME,
TTY_DRAW_LINE_PAD,
TTY_DRAW_LINE_DONE TTY_DRAW_LINE_DONE
}; };
static const char* tty_draw_line_states[] = { static const char* tty_draw_line_states[] = {
@@ -39,7 +38,6 @@ static const char* tty_draw_line_states[] = {
"NEW2", "NEW2",
"EMPTY", "EMPTY",
"SAME", "SAME",
"PAD",
"DONE" "DONE"
}; };
@@ -100,25 +98,6 @@ tty_draw_line_clear(struct tty *tty, u_int px, u_int py, u_int nx,
} }
} }
/* Is this cell empty? */
static u_int
tty_draw_line_get_empty(const struct grid_cell *gc, u_int nx)
{
u_int empty = 0;
if (gc->data.width != 1 && gc->data.width > nx)
empty = nx;
else if (gc->attr == 0 && gc->link == 0) {
if (gc->flags & GRID_FLAG_CLEARED)
empty = 1;
else if (gc->flags & GRID_FLAG_TAB)
empty = gc->data.width;
else if (gc->data.size == 1 && *gc->data.data == ' ')
empty = 1;
}
return (empty);
}
/* Draw a line from screen to tty. */ /* Draw a line from screen to tty. */
void void
tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx, tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx,
@@ -239,6 +218,9 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx,
next_state = TTY_DRAW_LINE_DONE; next_state = TTY_DRAW_LINE_DONE;
gcp = &grid_default_cell; gcp = &grid_default_cell;
} else { } else {
if (i > nx)
fatalx("position %u > width %u", i, nx);
/* Get the current cell. */ /* Get the current cell. */
grid_view_get_cell(gd, px + i, py, &gc); grid_view_get_cell(gd, px + i, py, &gc);
@@ -253,20 +235,36 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx,
} }
/* Work out the the empty width. */ /* Work out the the empty width. */
if (px >= ex || i >= ex - px) empty = 0;
if (px >= ex || i >= ex - px) {
/* Outside the area being drawn. */
empty = 1; empty = 1;
else if (gcp->bg != last.bg) } else if (gcp->data.width > nx - i) {
empty = 0; /* Wide character that has been truncated. */
else empty = nx - i;
empty = tty_draw_line_get_empty(gcp, nx - i); } else if (gcp->flags & GRID_FLAG_PADDING) {
/* Orphan padding cell. */
empty = 1;
} else if (gcp->bg == last.bg && gcp->attr == 0 &&
gcp->link == 0) {
/*
* No attributes - empty if cleared, tab or
* space.
*/
if (gcp->flags & GRID_FLAG_CLEARED)
empty = 1;
else if (gcp->flags & GRID_FLAG_TAB)
empty = gcp->data.width;
else if (gcp->data.size == 1 &&
*gcp->data.data == ' ')
empty = 1;
}
/* Work out the next state. */ /* Work out the next state. */
if (empty != 0) if (empty != 0)
next_state = TTY_DRAW_LINE_EMPTY; next_state = TTY_DRAW_LINE_EMPTY;
else if (current_state == TTY_DRAW_LINE_FIRST) else if (current_state == TTY_DRAW_LINE_FIRST)
next_state = TTY_DRAW_LINE_SAME; next_state = TTY_DRAW_LINE_SAME;
else if (gcp->flags & GRID_FLAG_PADDING)
next_state = TTY_DRAW_LINE_PAD;
else if (grid_cells_look_equal(gcp, &last)) { else if (grid_cells_look_equal(gcp, &last)) {
if (gcp->data.size > (sizeof buf) - len) if (gcp->data.size > (sizeof buf) - len)
next_state = TTY_DRAW_LINE_FLUSH; next_state = TTY_DRAW_LINE_FLUSH;
@@ -312,8 +310,7 @@ tty_draw_line(struct tty *tty, struct screen *s, u_int px, u_int py, u_int nx,
} }
/* Append the cell if it is not empty and not padding. */ /* Append the cell if it is not empty and not padding. */
if (next_state != TTY_DRAW_LINE_EMPTY && if (next_state != TTY_DRAW_LINE_EMPTY) {
next_state != TTY_DRAW_LINE_PAD) {
memcpy(buf + len, gcp->data.data, gcp->data.size); memcpy(buf + len, gcp->data.data, gcp->data.size);
len += gcp->data.size; len += gcp->data.size;
width += gcp->data.width; width += gcp->data.width;

View File

@@ -98,7 +98,7 @@ static const char *tty_feature_hyperlinks_capabilities[] = {
#if defined (__OpenBSD__) || (defined(NCURSES_VERSION_MAJOR) && \ #if defined (__OpenBSD__) || (defined(NCURSES_VERSION_MAJOR) && \
(NCURSES_VERSION_MAJOR > 5 || \ (NCURSES_VERSION_MAJOR > 5 || \
(NCURSES_VERSION_MAJOR == 5 && NCURSES_VERSION_MINOR > 8))) (NCURSES_VERSION_MAJOR == 5 && NCURSES_VERSION_MINOR > 8)))
"*:Hls=\\E]8;%?%p1%l%tid=%p1%s%;;%p2%s\\E\\\\", "Hls=\\E]8;%?%p1%l%tid=%p1%s%;;%p2%s\\E\\\\",
#endif #endif
NULL NULL
}; };
@@ -527,8 +527,13 @@ tty_default_features(int *feat, const char *name, u_int version)
}, },
{ .name = "foot", { .name = "foot",
.features = TTY_FEATURES_BASE_MODERN_XTERM "," .features = TTY_FEATURES_BASE_MODERN_XTERM ","
"ccolour,"
"cstyle," "cstyle,"
"extkeys" "extkeys,"
"usstyle,"
"sync,"
"osc7,"
"hyperlinks"
}, },
{ .name = "WezTerm", { .name = "WezTerm",
.features = TTY_FEATURES_BASE_MODERN_XTERM "," .features = TTY_FEATURES_BASE_MODERN_XTERM ","

View File

@@ -119,6 +119,8 @@ static void window_copy_copy_line(struct window_mode_entry *, char **,
static int window_copy_in_set(struct window_mode_entry *, u_int, u_int, static int window_copy_in_set(struct window_mode_entry *, u_int, u_int,
const char *); const char *);
static u_int window_copy_find_length(struct window_mode_entry *, u_int); static u_int window_copy_find_length(struct window_mode_entry *, u_int);
static u_int window_copy_cursor_limit(struct window_mode_entry *, u_int,
int);
static void window_copy_cursor_start_of_line(struct window_mode_entry *); static void window_copy_cursor_start_of_line(struct window_mode_entry *);
static void window_copy_cursor_back_to_indentation( static void window_copy_cursor_back_to_indentation(
struct window_mode_entry *); struct window_mode_entry *);
@@ -906,9 +908,9 @@ window_copy_get_line(struct window_pane *wp, u_int y)
{ {
struct window_mode_entry *wme = TAILQ_FIRST(&wp->modes); struct window_mode_entry *wme = TAILQ_FIRST(&wp->modes);
struct window_copy_mode_data *data = wme->data; struct window_copy_mode_data *data = wme->data;
struct grid *gd = data->screen.grid; struct grid *gd = data->backing->grid;
return (format_grid_line(gd, gd->hsize + y)); return (format_grid_line(gd, gd->hsize + y - data->oy));
} }
char * char *
@@ -1673,7 +1675,7 @@ window_copy_cmd_history_bottom(struct window_copy_cmd_state *cs)
window_copy_other_end(wme); window_copy_other_end(wme);
data->cy = screen_size_y(&data->screen) - 1; data->cy = screen_size_y(&data->screen) - 1;
data->cx = window_copy_find_length(wme, screen_hsize(s) + data->cy); data->cx = window_copy_cursor_limit(wme, screen_hsize(s) + data->cy, 0);
data->oy = 0; data->oy = 0;
if (data->searchmark != NULL && !data->timeout) if (data->searchmark != NULL && !data->timeout)
@@ -2694,6 +2696,8 @@ window_copy_cmd_search_backward_incremental(struct window_copy_cmd_state *cs)
data->cx = data->searchx; data->cx = data->searchx;
data->cy = data->searchy; data->cy = data->searchy;
data->oy = data->searcho; data->oy = data->searcho;
data->cx = window_copy_cursor_limit(wme,
screen_hsize(data->backing) + data->cy - data->oy, 0);
action = WINDOW_COPY_CMD_REDRAW; action = WINDOW_COPY_CMD_REDRAW;
} }
if (*arg0 == '\0') { if (*arg0 == '\0') {
@@ -2749,6 +2753,8 @@ window_copy_cmd_search_forward_incremental(struct window_copy_cmd_state *cs)
data->cx = data->searchx; data->cx = data->searchx;
data->cy = data->searchy; data->cy = data->searchy;
data->oy = data->searcho; data->oy = data->searcho;
data->cx = window_copy_cursor_limit(wme,
screen_hsize(data->backing) + data->cy - data->oy, 0);
action = WINDOW_COPY_CMD_REDRAW; action = WINDOW_COPY_CMD_REDRAW;
} }
if (*arg0 == '\0') { if (*arg0 == '\0') {
@@ -5162,7 +5168,17 @@ window_copy_update_cursor(struct window_mode_entry *wme, u_int cx, u_int cy)
struct window_copy_mode_data *data = wme->data; struct window_copy_mode_data *data = wme->data;
struct screen *s = &data->screen; struct screen *s = &data->screen;
struct screen_write_ctx ctx; struct screen_write_ctx ctx;
u_int old_cx, old_cy, width, content_sx; u_int old_cx, old_cy, py, width, content_sx;
u_int maxx;
int allow_onemore;
allow_onemore = (data->screen.sel != NULL && data->rectflag);
if (cy < screen_size_y(s)) {
py = screen_hsize(data->backing) + cy - data->oy;
maxx = window_copy_cursor_limit(wme, py, allow_onemore);
if (cx > maxx)
cx = maxx;
}
old_cx = data->cx; old_cy = data->cy; old_cx = data->cx; old_cy = data->cy;
data->cx = cx; data->cy = cy; data->cx = cx; data->cy = cy;
@@ -5655,7 +5671,7 @@ window_copy_clear_selection(struct window_mode_entry *wme)
data->selflag = SEL_CHAR; data->selflag = SEL_CHAR;
py = screen_hsize(data->backing) + data->cy - data->oy; py = screen_hsize(data->backing) + data->cy - data->oy;
px = window_copy_find_length(wme, py); px = window_copy_cursor_limit(wme, py, data->rectflag);
if (data->cx > px) if (data->cx > px)
window_copy_update_cursor(wme, px, data->cy); window_copy_update_cursor(wme, px, data->cy);
} }
@@ -5677,6 +5693,22 @@ window_copy_find_length(struct window_mode_entry *wme, u_int py)
return (grid_line_length(data->backing->grid, py)); return (grid_line_length(data->backing->grid, py));
} }
static u_int
window_copy_cursor_limit(struct window_mode_entry *wme, u_int py,
int allow_onemore)
{
struct options *oo = wme->wp->window->options;
u_int len;
len = window_copy_find_length(wme, py);
if (allow_onemore ||
options_get_number(oo, "mode-keys") != MODEKEY_VI)
return (len);
if (len == 0)
return (0);
return (len - 1);
}
static void static void
window_copy_cursor_start_of_line(struct window_mode_entry *wme) window_copy_cursor_start_of_line(struct window_mode_entry *wme)
{ {
@@ -5734,6 +5766,8 @@ window_copy_cursor_end_of_line(struct window_mode_entry *wme)
else else
grid_reader_cursor_end_of_line(&gr, 1, 0); grid_reader_cursor_end_of_line(&gr, 1, 0);
grid_reader_get_cursor(&gr, &px, &py); grid_reader_get_cursor(&gr, &px, &py);
if (data->screen.sel == NULL || !data->rectflag)
px = window_copy_cursor_limit(wme, py, 0);
window_copy_acquire_cursor_down(wme, hsize, screen_size_y(back_s), window_copy_acquire_cursor_down(wme, hsize, screen_size_y(back_s),
data->oy, oldy, px, py, 0); data->oy, oldy, px, py, 0);
} }
@@ -5784,6 +5818,10 @@ window_copy_other_end(struct window_mode_entry *wme)
data->cy = screen_size_y(s) - 1; data->cy = screen_size_y(s) - 1;
} else } else
data->cy = cy + sely - yy; data->cy = cy + sely - yy;
yy = screen_hsize(data->backing) + data->cy - data->oy;
hsize = window_copy_cursor_limit(wme, yy, data->rectflag);
if (data->cx > hsize)
data->cx = hsize;
window_copy_update_selection(wme, 1, 1); window_copy_update_selection(wme, 1, 1);
window_copy_redraw_screen(wme); window_copy_redraw_screen(wme);
@@ -5811,18 +5849,22 @@ window_copy_cursor_left(struct window_mode_entry *wme)
static void static void
window_copy_cursor_right(struct window_mode_entry *wme, int all) window_copy_cursor_right(struct window_mode_entry *wme, int all)
{ {
struct window_pane *wp = wme->wp;
struct window_copy_mode_data *data = wme->data; struct window_copy_mode_data *data = wme->data;
struct options *oo = wp->window->options;
struct screen *back_s = data->backing; struct screen *back_s = data->backing;
struct grid_reader gr; struct grid_reader gr;
u_int px, py, oldy, hsize; u_int px, py, oldy, hsize;
int onemore;
px = data->cx; px = data->cx;
hsize = screen_hsize(back_s); hsize = screen_hsize(back_s);
py = hsize + data->cy - data->oy; py = hsize + data->cy - data->oy;
oldy = data->cy; oldy = data->cy;
onemore = (options_get_number(oo, "mode-keys") != MODEKEY_VI);
grid_reader_start(&gr, back_s->grid, px, py); grid_reader_start(&gr, back_s->grid, px, py);
grid_reader_cursor_right(&gr, 1, all); grid_reader_cursor_right(&gr, 1, all, onemore);
grid_reader_get_cursor(&gr, &px, &py); grid_reader_get_cursor(&gr, &px, &py);
window_copy_acquire_cursor_down(wme, hsize, screen_size_y(back_s), window_copy_acquire_cursor_down(wme, hsize, screen_size_y(back_s),
data->oy, oldy, px, py, 0); data->oy, oldy, px, py, 0);
@@ -6037,20 +6079,23 @@ static void
window_copy_cursor_jump_to_back(struct window_mode_entry *wme) window_copy_cursor_jump_to_back(struct window_mode_entry *wme)
{ {
struct window_copy_mode_data *data = wme->data; struct window_copy_mode_data *data = wme->data;
struct options *oo = wme->wp->window->options;
struct screen *back_s = data->backing; struct screen *back_s = data->backing;
struct grid_reader gr; struct grid_reader gr;
u_int px, py, oldy, hsize; u_int px, py, oldy, hsize;
int onemore;
px = data->cx; px = data->cx;
hsize = screen_hsize(back_s); hsize = screen_hsize(back_s);
py = hsize + data->cy - data->oy; py = hsize + data->cy - data->oy;
oldy = data->cy; oldy = data->cy;
onemore = (options_get_number(oo, "mode-keys") != MODEKEY_VI);
grid_reader_start(&gr, back_s->grid, px, py); grid_reader_start(&gr, back_s->grid, px, py);
grid_reader_cursor_left(&gr, 0); grid_reader_cursor_left(&gr, 0);
grid_reader_cursor_left(&gr, 0); grid_reader_cursor_left(&gr, 0);
if (grid_reader_cursor_jump_back(&gr, data->jumpchar)) { if (grid_reader_cursor_jump_back(&gr, data->jumpchar)) {
grid_reader_cursor_right(&gr, 1, 0); grid_reader_cursor_right(&gr, 1, 0, onemore);
grid_reader_get_cursor(&gr, &px, &py); grid_reader_get_cursor(&gr, &px, &py);
window_copy_acquire_cursor_up(wme, hsize, data->oy, oldy, px, window_copy_acquire_cursor_up(wme, hsize, data->oy, oldy, px,
py); py);
@@ -6097,7 +6142,7 @@ window_copy_cursor_next_word_end_pos(struct window_mode_entry *wme,
grid_reader_start(&gr, back_s->grid, px, py); grid_reader_start(&gr, back_s->grid, px, py);
if (options_get_number(oo, "mode-keys") == MODEKEY_VI) { if (options_get_number(oo, "mode-keys") == MODEKEY_VI) {
if (!grid_reader_in_set(&gr, WHITESPACE)) if (!grid_reader_in_set(&gr, WHITESPACE))
grid_reader_cursor_right(&gr, 0, 0); grid_reader_cursor_right(&gr, 0, 0, 0);
grid_reader_cursor_next_word_end(&gr, separators); grid_reader_cursor_next_word_end(&gr, separators);
grid_reader_cursor_left(&gr, 1); grid_reader_cursor_left(&gr, 1);
} else } else
@@ -6127,7 +6172,7 @@ window_copy_cursor_next_word_end(struct window_mode_entry *wme,
grid_reader_start(&gr, back_s->grid, px, py); grid_reader_start(&gr, back_s->grid, px, py);
if (options_get_number(oo, "mode-keys") == MODEKEY_VI) { if (options_get_number(oo, "mode-keys") == MODEKEY_VI) {
if (!grid_reader_in_set(&gr, WHITESPACE)) if (!grid_reader_in_set(&gr, WHITESPACE))
grid_reader_cursor_right(&gr, 0, 0); grid_reader_cursor_right(&gr, 0, 0, 0);
grid_reader_cursor_next_word_end(&gr, separators); grid_reader_cursor_next_word_end(&gr, separators);
grid_reader_cursor_left(&gr, 1); grid_reader_cursor_left(&gr, 1);
} else } else
@@ -6361,7 +6406,7 @@ window_copy_rectangle_set(struct window_mode_entry *wme, int rectflag)
data->rectflag = rectflag; data->rectflag = rectflag;
py = screen_hsize(data->backing) + data->cy - data->oy; py = screen_hsize(data->backing) + data->cy - data->oy;
px = window_copy_find_length(wme, py); px = window_copy_cursor_limit(wme, py, data->rectflag);
if (data->cx > px) if (data->cx > px)
window_copy_update_cursor(wme, px, data->cy); window_copy_update_cursor(wme, px, data->cy);

View File

@@ -935,16 +935,14 @@ window_pane_index(struct window_pane *wp, u_int *i)
} }
u_int u_int
window_count_panes(struct window *w, int inc_floating) window_count_panes(struct window *w, int with_floating)
{ {
struct window_pane *wp; struct window_pane *wp;
u_int n; u_int n = 0;
n = 0;
TAILQ_FOREACH(wp, &w->panes, entry) { TAILQ_FOREACH(wp, &w->panes, entry) {
if ((inc_floating == 0) && (wp->flags & PANE_FLOATING)) if (with_floating || ~wp->flags & PANE_FLOATING)
continue; n++;
n++;
} }
return (n); return (n);
} }
@@ -1516,11 +1514,9 @@ window_pane_find_up(struct window_pane *wp)
{ {
struct window *w; struct window *w;
struct window_pane *next, *best, **list; struct window_pane *next, *best, **list;
int edge, left, right, end; int edge, left, right, end, status, found;
u_int size;
int status, found;
int xoff, yoff; int xoff, yoff;
u_int sx, sy; u_int size, sx, sy;
if (wp == NULL) if (wp == NULL)
return (NULL); return (NULL);
@@ -1579,11 +1575,9 @@ window_pane_find_down(struct window_pane *wp)
{ {
struct window *w; struct window *w;
struct window_pane *next, *best, **list; struct window_pane *next, *best, **list;
int edge, left, right, end; int edge, left, right, end, status, found;
u_int size;
int status, found;
int xoff, yoff; int xoff, yoff;
u_int sx, sy; u_int size, sx, sy;
if (wp == NULL) if (wp == NULL)
return (NULL); return (NULL);
@@ -1642,11 +1636,9 @@ window_pane_find_left(struct window_pane *wp)
{ {
struct window *w; struct window *w;
struct window_pane *next, *best, **list; struct window_pane *next, *best, **list;
int edge, top, bottom, end; int edge, top, bottom, end, found;
u_int size;
int found;
int xoff, yoff; int xoff, yoff;
u_int sx, sy; u_int size, sx, sy;
if (wp == NULL) if (wp == NULL)
return (NULL); return (NULL);
@@ -1696,11 +1688,9 @@ window_pane_find_right(struct window_pane *wp)
{ {
struct window *w; struct window *w;
struct window_pane *next, *best, **list; struct window_pane *next, *best, **list;
int edge, top, bottom, end; int edge, top, bottom, end, found;
u_int size;
int found;
int xoff, yoff; int xoff, yoff;
u_int sx, sy; u_int size, sx, sy;
if (wp == NULL) if (wp == NULL)
return (NULL); return (NULL);
@@ -1744,6 +1734,7 @@ window_pane_find_right(struct window_pane *wp)
return (best); return (best);
} }
/* Add window to stack. */
void void
window_pane_stack_push(struct window_panes *stack, struct window_pane *wp) window_pane_stack_push(struct window_panes *stack, struct window_pane *wp)
{ {
@@ -1754,6 +1745,7 @@ window_pane_stack_push(struct window_panes *stack, struct window_pane *wp)
} }
} }
/* Remove window from stack. */
void void
window_pane_stack_remove(struct window_panes *stack, struct window_pane *wp) window_pane_stack_remove(struct window_panes *stack, struct window_pane *wp)
{ {
@@ -2134,3 +2126,53 @@ window_pane_border_status_get_range(struct window_pane *wp, u_int x, u_int y)
*/ */
return (style_ranges_get_range(srs, x - wp->xoff - 2)); return (style_ranges_get_range(srs, x - wp->xoff - 2));
} }
int
window_pane_tile_geometry(struct window *w, struct window_pane *wp,
int *out_size, int *out_flags, enum layout_type *out_type,
struct cmdq_item *item, struct args *args, char **cause)
{
int size = -1, flags = *out_flags;
enum layout_type type;
u_int curval = 0;
type = LAYOUT_TOPBOTTOM;
if (args_has(args, 'h'))
type = LAYOUT_LEFTRIGHT;
if (args_has(args, 'l') || args_has(args, 'p')) {
if (args_has(args, 'f')) {
if (type == LAYOUT_TOPBOTTOM)
curval = w->sy;
else
curval = w->sx;
} else {
if (type == LAYOUT_TOPBOTTOM)
curval = wp->sy;
else
curval = wp->sx;
}
}
if (args_has(args, 'l')) {
size = args_percentage_and_expand(args, 'l', 0, INT_MAX, curval,
item, cause);
} else if (args_has(args, 'p')) {
size = args_strtonum_and_expand(args, 'p', 0, 100, item,
cause);
if (cause == NULL)
size = curval * size / 100;
}
if (*cause != NULL)
return (-1);
if (args_has(args, 'b'))
flags |= SPAWN_BEFORE;
if (args_has(args, 'f'))
flags |= SPAWN_FULLSIZE;
*out_size = size;
*out_flags = flags;
*out_type = type;
return (0);
}