Merged master into floating_panes

This commit is contained in:
Dane Jensen
2026-06-08 15:52:16 -07:00
58 changed files with 935 additions and 227 deletions

329
CHANGES
View File

@@ -1,3 +1,332 @@
CHANGES FROM 3.6b TO 3.7
* Add floating panes. These are panes which sit above the layout ("tiled
panes") like popups but unlike popups are not modal and behave like panes (so
the same escape sequence support). Floating panes are created with the
new-pane command, bound to * by default.
Currently floating panes can only be moved and resized using the mouse. The
default second status line (if status-format is set to 2) has changed to show
a list of panes. Many obvious features are not yet available for floating
panes (notably the ability to swap floating panes, resize them using
resize-pane, change them between floating and tiles, and restore custom
layouts with floating panes).
Mostly written by Michael Grant with help from Dane Jensen; testing and fixes
from others.
* Allow run-shell arguments after a shell command to be expanded as #{1}, #{2}
and so on (from Rasmus Thystrup Karstensen in issue 5121).
* Add -g to kill-session to kill all sessions in a session group (issue 5157
from github at jiku dot jp).
* Tighten up read-only checks on attach-session, detach-client and
switch-client so that a user should be able to only detach their own client
(reported by John Walker).
* Increase escape delay if the buffer contains a partial paste end, fixes
issues with at least Windows Terminal (from jing dot empty at gmail.com issue
5088).
* When mode-keys is set to vi, do not allow the cursor to go into the invisible
extra cell to the right of the visible text; this is closer to what vi(1)
does (from Max Vim in issue 5070).
* Add a five second limit on pasting for terminals which mysteriously lose the
end sequence if the paste is too big (that is, Terminal.app) (reported by
Garri Djavadyan in issue 4527).
* Show file open errors more sensibly (reported by Meriel Luna Mittelbach in
issue 5081).
* Update supported features list for Foot terminal (from Meriel Luna Mittelbach
in issue 5079).
* Turn off the "is this a paste" guessing if the terminal supports bracket
pasting instead (issue 5031).
* Check FIONREAD for all panes not just piped panes.
* Add emacs-style recentre-top-bottom command to copy mode (issue 5053 from
sinyax75 at gmail dot com).
* Allow the indicator in tree mode to be customized by two new options:
tree-mode-preview-format and tree-mode-preview-style.
* Fix control client hang on exit after toggling no-output (issue 5049 from
Aaron Campbell). Also various other control mode fixes.
* Add support for line numbers in copy mode. There is a new
copy-mode-line-numbers option which may be set to off, default (tmux's normal
line numbering where 0 is the top visible line), absolute (first line in
history is 1), relative (relative to the cursor) and hybrid (current line is
absolute, others relative). Also adds copy-mode-line-number-style and
copy-mode-current-line-number-style to set the style of the line numbers.
When copy mode is entered with the mouse, line numbers stay off. From Leo
Henon in issue 5025.
* Make C-[ have the same bindings as Escape for terminals with extended
keys where they are different (issue 5035 from Eric Nicolas).
* Sanitize paste buffer names in paste_set and paste_rename (issue 5032 from
Barrett Ruth).
* Do not hang in run-shell when job_run fails (from Barrett Ruth in issue
5037).
* Add ability to forward progress bar to outside terminal (issue 4972
from Eric Dorland).
* Translate keypad keys to text in prompt input (from Barrett Ruth in issue
4996).
* Sanitize pane titles and window and session names more consistently and
strictly, prevents C0 characters and other invisible characters causing
problems (reported by Chris Monardo in issue 4999).
* Make clock visible on terminals without colours (from Manuel Einfalt in issue
5001).
* Add detach to default session menu (suggested by Przemyslaw Sztoch).
* Include window format variables for pane notifications (issue 5007 from Saul
Nogueras).
* Limit precision to 100 for formats to stop silly formats from running out of
memory, reported by z1281552865 at gmail dot com. Also various other similar
changes, mostly found by OSS-Fuzz.
* Add WAYLAND_DISPLAY to default update-environment (issue 4965). Also some
additional XDG_* variables (issue 5169).
* Add -C flag to command-prompt to match display-message -C (do not freeze
panes) (from Barrett Ruth in issue 4978).
* Cache user from getpwuid because it can be very expensive on some
platforms (from Ben Maurer in issue 4973).
* Add remain-on-exit key to keep pane around until a key is pressed (from
Michael Grant).
* Add some new mouse ranges called "control0" to "control9" and use to add some
mouse controls to the pane state line (from Dane Jensen with some bits from
Michael Grant).
* Handle OSC 9;4 progress bar sequence and store in format variables (from Eric
Dorland in issue 4954).
* Correctly size buffer used for parsing clipboard sequences (from Michal
Majchrowicz).
* Limit MSG_COMMAND argument to between 0 and 1000 to prevent a misbehaving
client from crashing the server (from Michal Majchrowicz).
* Reorganize host keys are represented internally so they can be built more
easily (from Dane Jensen in issue 4953).
* Add new fuzzers for command parsing, formats and styles (from David
Korczynski in issue 4957). Also fix various issues shown from these.
* Add bracket_paste_flag format flag (from George Nachman in issue 4951).
* Use \- for hyphens in tmux.1 to cause newer groff versions to render them
correctly (from Keith Thompson in issue 4948).
* Various minor code improvements and fixes from Pavel Lavrukhin (issue 4936
and others).
* Use window options for cursor-style to avoid crash when no pane (from Arden
Packeer in issue 4942).
* Fix issue where popup window gets overwritten by background updates (from
Conor Taylor in issue 4920).
* Protect against overflow when scrollbar is off screen (from san65384 at gmail
dot com in issue 4933).
* Copy hyperlinks when redrawing popup so they do not vanish (from Antoine
Gaudreau Simard in issue 4925).
* Work around systemd killing panes early during system shutdown by creating
dependencies from the panes to the service which started tmux (issue 4926
from Dmitry Torokhov).
* Allow codepoint-widths to accept ranges (from san65384 at gmail dot com in
issue 4930).
* Add a short builtin help text for each mode accessible with C-h (based on
code from Patrick Motard in issue 4751).
* Draw message as one format, allowing prompts and messages to occupy only a
portion of the status bar, overlaying the normal status content rather than
replacing the entire line. A new message-format option now controls the
entire message (like status-format). The message-style option now need to
include "fill" in order to cover the whole width (the default has
"fill=yellow"). From Conor Taylor in issue 4861.
* Add next/previous variables for windows in W: loop (from Conor Taylor in
issue 4856).
* Various bug and memory leak fixes from Renaud Allard (issue 4916).
* Add pane_pipe_pid with pipe file descriptor.
* Make -c work with new-session -A (from Jody Frankowski in issue 4906).
* Allow copy mode to work for readonly clients, except for copy commands (from
Dane Jensen).
* Pass paste buffer through vis(3) when pasting to prevent buffers containing
for example the bracket end sequence causing issues, a new -S flag disables
(reported by Mason Davis).
* Add sorting (-O flag) and a custom format (-F) to list-keys (from Dane Jensen
in issue 4845).
* Add scroll-exit-on, scroll-exit-off, scroll-exit-toggle commands to copy mode
(from xcdnlgd at hotmail dot com in issue 4884).
* Respond to DECRQM 2026 (from David Turnbull in issue 4887) and various others
(from Ayman Bagabas in issue 5118).
* Fix various memory leaks reported by Huihui Huang (issue 4872).
* Pass which clipboard is set through to the terminal (from Axel Lindskog in
issue 4858).
* Reuse extended entry when clearing RGB cell, to prevent memory growth when
cells are repeatedly cleared (from Michael K Darling in issue 4862).
* Do not write before buffer when parsing empty clipboard or palette replies,
or try to allocate zero bytes with an empty clipboard sequence (reported by
DongHan Kim).
* Various bug fixes and code improvements from Conor Taylor (issue 4848).
* Clear search counts when clearing marks in case of repeated search (reported
by Daniel Pereira in issue 4817).
* Make OSC 52 work in popups (from gogongxt at 163 dot com in issue 4797).
* Refresh copy mode when style changes (from Josh Cooper in issue 4830).
* Make sorting code common and add -O for sorting to the list commands (from
Dane Jensen in issue 4813).
* Do not treat cells as empty unless the background colour stays the same,
fixes invisible clock in clock mode (reported by Theo Buehler).
* When history-limit is changed, apply to existing panes, not just new
ones (issue 4705).
* Reevaluate menu and popup styles on each draw to allow them to change when
options change (from Josh Cooper in issues 4828 and 4829).
* Handle theme keys earlier so they are processed even if a popup is open (from
Josh Cooper in issue 4827).
* Fix window-size=latest not resizing on switch-client in session groups (from
Ilya Grigoriev in issue 4818).
* Add -e flag to command-prompt to close if empty (from Dane Jensen in issue
4812).
* Correctly draw indicators when pane-border-indicators is set to both
(reported by Ilya Grigoriev in issue 4780).
* Remember last pane or type of location for double and triple clicks and
correctly handle it changes between first and second or second and third
(issue 4795 from Shaobo Song).
* Add paste to the default pane menu (issue 4763).
* Reduce request timeout to 500 milliseconds to match the extended escape-time,
and discard palette requests if receiving a reply for a different index.
* Extend escape timeout if there are active forwarded requests not just
tmux's own requests (issue 4793).
* Correct redrawing of wide characters when overwritten (reported by Jake
Stewart in issue 4737).
* If cannot find a terminator for palette responses, treat as a partial key not
complete (issue 4749).
* Do not send theme unless it has changed, and do not send immediately when
updates are enabled (issue 5787).
* Do not use ;;s in list-keys output as it is confusing and cannot be
parsed on input (from Patrick Motard in issue 4750).
* Redraw pane borders when entering or leaving alternate screen (from Mike
Jonkmans in issue 4788).
* Add focus-follows-mouse option (from Barry Wasdell in issue 4771).
* Add selection_mode format variable for copy mode (from Mike Jonkmans in issue
4773).
* Add prompt-command-cursor-style (from Joshua Cooper in issue 4765).
* With status-keys vi, move the cursor left by one when pressing Escape to
enter command mode, like vi (issue 4767 from Joshua Cooper).
* Add {current}/{active} for -t for current window or active pane (from Manuel
Einfalt, issue 4766).
* Add support for applications to use synchronized output mode (DECSET 2026) to
prevent screen tearing during rapid updates (from Chris Lloyd in issue 4744).
* Do not set a default prompt cursor colour because some terminals (urxvt, st)
do not support the reset sequence (issue 4759).
* Add a scroll-to-mouse command for copy mode to scroll to the mouse position
and bind to the scrollbar, brings the scrollbar keys into line with the other
mouse keys (from Michael Grant in issue 4731).
* Bump the maximum number of SIXEL images to 20.
* Fix key code for M-BSpace (issue 4717).
* Fix calculation of scaled SIXEL size (from nincsnevem662 at gmail dot com in
issue 4739). Also various other fixes and improvements for SIXEL.
* Fix a race between fork and pane_current_path, most noticeable on systems
where starting processes is slow (issue 4719).
* Fix mouse position calculation on scrollbar with pane status line at the top
(issue 4738 from Michael Grant).
* Do not read outside buffer if format is a single #, and do not loop forever
if UTF-8 is unfinished in a format (reported by Giorgi Kobakhia in issue
4735).
* Add a missing skin tone character (from Jake Stewart in issue 4736).
* Allow UTF-8 characters to be combined in either order (reported by Jake
Stewart in issue 4726).
* Do not show scrollbar when entering copy mode from a pane in the alternate
screen (issue 4728 from Michael Grant).
* Fix the size calculation for left-right windows used to spread out cells
horizontally evenly (from Michael Grant in issue 4724).
* Add a get-clipboard option which when enabled (the default is off) and a
clipboard is requested from a pane, requests it from the terminal and
forwards to the requesting pane; also remove the now-redundant
forward-to-pane ability from "refresh-client -l" (issue 4275).
* Fix the noattr attribute in styles, used by the default mode-style (issue
4713).
* Do not remove TERM for commands run from config file (regression reported by
Dennis Eriksen).
* Add seconds options for clock mode (from augustus7613 dot mail at pm dot me,
issue 4697; later improved by Joao Pedro in issue 4760).
CHANGES FROM 3.6a TO 3.6b
* Remove images from the correct list when they are removed while in the

View File

@@ -29,18 +29,21 @@
static enum cmd_retval cmd_capture_pane_exec(struct cmd *, struct cmdq_item *);
static char *cmd_capture_pane_append(char *, size_t *, char *, size_t);
static char *cmd_capture_pane_append(char *, size_t *, const char *,
size_t);
static char *cmd_capture_pane_pending(struct args *, struct window_pane *,
size_t *);
static char *cmd_capture_pane_history(struct args *, struct cmdq_item *,
struct window_pane *, size_t *);
static char *cmd_capture_pane_hyperlinks(struct grid *, struct screen *,
u_int, u_int *, u_int *, size_t *);
const struct cmd_entry cmd_capture_pane_entry = {
.name = "capture-pane",
.alias = "capturep",
.args = { "ab:CeE:JMNpPqS:Tt:", 0, 0, NULL },
.usage = "[-aCeJMNpPqT] " CMD_BUFFER_USAGE " [-E end-line] "
.args = { "ab:CeE:FHJLMNpPqS:Tt:", 0, 0, NULL },
.usage = "[-aCeFHJLMNpPqT] " CMD_BUFFER_USAGE " [-E end-line] "
"[-S start-line] " CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 },
@@ -63,7 +66,8 @@ const struct cmd_entry cmd_clear_history_entry = {
};
static char *
cmd_capture_pane_append(char *buf, size_t *len, char *line, size_t linelen)
cmd_capture_pane_append(char *buf, size_t *len, const char *line,
size_t linelen)
{
buf = xrealloc(buf, *len + linelen + 1);
memcpy(buf + *len, line, linelen);
@@ -103,6 +107,46 @@ cmd_capture_pane_pending(struct args *args, struct window_pane *wp,
return (buf);
}
static char *
cmd_capture_pane_hyperlinks(struct grid *gd, struct screen *s, u_int py,
u_int *links, u_int *nlinks, size_t *len)
{
const struct grid_line *gl = grid_peek_line(gd, py);
struct grid_cell gc;
const char *uri;
char *line = xstrdup("");
u_int i, j;
*len = 0;
if (s->hyperlinks == NULL || (~gl->flags & GRID_LINE_HYPERLINK))
return (line);
for (i = 0; i < gl->cellused; i++) {
grid_get_cell(gd, i, py, &gc);
if (gc.link == 0)
continue;
for (j = 0; j < *nlinks; j++) {
if (links[j] == gc.link)
break;
}
if (j != *nlinks)
continue;
if (!hyperlinks_get(s->hyperlinks, gc.link, &uri, NULL, NULL))
continue;
if (*nlinks == gd->sx)
break;
links[(*nlinks)++] = gc.link;
if (*len != 0)
line = cmd_capture_pane_append(line, len, " ", 1);
line = cmd_capture_pane_append(line, len, uri, strlen(uri));
}
return (line);
}
static char *
cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
struct window_pane *wp, size_t *len)
@@ -112,9 +156,11 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
struct screen *s;
struct grid_cell *gc = NULL;
struct window_mode_entry *wme;
int n, join_lines, flags = 0;
int n, join_lines, number_lines, flags = 0;
int show_flags, hyperlinks;
u_int *links = NULL, nlinks = 0;
u_int i, sx, top, bottom, tmp;
char *cause, *buf, *line;
char *cause, *buf = NULL, *line, b[64], *cp;
const char *Sflag, *Eflag;
size_t linelen;
@@ -152,7 +198,7 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
if (cause != NULL) {
top = gd->hsize;
free(cause);
} else if (n < 0 && (u_int) -n > gd->hsize)
} else if (n < 0 && (u_int)-n > gd->hsize)
top = 0;
else
top = gd->hsize + n;
@@ -169,7 +215,7 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
if (cause != NULL) {
bottom = gd->hsize + gd->sy - 1;
free(cause);
} else if (n < 0 && (u_int) -n > gd->hsize)
} else if (n < 0 && (u_int)-n > gd->hsize)
bottom = 0;
else
bottom = gd->hsize + n;
@@ -192,12 +238,57 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
flags |= GRID_STRING_EMPTY_CELLS;
if (!join_lines && !args_has(args, 'N'))
flags |= GRID_STRING_TRIM_SPACES;
number_lines = args_has(args, 'L');
show_flags = args_has(args, 'F');
hyperlinks = args_has(args, 'H');
if (hyperlinks)
links = xreallocarray(NULL, gd->sx, sizeof *links);
buf = NULL;
for (i = top; i <= bottom; i++) {
line = grid_string_cells(gd, 0, i, sx, &gc, flags, s);
linelen = strlen(line);
if (hyperlinks) {
line = cmd_capture_pane_hyperlinks(gd, s, i, links,
&nlinks, &linelen);
} else {
line = grid_string_cells(gd, 0, i, sx, &gc, flags, s);
linelen = strlen(line);
}
if (hyperlinks && linelen == 0) {
free(line);
continue;
}
if (number_lines) {
if (i >= gd->hsize)
n = i - gd->hsize;
else
n = (int)i - (int)gd->hsize;
n = snprintf(b, sizeof b, "%d ", n);
if (n >= 0)
buf = cmd_capture_pane_append(buf, len, b, n);
}
if (show_flags) {
cp = b;
*cp = '\0';
gl = grid_peek_line(gd, i);
if (gl->flags & GRID_LINE_DEAD)
*cp++ = 'D';
if (gl->flags & GRID_LINE_HYPERLINK)
*cp++ = 'H';
if (gl->flags & GRID_LINE_START_OUTPUT)
*cp++ = 'O';
if (gl->flags & GRID_LINE_START_PROMPT)
*cp++ = 'P';
if (gl->flags & GRID_LINE_WRAPPED)
*cp++ = 'W';
if (gl->flags & GRID_LINE_EXTENDED)
*cp++ = 'X';
if (b == cp)
*cp++ = '-';
*cp++ = ' ';
*cp = '\0';
buf = cmd_capture_pane_append(buf, len, b, strlen (b));
}
buf = cmd_capture_pane_append(buf, len, line, linelen);
gl = grid_peek_line(gd, i);
@@ -206,6 +297,9 @@ cmd_capture_pane_history(struct args *args, struct cmdq_item *item,
free(line);
}
free(links);
if (buf == NULL)
buf = xstrdup("");
return (buf);
}
@@ -228,7 +322,7 @@ cmd_capture_pane_exec(struct cmd *self, struct cmdq_item *item)
}
len = 0;
if (args_has(args, 'P'))
if (args_has(args, 'P') && !args_has(args, 'H'))
buf = cmd_capture_pane_pending(args, wp, &len);
else
buf = cmd_capture_pane_history(args, item, wp, &len);

View File

@@ -33,8 +33,8 @@ const struct cmd_entry cmd_choose_tree_entry = {
.name = "choose-tree",
.alias = NULL,
.args = { "F:f:GK:NO:rst:wyZ", 0, 1, cmd_choose_tree_args_parse },
.usage = "[-GNrswZ] [-F format] [-f filter] [-K key-format] "
.args = { "F:f:GhK:kNO:rst:wyZ", 0, 1, cmd_choose_tree_args_parse },
.usage = "[-GhkNrswZ] [-F format] [-f filter] [-K key-format] "
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",
.target = { 't', CMD_FIND_PANE, 0 },
@@ -47,8 +47,8 @@ const struct cmd_entry cmd_choose_client_entry = {
.name = "choose-client",
.alias = NULL,
.args = { "F:f:K:NO:rt:yZ", 0, 1, cmd_choose_tree_args_parse },
.usage = "[-NrZ] [-F format] [-f filter] [-K key-format] "
.args = { "F:f:hK:kNO:rt:yZ", 0, 1, cmd_choose_tree_args_parse },
.usage = "[-hkNrZ] [-F format] [-f filter] [-K key-format] "
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",
.target = { 't', CMD_FIND_PANE, 0 },
@@ -61,8 +61,8 @@ const struct cmd_entry cmd_choose_buffer_entry = {
.name = "choose-buffer",
.alias = NULL,
.args = { "F:f:K:NO:rt:yZ", 0, 1, cmd_choose_tree_args_parse },
.usage = "[-NrZ] [-F format] [-f filter] [-K key-format] "
.args = { "F:f:K:kNO:rt:yZ", 0, 1, cmd_choose_tree_args_parse },
.usage = "[-kNrZ] [-F format] [-f filter] [-K key-format] "
"[-O sort-order] " CMD_TARGET_PANE_USAGE " [template]",
.target = { 't', CMD_FIND_PANE, 0 },
@@ -75,8 +75,8 @@ const struct cmd_entry cmd_customize_mode_entry = {
.name = "customize-mode",
.alias = NULL,
.args = { "F:f:Nt:yZ", 0, 0, NULL },
.usage = "[-NZ] [-F format] [-f filter] " CMD_TARGET_PANE_USAGE,
.args = { "F:f:kNt:yZ", 0, 0, NULL },
.usage = "[-kNZ] [-F format] [-f filter] " CMD_TARGET_PANE_USAGE,
.target = { 't', CMD_FIND_PANE, 0 },

View File

@@ -76,6 +76,40 @@ cmd_display_panes_put(struct screen_redraw_ctx *ctx,
}
}
static void
cmd_display_panes_draw_format(struct screen_redraw_ctx *ctx,
struct window_pane *wp, u_int xoff, u_int yoff, u_int sx,
const struct grid_cell *gc)
{
struct client *c = ctx->c;
struct tty *tty = &c->tty;
struct session *s = c->session;
struct screen screen;
struct screen_write_ctx sctx;
struct visible_ranges *r;
struct visible_range *ri;
const char *format;
char *expanded;
u_int i, px = ctx->ox + xoff;
format = options_get_string(s->options, "display-panes-format");
expanded = format_single(NULL, format, c, s, s->curw, wp);
screen_init(&screen, sx, 1, 0);
screen_write_start(&sctx, &screen);
format_draw(&sctx, gc, sx, expanded, NULL, 0);
screen_write_stop(&sctx);
free(expanded);
r = screen_redraw_get_visible_ranges(wp, px, wp->yoff, sx, NULL);
for (i = 0; i < r->used; i++) {
ri = &r->ranges[i];
tty_draw_line(tty, &screen, ri->px - px, 0, ri->nx,
ri->px - ctx->ox, yoff, gc, NULL);
}
screen_free(&screen);
}
static void
cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
struct window_pane *wp)
@@ -89,8 +123,8 @@ cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
u_int pane, idx, px, py, i, j, xoff, yoff, sx, sy;
u_int cx, cy;
int colour, active_colour;
char buf[16], lbuf[16], rbuf[16], *ptr;
size_t len, llen, rlen;
char buf[16], lbuf[16], *ptr;
size_t len, llen;
if (wp->xoff + (int)wp->sx <= ctx->ox ||
wp->xoff >= ctx->ox + (int)ctx->sx ||
@@ -159,7 +193,6 @@ cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
bgc.bg = colour;
}
rlen = xsnprintf(rbuf, sizeof rbuf, "%ux%u", wp->sx, wp->sy);
if (pane > 9 && pane < 35)
llen = xsnprintf(lbuf, sizeof lbuf, "%c", 'a' + (pane - 10));
else
@@ -207,13 +240,9 @@ cmd_display_panes_draw_pane(struct screen_redraw_ctx *ctx,
if (sy <= 6)
goto out;
tty_attributes(tty, &fgc, &grid_default_cell, NULL, NULL);
if (rlen != 0 && sx >= rlen) {
cx = xoff + sx - rlen;
cy = yoff;
cmd_display_panes_put(ctx, wp, cx, cy, rbuf, rlen);
}
cmd_display_panes_draw_format(ctx, wp, xoff, yoff, sx, &fgc);
if (llen != 0) {
tty_attributes(tty, &fgc, &grid_default_cell, NULL, NULL);
cx = xoff + sx / 2 + len * 3 - llen - 1;
cy = yoff + py + 5;
cmd_display_panes_put(ctx, wp, cx, cy, lbuf, llen);

View File

@@ -93,7 +93,7 @@ cmd_join_pane_exec(struct cmd *self, struct cmdq_item *item)
lc = layout_get_tiled_cell(item, args, dst_w, dst_wp, flags, &cause);
if (cause != NULL) {
cmdq_error(item, "%s", cause);
cmdq_error(item, "size or position %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}

View File

@@ -33,8 +33,8 @@ const struct cmd_entry cmd_kill_session_entry = {
.name = "kill-session",
.alias = NULL,
.args = { "aCt:", 0, 0, NULL },
.usage = "[-aC] " CMD_TARGET_SESSION_USAGE,
.args = { "aCgt:", 0, 0, NULL },
.usage = "[-aCg] " CMD_TARGET_SESSION_USAGE,
.target = { 't', CMD_FIND_SESSION, 0 },
@@ -48,6 +48,7 @@ cmd_kill_session_exec(struct cmd *self, struct cmdq_item *item)
struct args *args = cmd_get_args(self);
struct cmd_find_state *target = cmdq_get_target(item);
struct session *s = target->s, *sloop, *stmp;
struct session_group *sg;
struct winlink *wl;
if (args_has(args, 'C')) {
@@ -63,6 +64,12 @@ cmd_kill_session_exec(struct cmd *self, struct cmdq_item *item)
session_destroy(sloop, 1, __func__);
}
}
} else if (args_has(args, 'g') &&
(sg = session_group_contains(s)) != NULL) {
TAILQ_FOREACH_SAFE(sloop, &sg->sessions, gentry, stmp) {
server_destroy_session(sloop);
session_destroy(sloop, 1, __func__);
}
} else {
server_destroy_session(s);
session_destroy(s, 1, __func__);

View File

@@ -35,7 +35,7 @@
"," \
"bind-key #{?key_has_repeat,#{?key_repeat,-r, },} " \
"-T #{p|#{key_table_width}:key_table} " \
"#{p|#{key_string_width}:key_string} " \
"#{p|#{key_string_width}:#{q|a:key_string}} " \
"#{key_command}}"
static enum cmd_retval cmd_list_keys_exec(struct cmd *, struct cmdq_item *);

View File

@@ -38,11 +38,11 @@ const struct cmd_entry cmd_new_pane_entry = {
.name = "new-pane",
.alias = "newp",
.args = { "bc:de:fF:hIkl:Lm:p:PR:s:S:t:vx:X:y:Y:Z", 0, -1, NULL },
.args = { "bc:de:EfF:hIkl:Lm:p:PR:s:S:t:T:vx:X:y:Y:Z", 0, -1, NULL },
.usage = "[-bdefhIklPvZ] [-c start-directory] [-e environment] "
"[-F format] [-l size] [-m message] [-p percentage] "
"[-s style] [-S active-border-style] "
"[-R inactive-border-style] [-x width] [-y height] "
"[-R inactive-border-style] [-T title] [-x width] [-y height] "
"[-X x-position] [-Y y-position] " CMD_TARGET_PANE_USAGE " "
"[shell-command [argument ...]]",
@@ -56,11 +56,11 @@ const struct cmd_entry cmd_split_window_entry = {
.name = "split-window",
.alias = "splitw",
.args = { "bc:de:fF:hIkl:m:p:PR:s:S:t:vZ", 0, -1, NULL },
.args = { "bc:de:EfF:hIkl:m:p:PR:s:S:t:T:vZ", 0, -1, NULL },
.usage = "[-bdefhIklPvZ] [-c start-directory] [-e environment] "
"[-F format] [-l size] [-m message] [-p percentage] "
"[-s style] [-S active-border-style] "
"[-R inactive-border-style] " CMD_TARGET_PANE_USAGE " "
"[-R inactive-border-style] [-T title] " CMD_TARGET_PANE_USAGE " "
"[shell-command [argument ...]]",
.target = { 't', CMD_FIND_PANE, 0 },
@@ -83,9 +83,9 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
struct window_pane *wp = target->wp, *new_wp;
struct layout_cell *lc = NULL;
struct cmd_find_state fs;
int input, is_floating, flags = 0;
int input, empty, is_floating, flags = 0;
const char *template, *style;
char *cause = NULL, *cp;
char *cause = NULL, *cp, *title;
struct args_value *av;
u_int count = args_count(args);
@@ -93,22 +93,33 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
is_floating = !args_has(args, 'L');
else
is_floating = 0;
input = (args_has(args, 'I') && count == 0);
flags = is_floating ? SPAWN_FLOATING : 0;
if (args_has(args, 'b'))
flags |= SPAWN_BEFORE;
if (args_has(args, 'f'))
flags |= SPAWN_FULLSIZE;
if (input || (count == 1 && *args_string(args, 0) == '\0'))
input = args_has(args, 'I');
if (input)
empty = 1;
else
empty = args_has(args, 'E');
if (empty &&
count != 0 &&
(count != 1 || *args_string(args, 0) != '\0')) {
cmdq_error(item, "command cannot be given for empty pane");
return (CMD_RETURN_ERROR);
}
if (empty)
flags |= SPAWN_EMPTY;
if (is_floating)
lc = layout_get_floating_cell(item, args, w, wp, lc, &cause);
lc = layout_get_floating_cell(item, args, w, wp, &cause);
else
lc = layout_get_tiled_cell(item, args, w, wp, flags, &cause);
if (cause != NULL) {
cmdq_error(item, "%s", cause);
cmdq_error(item, "size or position %s", cause);
free(cause);
return (CMD_RETURN_ERROR);
}
@@ -183,6 +194,12 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
"remain-on-exit-format",
0, "%s", args_get(args, 'm'));
}
if (args_has(args, 'T')) {
title = format_single_from_target(item, args_get(args, 'T'));
screen_set_title(&new_wp->base, title);
notify_pane("pane-title-changed", new_wp);
free(title);
}
if (input) {
switch (window_pane_start_input(new_wp, item, &cause)) {
@@ -209,7 +226,7 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
window_pop_zoom(wp->window);
server_redraw_window(wp->window);
}
server_status_session(s);
server_redraw_session(s);
if (args_has(args, 'P')) {
if ((template = args_get(args, 'F')) == NULL)

View File

@@ -79,7 +79,7 @@ cmd_swap_pane_exec(struct cmd *self, struct cmdq_item *item)
if (src_wp == dst_wp)
goto out;
if (window_pane_is_floating(src_wp) &&
if (window_pane_is_floating(src_wp) ||
window_pane_is_floating(dst_wp)) {
cmdq_error(item, "cannot swap floating panes");
return (CMD_RETURN_ERROR);

View File

@@ -116,6 +116,8 @@ format_job_cmp(struct format_job *fj1, struct format_job *fj2)
#define FORMAT_NOT 0x80000
#define FORMAT_NOT_NOT 0x100000
#define FORMAT_REPEAT 0x200000
#define FORMAT_QUOTE_ARGUMENTS 0x400000
#define FORMAT_RELATIVE 0x800000
/* Limit on recursion. */
#define FORMAT_LOOP_LIMIT 100
@@ -4079,6 +4081,50 @@ format_pretty_time(time_t t, int seconds)
return (xstrdup(s));
}
/* Make a relative time. */
static char *
format_relative_time(time_t t)
{
time_t now, age;
u_int d, h, m, s;
char out[32], sign;
time(&now);
if (t == now)
return (xstrdup("0s"));
if (t > now) {
sign = '+';
age = t - now;
} else {
sign = '-';
age = now - t;
}
d = age / 86400;
h = (age % 86400) / 3600;
m = (age % 3600) / 60;
s = age % 60;
if (d != 0) {
if (h != 0)
xsnprintf(out, sizeof out, "%c%ud%uh", sign, d, h);
else
xsnprintf(out, sizeof out, "%c%ud", sign, d);
} else if (h != 0) {
if (m != 0)
xsnprintf(out, sizeof out, "%c%uh%um", sign, h, m);
else
xsnprintf(out, sizeof out, "%c%uh", sign, h);
} else if (m != 0) {
if (s != 0)
xsnprintf(out, sizeof out, "%c%um%us", sign, m, s);
else
xsnprintf(out, sizeof out, "%c%um", sign, m);
} else
xsnprintf(out, sizeof out, "%c%us", sign, s);
return (xstrdup(out));
}
/* Find a format entry. */
static char *
format_find(struct format_tree *ft, const char *key, int modifiers,
@@ -4160,7 +4206,9 @@ found:
}
if (t == 0)
return (NULL);
if (modifiers & FORMAT_PRETTY)
if (modifiers & FORMAT_RELATIVE)
found = format_relative_time(t);
else if (modifiers & FORMAT_PRETTY)
found = format_pretty_time(t, 0);
else {
if (time_format != NULL) {
@@ -4199,6 +4247,11 @@ found:
found = format_quote_style(saved);
free(saved);
}
if (modifiers & FORMAT_QUOTE_ARGUMENTS) {
saved = found;
found = args_escape(saved);
free(saved);
}
return (found);
}
@@ -5160,6 +5213,8 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
break;
if (strchr(fm->argv[0], 'p') != NULL)
modifiers |= FORMAT_PRETTY;
else if (strchr(fm->argv[0], 'r') != NULL)
modifiers |= FORMAT_RELATIVE;
else if (fm->argc >= 2 &&
strchr(fm->argv[0], 'f') != NULL) {
free(time_format);
@@ -5172,6 +5227,8 @@ format_replace(struct format_expand_state *es, const char *key, size_t keylen,
else if (strchr(fm->argv[0], 'e') != NULL ||
strchr(fm->argv[0], 'h') != NULL)
modifiers |= FORMAT_QUOTE_STYLE;
else if (strchr(fm->argv[0], 'a') != NULL)
modifiers |= FORMAT_QUOTE_ARGUMENTS;
break;
case 'E':
modifiers |= FORMAT_EXPAND;

13
grid.c
View File

@@ -125,6 +125,8 @@ grid_extended_cell(struct grid_line *gl, struct grid_cell_entry *gce,
else if (gce->offset >= gl->extdsize)
fatalx("offset too big");
gl->flags |= GRID_LINE_EXTENDED;
if (gc->link != 0)
gl->flags |= GRID_LINE_HYPERLINK;
if (gc->flags & GRID_FLAG_TAB)
uc = gc->data.width;
@@ -285,9 +287,8 @@ static void
grid_free_line(struct grid *gd, u_int py)
{
free(gd->linedata[py].celldata);
gd->linedata[py].celldata = NULL;
free(gd->linedata[py].extddata);
gd->linedata[py].extddata = NULL;
memset(&gd->linedata[py], 0, sizeof gd->linedata[py]);
}
/* Free several lines. */
@@ -332,9 +333,7 @@ void
grid_destroy(struct grid *gd)
{
grid_free_lines(gd, 0, gd->hsize + gd->sy);
free(gd->linedata);
free(gd);
}
@@ -414,12 +413,14 @@ grid_collect_history(struct grid *gd, int all)
void
grid_remove_history(struct grid *gd, u_int ny)
{
u_int yy;
u_int yy, start;
if (ny > gd->hsize)
return;
start = gd->hsize + gd->sy - ny;
for (yy = 0; yy < ny; yy++)
grid_free_line(gd, gd->hsize + gd->sy - 1 - yy);
grid_free_line(gd, start + yy);
memset(&gd->linedata[start], 0, ny * sizeof *gd->linedata);
gd->hsize -= ny;
}

160
layout.c
View File

@@ -46,9 +46,6 @@ static int layout_set_size_check(struct window *, struct layout_cell *,
enum layout_type, int);
static void layout_resize_child_cells(struct window *,
struct layout_cell *);
static struct layout_cell *layout_active_neighbour(struct layout_cell *, int);
void layout_redistribute_cells(struct window *, struct layout_cell *,
enum layout_type);
/* Create a new layout cell. */
struct layout_cell *
@@ -253,9 +250,10 @@ layout_fix_offsets1(struct layout_cell *lc)
if (lc->type == LAYOUT_LEFTRIGHT) {
xoff = lc->xoff;
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
if (lcchild->type == LAYOUT_WINDOWPANE &&
if (lcchild->flags & LAYOUT_CELL_FLOATING ||
(lcchild->type == LAYOUT_WINDOWPANE &&
lcchild->wp != NULL &&
lcchild->wp->flags & PANE_HIDDEN)
(lcchild->wp->flags & PANE_HIDDEN)))
continue;
lcchild->xoff = xoff;
lcchild->yoff = lc->yoff;
@@ -266,9 +264,10 @@ layout_fix_offsets1(struct layout_cell *lc)
} else {
yoff = lc->yoff;
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
if (lcchild->type == LAYOUT_WINDOWPANE &&
if (lcchild->flags & LAYOUT_CELL_FLOATING ||
(lcchild->type == LAYOUT_WINDOWPANE &&
lcchild->wp != NULL &&
lcchild->wp->flags & PANE_HIDDEN)
(lcchild->wp->flags & PANE_HIDDEN)))
continue;
lcchild->xoff = lc->xoff;
lcchild->yoff = yoff;
@@ -285,6 +284,10 @@ layout_fix_offsets(struct window *w)
{
struct layout_cell *lc = w->layout_root;
/* Root consists of a single floating cell */
if (lc->flags & LAYOUT_CELL_FLOATING)
return;
lc->xoff = 0;
lc->yoff = 0;
@@ -493,8 +496,11 @@ layout_resize_adjust(struct window *w, struct layout_cell *lc,
/* Child cell runs in a different direction. */
if (lc->type != type) {
TAILQ_FOREACH(lcchild, &lc->cells, entry)
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
if (lcchild->flags & LAYOUT_CELL_FLOATING)
continue;
layout_resize_adjust(w, lcchild, type, change);
}
return;
}
@@ -506,6 +512,8 @@ layout_resize_adjust(struct window *w, struct layout_cell *lc,
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
if (change == 0)
break;
if (lcchild->flags & LAYOUT_CELL_FLOATING)
continue;
if (change > 0) {
layout_resize_adjust(w, lcchild, type, 1);
change--;
@@ -610,30 +618,33 @@ void
layout_destroy_cell(struct window *w, struct layout_cell *lc,
struct layout_cell **lcroot)
{
struct layout_cell *lcother, *lcparent;
struct layout_cell *lcother = NULL, *lcparent;
/*
* If no parent, this is either a floating pane or the last
* pane so window close is imminent and there is no need to
* resize anything.
*/
/* If no parent, this is the last pane in a window. */
lcparent = lc->parent;
if (lcparent == NULL) {
if (lc->wp != NULL && !window_pane_is_floating(lc->wp))
if (lc->wp != NULL)
*lcroot = NULL;
layout_free_cell(lc);
return;
}
/* Merge the space into the previous or next cell. */
if (lc == TAILQ_FIRST(&lcparent->cells))
lcother = TAILQ_NEXT(lc, entry);
else
lcother = TAILQ_PREV(lc, layout_cells, entry);
if (lcother != NULL && lcparent->type == LAYOUT_LEFTRIGHT)
layout_resize_adjust(w, lcother, lcparent->type, lc->sx + 1);
else if (lcother != NULL)
layout_resize_adjust(w, lcother, lcparent->type, lc->sy + 1);
if (~lc->flags & LAYOUT_CELL_FLOATING) {
/* Merge the space into the previous or next cell. */
if (lc == TAILQ_FIRST(&lcparent->cells))
lcother = TAILQ_NEXT(lc, entry);
else
lcother = TAILQ_PREV(lc, layout_cells, entry);
}
if (lcother != NULL && (~lcother->flags & LAYOUT_CELL_FLOATING)) {
if (lcparent->type == LAYOUT_LEFTRIGHT) {
layout_resize_adjust(w, lcother, lcparent->type,
lc->sx + 1);
} else {
layout_resize_adjust(w, lcother, lcparent->type,
lc->sy + 1);
}
}
/* Remove this from the parent's list. */
TAILQ_REMOVE(&lcparent->cells, lc, entry);
@@ -649,8 +660,10 @@ layout_destroy_cell(struct window *w, struct layout_cell *lc,
lc->parent = lcparent->parent;
if (lc->parent == NULL) {
lc->xoff = 0;
lc->yoff = 0;
if (~lc->flags & LAYOUT_CELL_FLOATING) {
lc->xoff = 0;
lc->yoff = 0;
}
/*
* If the sole remaining child is a hidden
@@ -774,6 +787,8 @@ layout_resize(struct window *w, u_int sx, u_int sy)
* out proportionately - this should leave the layout fitting the new
* window size.
*/
if (lc->type == LAYOUT_WINDOWPANE && (lc->flags & LAYOUT_CELL_FLOATING))
return;
xchange = sx - lc->sx;
xlimit = layout_resize_check(w, lc, LAYOUT_LEFTRIGHT);
if (xchange < 0 && xchange < -xlimit)
@@ -1086,6 +1101,8 @@ layout_resize_child_cells(struct window *w, struct layout_cell *lc)
count = 0;
previous = 0;
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
if (lcchild->flags & LAYOUT_CELL_FLOATING)
continue;
count++;
if (lc->type == LAYOUT_LEFTRIGHT)
previous += lcchild->sx;
@@ -1104,6 +1121,8 @@ layout_resize_child_cells(struct window *w, struct layout_cell *lc)
/* Resize children into the new size. */
idx = 0;
TAILQ_FOREACH(lcchild, &lc->cells, entry) {
if (lcchild->flags & LAYOUT_CELL_FLOATING)
continue;
if (lc->type == LAYOUT_TOPBOTTOM) {
lcchild->sx = lc->sx;
lcchild->xoff = lc->xoff;
@@ -1112,9 +1131,10 @@ layout_resize_child_cells(struct window *w, struct layout_cell *lc)
lc->type, lc->sx, count - idx, available);
available -= (lcchild->sx + 1);
}
if (lc->type == LAYOUT_LEFTRIGHT)
if (lc->type == LAYOUT_LEFTRIGHT) {
lcchild->sy = lc->sy;
else {
lcchild->yoff = lc->yoff;
} else {
lcchild->sy = layout_new_pane_size(w, previous, lcchild,
lc->type, lc->sy, count - idx, available);
available -= (lcchild->sy + 1);
@@ -1303,6 +1323,39 @@ layout_split_pane(struct window_pane *wp, enum layout_type type, int size,
return (lcnew);
}
/*
* Creates a cell for a new floating pane. This must be followed by
* layout_assign_pane before much else happens!
*/
struct layout_cell *
layout_floating_pane(struct window *w, u_int sx, u_int sy, int ox, int oy)
{
struct layout_cell *lc = w->layout_root, *lcnew, *lcparent;
if (lc->type == LAYOUT_WINDOWPANE) {
/*
* Adding a pane to a root that doesn't have a container. Must
* create and insert a new root.
*/
lcparent = layout_create_cell(NULL);
layout_make_node(lcparent, LAYOUT_TOPBOTTOM);
layout_set_size(lcparent, w->sx, w->sy, 0, 0);
w->layout_root = lcparent;
/* Insert the old cell. */
lc->parent = lcparent;
TAILQ_INSERT_HEAD(&lcparent->cells, lc, entry);
} else
lcparent = w->layout_root;
lcnew = layout_create_cell(lcparent);
TAILQ_INSERT_TAIL(&lcparent->cells, lcnew, entry);
lcnew->flags |= LAYOUT_CELL_FLOATING;
layout_set_size(lcnew, sx, sy, ox, oy);
return (lcnew);
}
/* Destroy the cell associated with a pane. */
void
layout_close_pane(struct window_pane *wp)
@@ -1314,6 +1367,7 @@ layout_close_pane(struct window_pane *wp)
/* Remove the cell. */
layout_destroy_cell(w, wp->layout_cell, &w->layout_root);
wp->layout_cell = NULL;
/* Fix pane offsets and sizes. */
if (w->layout_root != NULL) {
@@ -1470,49 +1524,37 @@ layout_get_tiled_cell(struct cmdq_item *item, struct args *args,
/* Get a new floating cell. */
struct layout_cell *
layout_get_floating_cell(struct cmdq_item *item, struct args *args,
struct window *w, __unused struct window_pane *wp, struct layout_cell *lc,
char **cause)
struct window *w, __unused struct window_pane *wp, char **cause)
{
u_int sx, sy, ox, oy;
int new = 0;
if (lc == NULL) {
lc = layout_create_cell(NULL);
new = 1;
}
sx = lc->sx; sy = lc->sy;
ox = lc->xoff; oy = lc->yoff;
struct layout_cell *lcnew;
int sx = w->sx / 2, sy = w->sy / 4;
int ox = INT_MAX, oy = INT_MAX;
if (args_has(args, 'x')) {
sx = args_percentage_and_expand(args, 'x', 0, USHRT_MAX, w->sx,
sx = args_percentage_and_expand(args, 'x', 0, w->sx - 1, w->sx,
item, cause);
if (*cause != NULL)
goto error;
return (NULL);
}
if (args_has(args, 'y')) {
sy = args_percentage_and_expand(args, 'y', 0, USHRT_MAX, w->sy,
sy = args_percentage_and_expand(args, 'y', 0, w->sy - 1, w->sy,
item, cause);
if (*cause != NULL)
goto error;
return (NULL);
}
if (args_has(args, 'X')) {
ox = args_percentage_and_expand(args, 'X', 0, USHRT_MAX, w->sx,
item, cause);
ox = args_percentage_and_expand(args, 'X', -sx, w->sx,
w->sx, item, cause);
if (*cause != NULL)
goto error;
return (NULL);
}
if (args_has(args, 'Y')) {
oy = args_percentage_and_expand(args, 'Y', 0, USHRT_MAX, w->sy,
item, cause);
oy = args_percentage_and_expand(args, 'Y', -sy, w->sy,
w->sy, item, cause);
if (*cause != NULL)
goto error;
return (NULL);
}
if (sx == UINT_MAX)
sx = w->sx / 2;
if (sy == UINT_MAX)
sy = w->sy / 4;
if (ox == INT_MAX) {
if (w->last_new_pane_x == 0)
ox = 4;
@@ -1533,13 +1575,7 @@ layout_get_floating_cell(struct cmdq_item *item, struct args *args,
}
w->last_new_pane_y = oy;
}
layout_set_size(lc, sx, sy, ox, oy);
lc->flags |= LAYOUT_CELL_FLOATING;
return (lc);
error:
if (new)
layout_destroy_cell(w, lc, &w->layout_root);
return (NULL);
lcnew = layout_floating_pane(w, sx, sy, ox, oy);
return (lcnew);
}

View File

@@ -1224,6 +1224,11 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
u_int i, x, y;
int choice, preview;
if (mtd->line_size == 0) {
*key = KEYC_NONE;
return (1);
}
if (KEYC_IS_MOUSE(*key) && m != NULL) {
if (cmd_mouse_at(mtd->wp, m, &x, &y, 0) != 0) {
*key = KEYC_NONE;

View File

@@ -647,6 +647,14 @@ const struct options_table_entry options_table[] = {
.text = "Colour of not active panes for 'display-panes'."
},
{ .name = "display-panes-format",
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SESSION,
.default_str = "#[align=right]#{pane_width}x#{pane_height}",
.text = "Format of text shown by 'display-panes', expanded for each "
"pane."
},
{ .name = "display-panes-time",
.type = OPTIONS_TABLE_NUMBER,
.scope = OPTIONS_TABLE_SESSION,
@@ -1028,7 +1036,8 @@ const struct options_table_entry options_table[] = {
.flags = OPTIONS_TABLE_IS_ARRAY,
.default_str = "DISPLAY KRB5CCNAME MSYSTEM SSH_ASKPASS SSH_AUTH_SOCK "
"SSH_AGENT_PID SSH_CONNECTION WAYLAND_DISPLAY "
"WINDOWID XAUTHORITY",
"WINDOWID XAUTHORITY XDG_CURRENT_DESKTOP "
"XDG_SESSION_DESKTOP XDG_SESSION_TYPE",
.text = "List of environment variables to update in the session "
"environment when a client is attached."
},

View File

@@ -4,9 +4,9 @@ PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
TMUX="$TEST_TMUX -Ltest -f/dev/null"
$TMUX kill-server 2>/dev/null
TMUX2="$TEST_TMUX -Ltest2"
TMUX2="$TEST_TMUX -Ltest2 -f/dev/null"
$TMUX2 kill-server 2>/dev/null
TMP=$(mktemp)

View File

@@ -11,9 +11,9 @@ PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
TMUX="$TEST_TMUX -Ltest -f/dev/null"
$TMUX kill-server 2>/dev/null
TMUX_OUTER="$TEST_TMUX -Ltest2"
TMUX_OUTER="$TEST_TMUX -Ltest2 -f/dev/null"
$TMUX_OUTER kill-server 2>/dev/null
trap "$TMUX kill-server 2>/dev/null; $TMUX_OUTER kill-server 2>/dev/null" 0 1 15

View File

@@ -6,7 +6,7 @@ PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
TMUX="$TEST_TMUX -Ltest -f/dev/null"
TMP=$(mktemp)
TMP2=$(mktemp)
trap "rm -f $TMP $TMP2" 0 1 15

View File

@@ -7,7 +7,7 @@ PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
TMUX="$TEST_TMUX -Ltest -f/dev/null"
$TMUX kill-server 2>/dev/null
TMP=$(mktemp)

View File

@@ -4,7 +4,7 @@ PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
TMUX="$TEST_TMUX -Ltest -f/dev/null"
$TMUX kill-server 2>/dev/null
TMP=$(mktemp)

View File

@@ -4,7 +4,7 @@ PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
TMUX="$TEST_TMUX -Ltest -f/dev/null"
$TMUX kill-server 2>/dev/null
TMP=$(mktemp)

View File

@@ -4,7 +4,7 @@ PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
TMUX="$TEST_TMUX -Ltest -f/dev/null"
$TMUX kill-server 2>/dev/null
for i in conf/*.conf; do

View File

@@ -4,7 +4,7 @@ PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
TMUX="$TEST_TMUX -Ltest -f/dev/null"
$TMUX kill-server 2>/dev/null
TMP=$(mktemp)

View File

@@ -8,7 +8,7 @@ PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
TMUX="$TEST_TMUX -Ltest -f/dev/null"
$TMUX kill-server 2>/dev/null
TMP=$(mktemp)

View File

@@ -4,7 +4,7 @@ PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -f/dev/null -Ltest"
TMUX="$TEST_TMUX -Ltest -f/dev/null"
$TMUX kill-server 2>/dev/null
$TMUX new -d -x40 -y10 \

View File

@@ -34,14 +34,17 @@ $TMUX send-keys -X previous-word
$TMUX send-keys -X copy-selection
[ "$($TMUX show-buffer)" = "line" ] || exit 1
# Test that `next-word-end` wraps around indented line breaks.
# Test that `next-word-end` stops at the end of the line.
$TMUX send-keys -X next-word
$TMUX send-keys -X next-word
$TMUX send-keys -X begin-selection
$TMUX send-keys -X next-word-end
$TMUX send-keys -X next-word-end
$TMUX send-keys -X copy-selection
[ "$($TMUX show-buffer)" = "$(printf "words\n\tIndented")" ] || exit 1
[ "$($TMUX show-buffer)" = "words" ] || exit 1
# Move to the next word for the following tests.
$TMUX send-keys -X next-word
# Test that `next-word` wraps around un-indented line breaks.
$TMUX send-keys -X next-word

View File

@@ -4,7 +4,7 @@ PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -f/dev/null -Ltest"
TMUX="$TEST_TMUX -Ltest -f/dev/null"
$TMUX kill-server 2>/dev/null
TMP=$(mktemp)

View File

@@ -4,7 +4,7 @@ PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
TMUX="$TEST_TMUX -Ltest -f/dev/null"
$TMUX kill-server 2>/dev/null
TMP=$(mktemp)

View File

@@ -4,7 +4,7 @@ PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
TMUX="$TEST_TMUX -Ltest -f/dev/null"
$TMUX kill-server 2>/dev/null
TMP=$(mktemp)

View File

@@ -4,7 +4,7 @@ PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
TMUX="$TEST_TMUX -Ltest -f/dev/null"
$TMUX kill-server 2>/dev/null
TMP=$(mktemp)

View File

@@ -9,16 +9,12 @@ PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
TMUX="$TEST_TMUX -Ltest -f/dev/null"
$TMUX kill-server 2>/dev/null
sleep 1
TMP=$(mktemp)
TMP2=$(mktemp)
TMP3=$(mktemp)
TMP4=$(mktemp)
TMP5=$(mktemp)
trap "rm -f $TMP $TMP2 $TMP3 $TMP4 $TMP5; $TMUX kill-server 2>/dev/null" 0 1 15
trap "rm -f $TMP; $TMUX kill-server 2>/dev/null" 0 1 15
$TMUX -f/dev/null new -d -x80 -y24 || exit 1
sleep 1
@@ -35,13 +31,14 @@ query_decrpm() {
_outfile=$1
_mode=$2
_setup=$3
_n=$4
$TMUX respawnw -k -t:0 -- sh -c "
exec 2>/dev/null
stty raw -echo
${_setup:+printf '$_setup'; sleep 0.2}
printf '\033[%s\$p' "$_mode"
dd bs=1 count=11 2>/dev/null | cat -v > $_outfile
dd bs=1 count=$_n 2>/dev/null | cat -v > $_outfile
sleep 0.2
" || exit 1
sleep 2
@@ -50,7 +47,7 @@ query_decrpm() {
# ------------------------------------------------------------------
# Test 1: mode 2026 should be reset by default (Ps=2)
# ------------------------------------------------------------------
query_decrpm "$TMP" "?2026"
query_decrpm "$TMP" "?2026" '' 11
actual=$(cat "$TMP")
expected='^[[?2026;2$y'
@@ -67,9 +64,9 @@ fi
# ------------------------------------------------------------------
# Test 2: set mode 2026 (SM ?2026), then query (expect Ps=1)
# ------------------------------------------------------------------
query_decrpm "$TMP2" "?2026" '\033[?2026h'
query_decrpm "$TMP" "?2026" '\033[?2026h' 11
actual=$(cat "$TMP2")
actual=$(cat "$TMP")
expected='^[[?2026;1$y'
if [ "$actual" = "$expected" ]; then
@@ -84,9 +81,9 @@ fi
# ------------------------------------------------------------------
# Test 3: mode 25 should return current value
# ------------------------------------------------------------------
query_decrpm "$TMP3" "?25" '\033[?25l'
query_decrpm "$TMP" "?25" '\033[?25l' 9
actual=$(cat "$TMP3")
actual=$(cat "$TMP")
expected='^[[?25;2$y'
if [ "$actual" = "$expected" ]; then
@@ -101,9 +98,9 @@ fi
# ------------------------------------------------------------------
# Test 4: mode ?9999 should return not recognized
# ------------------------------------------------------------------
query_decrpm "$TMP4" "?9999" '\033[?9999h'
query_decrpm "$TMP" "?9999" '\033[?9999h' 11
actual=$(cat "$TMP4")
actual=$(cat "$TMP")
expected='^[[?9999;0$y'
if [ "$actual" = "$expected" ]; then
@@ -122,9 +119,9 @@ exit $exit_status
# ------------------------------------------------------------------
# Test 5: mode 4 is reset by default
# ------------------------------------------------------------------
query_decrpm "$TMP5" "4" '\033[4h'
query_decrpm "$TMP" "4" '\033[4h' 11
actual=$(cat "$TMP5")
actual=$(cat "$TMP")
expected='^[[4;1$y'
if [ "$actual" = "$expected" ]; then

View File

@@ -6,7 +6,7 @@ PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
TMUX="$TEST_TMUX -Ltest -f/dev/null"
# test_format $format $expected_result
test_format()

View File

@@ -7,7 +7,7 @@ PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
TMUX="$TEST_TMUX -Ltest -f/dev/null"
$TMUX kill-server 2>/dev/null
$TMUX -f/dev/null has -tfoo </dev/null 2>/dev/null && exit 1

View File

@@ -7,7 +7,7 @@ PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
TMUX="$TEST_TMUX -Ltest -f/dev/null"
$TMUX kill-server 2>/dev/null
TMP=$(mktemp)

View File

@@ -7,7 +7,7 @@ PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
TMUX="$TEST_TMUX -Ltest -f/dev/null"
$TMUX kill-server 2>/dev/null
TMP=$(mktemp)

View File

@@ -7,7 +7,7 @@ PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
TMUX="$TEST_TMUX -Ltest -f/dev/null"
$TMUX kill-server 2>/dev/null
TMP=$(mktemp)

View File

@@ -4,7 +4,7 @@ PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
TMUX="$TEST_TMUX -Ltest -f/dev/null"
$TMUX kill-server 2>/dev/null
sleep 1
$TMUX -f/dev/null new -x20 -y2 -d \; set -g escape-time 0 || exit 1

View File

@@ -6,7 +6,7 @@ PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
TMUX="$TEST_TMUX -Ltest -f/dev/null"
$TMUX kill-server 2>/dev/null
sleep 1

View File

@@ -6,7 +6,7 @@ PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
TMUX="$TEST_TMUX -Ltest -f/dev/null"
$TMUX kill-server 2>/dev/null
TMP=$(mktemp)

View File

@@ -6,7 +6,7 @@ PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
TMUX="$TEST_TMUX -Ltest -f/dev/null"
$TMUX kill-server 2>/dev/null
TMP=$(mktemp)

View File

@@ -5,14 +5,14 @@
PATH=/bin:/usr/bin
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
TMUX="$TEST_TMUX -Ltest -f/dev/null"
$TMUX kill-server 2>/dev/null
TERM=$($TMUX start \; show -gv default-terminal)
TMP=$(mktemp)
OUT=$(mktemp)
SCRIPT=$(mktemp)
#trap "rm -f $TMP $OUT $SCRIPT" 0 1 15
trap "rm -f $TMP $OUT $SCRIPT" 0 1 15
cat <<EOF >$SCRIPT
(

View File

@@ -8,7 +8,7 @@ PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
TMUX="$TEST_TMUX -Ltest -f/dev/null"
$TMUX kill-server 2>/dev/null
TMP=$(mktemp)

View File

@@ -6,7 +6,7 @@ PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
TMUX="$TEST_TMUX -Ltest -f/dev/null"
$TMUX kill-server 2>/dev/null
TMP=$(mktemp)

View File

@@ -6,7 +6,7 @@ PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
TMUX="$TEST_TMUX -Ltest -f/dev/null"
$TMUX kill-server 2>/dev/null
TMP=$(mktemp)

View File

@@ -4,7 +4,7 @@ PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
TMUX="$TEST_TMUX -Ltest -f/dev/null"
$TMUX kill-server 2>/dev/null
$TMUX new -d

View File

@@ -7,7 +7,7 @@ PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
TMUX="$TEST_TMUX -Ltest -f/dev/null"
$TMUX kill-server 2>/dev/null
TMP=$(mktemp)

View File

@@ -10,7 +10,7 @@ PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
TMUX="$TEST_TMUX -Ltest -f/dev/null"
$TMUX kill-server 2>/dev/null
TMP1=$(mktemp)

View File

@@ -17,9 +17,9 @@ if command -v bash >/dev/null 2>&1; then
fi
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
TMUX="$TEST_TMUX -Ltest -f/dev/null"
$TMUX kill-server 2>/dev/null
TMUX2="$TEST_TMUX -Ltest2"
TMUX2="$TEST_TMUX -Ltest2 -f/dev/null"
$TMUX2 kill-server 2>/dev/null
$TMUX2 -f/dev/null new -d "$TMUX -f/dev/null new -- $shell"

View File

@@ -4,9 +4,9 @@ PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
TMUX="$TEST_TMUX -Ltest -f/dev/null"
$TMUX kill-server 2>/dev/null
TMUX2="$TEST_TMUX -Ltest2"
TMUX2="$TEST_TMUX -Ltest2 -f/dev/null"
$TMUX2 kill-server 2>/dev/null
TMP=$(mktemp)

View File

@@ -90,7 +90,7 @@ You should see the Greek word 'kosme': "κόσμε"
2.3.2 U-0000E000 = ee 80 80 = "" |
2.3.3 U-0000FFFD = ef bf bd = "<22>" |
2.3.4 U-0010FFFF = f4 8f bf bf = "􏿿" |
2.3.5 U-00110000 = f4 90 80 80 = "<22><EFBFBD><EFBFBD><EFBFBD>" |
2.3.5 U-00110000 = f4 90 80 80 = "<22>" |
|
3 Malformed sequences |
|

View File

@@ -4,7 +4,7 @@ PATH=/bin:/usr/bin
TERM=screen
[ -z "$TEST_TMUX" ] && TEST_TMUX=$(readlink -f ../tmux)
TMUX="$TEST_TMUX -Ltest"
TMUX="$TEST_TMUX -Ltest -f/dev/null"
TMP=$(mktemp)
trap "rm -f $TMP" 0 1 15
$TMUX kill-server 2>/dev/null

View File

@@ -627,21 +627,23 @@ screen_write_fast_copy(struct screen_write_ctx *ctx, struct screen *src,
struct grid_line *gl, *sgl;
struct grid_cell gc;
u_int xx, yy, cx = s->cx, cy = s->cy;
int yoff = 0;
int xoff = 0, yoff = 0;
struct visible_ranges *r;
if (nx == 0 || ny == 0)
return;
if (wp != NULL)
if (wp != NULL) {
xoff = wp->xoff;
yoff = wp->yoff;
}
for (yy = py; yy < py + ny; yy++) {
if (yy >= gd->hsize + gd->sy)
break;
s->cx = cx;
screen_write_initctx(ctx, &ttyctx, 0, 0);
r = screen_redraw_get_visible_ranges(wp, px, s->cy + yoff, nx,
NULL);
r = screen_redraw_get_visible_ranges(wp, xoff + s->cx,
s->cy + yoff, nx, NULL);
for (xx = px; xx < px + nx; xx++) {
gl = grid_get_line(gd, yy);
sgl = grid_get_line(s->grid, s->cy);
@@ -653,7 +655,7 @@ screen_write_fast_copy(struct screen_write_ctx *ctx, struct screen *src,
break;
grid_view_set_cell(s->grid, s->cx, s->cy, &gc);
if (!screen_redraw_is_visible(r, px))
if (!screen_redraw_is_visible(r, xoff + s->cx))
break;
ttyctx.cell = &gc;
ttyctx.flags &= (TTY_CTX_OVERLAY_SYNC|TTY_CTX_SYNC);
@@ -2925,16 +2927,22 @@ void
screen_write_alternateon(struct screen_write_ctx *ctx, struct grid_cell *gc,
int cursor)
{
struct tty_ctx ttyctx;
struct window_pane *wp = ctx->wp;
struct tty_ctx ttyctx;
struct window_pane *wp = ctx->wp;
struct window_pane_resize *r, *r1;
if (wp != NULL && !options_get_number(wp->options, "alternate-screen"))
return;
screen_write_collect_flush(ctx, 0, __func__);
screen_alternate_on(ctx->s, gc, cursor);
if (!screen_alternate_on(ctx->s, gc, cursor))
return;
if (wp != NULL) {
TAILQ_FOREACH_SAFE (r, &wp->resize_queue, entry, r1) {
TAILQ_REMOVE(&wp->resize_queue, r, entry);
free(r);
}
layout_fix_panes(wp->window, NULL);
server_redraw_window_borders(wp->window);
}
@@ -2956,7 +2964,8 @@ screen_write_alternateoff(struct screen_write_ctx *ctx, struct grid_cell *gc,
return;
screen_write_collect_flush(ctx, 0, __func__);
screen_alternate_off(ctx->s, gc, cursor);
if (!screen_alternate_off(ctx->s, gc, cursor))
return;
if (wp != NULL) {
layout_fix_panes(wp->window, NULL);

View File

@@ -672,7 +672,7 @@ screen_reflow(struct screen *s, u_int new_x, u_int *cx, u_int *cy, int cursor)
* Enter alternative screen mode. A copy of the visible screen is saved and the
* history is not updated.
*/
void
int
screen_alternate_on(struct screen *s, struct grid_cell *gc, int cursor)
{
u_int sx, sy;
@@ -681,7 +681,7 @@ screen_alternate_on(struct screen *s, struct grid_cell *gc, int cursor)
#endif
if (SCREEN_IS_ALTERNATE(s))
return;
return 0;
sx = screen_size_x(s);
sy = screen_size_y(s);
@@ -703,10 +703,12 @@ screen_alternate_on(struct screen *s, struct grid_cell *gc, int cursor)
s->saved_flags = s->grid->flags;
s->grid->flags &= ~GRID_HISTORY;
return 1;
}
/* Exit alternate screen mode and restore the copied grid. */
void
int
screen_alternate_off(struct screen *s, struct grid_cell *gc, int cursor)
{
u_int sx = screen_size_x(s), sy = screen_size_y(s);
@@ -738,7 +740,7 @@ screen_alternate_off(struct screen *s, struct grid_cell *gc, int cursor)
s->cx = screen_size_x(s) - 1;
if (s->cy > screen_size_y(s) - 1)
s->cy = screen_size_y(s) - 1;
return;
return 0;
}
/* Restore the saved grid. */
@@ -767,6 +769,8 @@ screen_alternate_off(struct screen *s, struct grid_cell *gc, int cursor)
s->cx = screen_size_x(s) - 1;
if (s->cy > screen_size_y(s) - 1)
s->cy = screen_size_y(s) - 1;
return 1;
}
/* Get mode as a string. */

View File

@@ -1623,10 +1623,7 @@ server_client_resize_timer(__unused int fd, __unused short events, void *data)
static void
server_client_check_pane_resize(struct window_pane *wp)
{
struct window_pane_resize *r;
struct window_pane_resize *r1;
struct window_pane_resize *first;
struct window_pane_resize *last;
struct window_pane_resize *r, *r1, *first, *last;
struct timeval tv = { .tv_usec = 250000 };
if (TAILQ_EMPTY(&wp->resize_queue))
@@ -1852,12 +1849,13 @@ server_client_reset_state(struct client *c)
cx = wp->xoff + (int)s->cx - (int)ox;
cy = wp->yoff + (int)s->cy - (int)oy;
r = screen_redraw_get_visible_ranges(wp, cx, cy, 1, NULL);
if (!screen_redraw_is_visible(r, cx))
cursor = 0;
if (status_at_line(c) == 0)
cy += status_line_size(c);
}
r = screen_redraw_get_visible_ranges(wp, cx, cy, 1, NULL);
if (!screen_redraw_is_visible(r, cx))
cursor = 0;
if (!cursor)
mode &= ~MODE_CURSOR;

130
tmux.1
View File

@@ -1206,7 +1206,7 @@ Kill the
.Nm
server and clients and destroy all sessions.
.It Xo Ic kill\-session
.Op Fl aC
.Op Fl aCg
.Op Fl t Ar target\-session
.Xc
Destroy the given session, closing any windows linked to it and no other
@@ -1214,6 +1214,10 @@ sessions, and detaching all clients attached to it.
If
.Fl a
is given, all sessions but the specified one is killed.
If
.Fl g
is given and the session is in a session group, all sessions in the group are
killed.
The
.Fl C
flag clears alerts (bell, activity, or silence) in all windows linked to the
@@ -2310,7 +2314,6 @@ cursor on that line.
Scroll pane in copy\-mode when bound to a mouse drag event.
.Fl e
causes copy mode to exit when at the bottom.
.Pp
.It Xo
.Ic scroll\-top
.Xc
@@ -2666,7 +2669,7 @@ but a different format may be specified with
.Fl F .
.Tg capturep
.It Xo Ic capture\-pane
.Op Fl aepPqCJMN
.Op Fl aeFHLpPqCJMN
.Op Fl b Ar buffer\-name
.Op Fl E Ar end\-line
.Op Fl S Ar start\-line
@@ -2706,6 +2709,26 @@ implies
.Fl P
captures only any output that the pane has received that is the beginning of an
as-yet incomplete escape sequence.
.Fl L
includes the line number at the start of each line and
.Fl F
includes the flags (where
.Ql -
is no flags,
.Ql D
is an unused line,
.Ql O
is a line marked as output,
.Ql P
is a line marked as a prompt,
.Ql X
is a line containing extended cells and
.Ql H
is a line with hyperlinks).
With
.Fl H ,
only hyperlinks in the specified lines are captured.
Multiple hyperlinks on the same line are separated by spaces.
.Pp
.Fl S
and
@@ -2721,7 +2744,7 @@ the end of the visible pane.
The default is to capture only the visible contents of the pane.
.It Xo
.Ic choose\-client
.Op Fl NryZ
.Op Fl hkNryZ
.Op Fl F Ar format
.Op Fl f Ar filter
.Op Fl K Ar key\-format
@@ -2792,12 +2815,20 @@ If a filter would lead to an empty list, it is ignored.
specifies the format for each item in the list and
.Fl K
a format for each shortcut key; both are evaluated once for each line.
.Pp
.Fl N
starts without the preview or if given twice with the larger preview.
This command works only if at least one client is attached.
.Fl h
hides the pane containing the mode.
.Fl k
kills the pane when the mode is exited.
.Pp
The
.Ic choose-client
command works only if at least one client is attached.
.It Xo
.Ic choose\-tree
.Op Fl GNrswyZ
.Op Fl GhkNrswyZ
.Op Fl F Ar format
.Op Fl f Ar filter
.Op Fl K Ar key\-format
@@ -2882,15 +2913,30 @@ If a filter would lead to an empty list, it is ignored.
specifies the format for each item in the tree and
.Fl K
a format for each shortcut key; both are evaluated once for each line.
.Fl N
starts without the preview or if given twice with the larger preview.
.Fl G
includes all sessions in any session groups in the tree rather than only the
first.
This command works only if at least one client is attached.
.Pp
.Fl N
starts without the preview or if given twice with the larger preview.
.Fl h
hides the pane containing the mode.
.Fl k
kills the pane when the mode is exited.
.Fl h
and
.Fl k
are intended to ease use of the mode in a floating pane; for example:
.Bd -literal -offset indent
bind s 'new-pane -x50% -y50% -E; choose-tree -hks'
.Ed
.Pp
The
.Ic choose-tree
command works only if at least one client is attached.
.It Xo
.Ic customize\-mode
.Op Fl NZ
.Op Fl kNZ
.Op Fl F Ar format
.Op Fl f Ar filter
.Op Fl t Ar target\-pane
@@ -2936,9 +2982,15 @@ the item in the list is not shown, otherwise it is shown.
If a filter would lead to an empty list, it is ignored.
.Fl F
specifies the format for each item in the tree.
.Pp
.Fl N
starts without the option information.
This command works only if at least one client is attached.
.Fl k
kills the pane when the mode is exited.
.Pp
The
.Ic customize-mode
command works only if at least one client is attached.
.It Xo
.Tg displayp
.Ic display\-panes
@@ -3009,7 +3061,9 @@ The default is
.Fl Z
zooms the pane.
.Pp
This command works only if at least one client is attached.
The
.Ic find-window
command works only if at least one client is attached.
.Tg floatp
.It Xo Ic float\-pane
.Op Fl h Ar height
@@ -3371,6 +3425,7 @@ but a different format may be specified with
.Op Fl s Ar style
.Op Fl S Ar active\-border\-style
.Op Fl t Ar target\-pane
.Op Fl T Ar title
.Op Ar shell\-command Op Ar argument ...
.Xc
.D1 Pq alias: Ic newp
@@ -3389,6 +3444,8 @@ sets the border style when the pane is active and
.Fl R
sets the border style when the pane is inactive (see
.Sx STYLES ) .
.Fl T
sets the pane title.
.Pp
.Fl h
does a horizontal split and
@@ -3433,15 +3490,16 @@ but also sets the
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.
.Fl E ,
or an empty
.Ar shell\-command ,
(\[aq]\[aq]) will create an empty pane with no command running in it;
.Ic display-message
.Fl I
can write to an empty pane.
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.
flag 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 &
@@ -3785,6 +3843,7 @@ the command behaves like
.Op Fl s Ar style
.Op Fl S Ar active\-border\-style
.Op Fl t Ar target\-pane
.Op Fl T Ar title
.Op Ar shell\-command Op Ar argument ...
.Xc
.D1 Pq alias: Ic splitw
@@ -4848,6 +4907,12 @@ command to show the indicator for the active pane.
Set the colour used by the
.Ic display\-panes
command to show the indicators for inactive panes.
.It Ic display\-panes\-format Ar format
Set the
.Ar format
of the text shown by the
.Ic display\-panes
command, expanded for each pane.
.It Ic display\-panes\-time Ar time
Set the time in milliseconds for which the indicators shown by the
.Ic display\-panes
@@ -6375,9 +6440,15 @@ gives
gives
.Ql Sun Oct 25 09:25:02 2015 .
Adding
.Ql p (
.Ql `t/p` )
.Ql p
.Pq Ql t/p
will use shorter but less accurate time format for times in the past.
.Ql r
.Pq Ql t/r
will show the time relative to the current time, for example
.Ql \-1m
or
.Ql +2m23s .
A custom format may be given using an
.Ql f
suffix (note that
@@ -6405,12 +6476,17 @@ of the variable respectively.
.Ql q:\&
will escape
.Xr sh 1
special characters or with a
special characters; with a
.Ql h
suffix, escape hash characters (so
.Ql #
becomes
.Ql ## ) .
.Ql ## ) ;
or with
.Ql a
escape
.Nm
command arguments.
.Ql E:\&
will expand the format twice, for example
.Ql #{E:status\-left}
@@ -7703,7 +7779,7 @@ The buffer commands are as follows:
.Bl -tag -width Ds
.It Xo
.Ic choose\-buffer
.Op Fl NryZ
.Op Fl kNryZ
.Op Fl F Ar format
.Op Fl f Ar filter
.Op Fl K Ar key\-format
@@ -7774,7 +7850,11 @@ specifies the format for each item in the list and
a format for each shortcut key; both are evaluated once for each line.
.Fl N
starts without the preview.
This command works only if at least one client is attached.
.Fl k
kills the pane when the mode is exited.
The
.Ic choose-buffer
command works only if at least one client is attached.
.Tg clearhist
.It Xo Ic clear\-history
.Op Fl H

17
tmux.h
View File

@@ -780,6 +780,7 @@ struct colour_palette {
#define GRID_LINE_DEAD 0x4
#define GRID_LINE_START_PROMPT 0x8
#define GRID_LINE_START_OUTPUT 0x10
#define GRID_LINE_HYPERLINK 0x20
/* Grid string flags. */
#define GRID_STRING_WITH_SEQUENCES 0x1
@@ -1180,6 +1181,8 @@ struct window_mode_entry {
struct screen *screen;
u_int prefix;
int kill;
TAILQ_ENTRY(window_mode_entry) entry;
};
@@ -1270,7 +1273,7 @@ struct window_pane {
#define PANE_FOCUSED 0x4
#define PANE_VISITED 0x8
#define PANE_ZOOMED 0x10
/* unused 0x20 */
/* 0x20 unused */
#define PANE_INPUTOFF 0x40
#define PANE_CHANGED 0x80
#define PANE_EXITED 0x100
@@ -1482,8 +1485,7 @@ TAILQ_HEAD(layout_cells, layout_cell);
struct layout_cell {
enum layout_type type;
/* unused 0x1 */
#define LAYOUT_CELL_FLOATING 0x2
#define LAYOUT_CELL_FLOATING 0x1
int flags;
struct layout_cell *parent;
@@ -3397,8 +3399,8 @@ void screen_hide_selection(struct screen *);
int screen_check_selection(struct screen *, u_int, u_int);
int screen_select_cell(struct screen *, struct grid_cell *,
const struct grid_cell *);
void screen_alternate_on(struct screen *, struct grid_cell *, int);
void screen_alternate_off(struct screen *, struct grid_cell *, int);
int screen_alternate_on(struct screen *, struct grid_cell *, int);
int screen_alternate_off(struct screen *, struct grid_cell *, int);
const char *screen_mode_to_string(int);
const char *screen_print(struct screen *, int);
@@ -3547,12 +3549,13 @@ void layout_assign_pane(struct layout_cell *, struct window_pane *,
int);
struct layout_cell *layout_split_pane(struct window_pane *, enum layout_type,
int, int);
struct layout_cell *layout_floating_pane(struct window *, u_int, u_int, int,
int);
void layout_close_pane(struct window_pane *);
int layout_spread_cell(struct window *, struct layout_cell *);
void layout_spread_out(struct window_pane *);
struct layout_cell *layout_get_floating_cell(struct cmdq_item *, struct args *,
struct window *, struct window_pane *, struct layout_cell *,
char **);
struct window *, struct window_pane *, char **);
struct layout_cell *layout_get_tiled_cell(struct cmdq_item *, struct args *,
struct window *, struct window_pane *, int, char **);

View File

@@ -82,6 +82,7 @@ struct window_client_modedata {
char *format;
char *key_format;
char *command;
int hide_preview_this_pane;
struct window_client_itemdata **item_list;
u_int item_size;
@@ -162,9 +163,10 @@ window_client_build(void *modedata, struct sort_criteria *sort_crit,
}
static void
window_client_draw(__unused void *modedata, void *itemdata,
window_client_draw(void *modedata, void *itemdata,
struct screen_write_ctx *ctx, u_int sx, u_int sy)
{
struct window_client_modedata *data = modedata;
struct window_client_itemdata *item = itemdata;
struct client *c = item->c;
struct screen *s = ctx->s;
@@ -174,6 +176,12 @@ window_client_draw(__unused void *modedata, void *itemdata,
if (c->session == NULL || (c->flags & CLIENT_UNATTACHEDFLAGS))
return;
wp = c->session->curw->window->active;
if (data->hide_preview_this_pane && wp == data->wp) {
if (!TAILQ_EMPTY(&c->session->curw->window->last_panes))
wp = TAILQ_FIRST(&c->session->curw->window->last_panes);
else
wp = NULL;
}
lines = status_line_size(c);
if (lines >= sy)
@@ -184,7 +192,8 @@ window_client_draw(__unused void *modedata, void *itemdata,
at = 0;
screen_write_cursormove(ctx, cx, cy + at, 0);
screen_write_preview(ctx, &wp->base, sx, sy - 2 - lines);
if (wp != NULL)
screen_write_preview(ctx, &wp->base, sx, sy - 2 - lines);
if (at != 0)
screen_write_cursormove(ctx, cx, cy + 2, 0);
@@ -270,6 +279,7 @@ window_client_init(struct window_mode_entry *wme,
wme->data = data = xcalloc(1, sizeof *data);
data->wp = wp;
data->hide_preview_this_pane = args != NULL && args_has(args, 'h');
if (args == NULL || !args_has(args, 'F'))
data->format = xstrdup(WINDOW_CLIENT_DEFAULT_FORMAT);

View File

@@ -113,6 +113,7 @@ struct window_tree_modedata {
char *key_format;
char *command;
int squash_groups;
int hide_preview_this_pane;
int prompt_flags;
struct window_tree_itemdata **item_list;
@@ -289,6 +290,8 @@ window_tree_build_window(struct session *s, struct winlink *wl,
if (n == 0)
goto empty;
for (i = 0; i < n; i++) {
if (data->hide_preview_this_pane && l[i] == data->wp)
continue;
if (window_tree_filter_pane(s, wl, l[i], filter))
window_tree_build_pane(s, wl, l[i], modedata, mti);
}
@@ -580,6 +583,10 @@ window_tree_draw_window(struct window_tree_modedata *data, struct session *s,
struct options *oo;
total = window_count_panes(w, 1);
if (data->hide_preview_this_pane && data->wp->window == w)
total--;
if (total == 0)
return;
if (sx / total < 24) {
visible = sx / 24;
@@ -590,6 +597,8 @@ window_tree_draw_window(struct window_tree_modedata *data, struct session *s,
current = 0;
TAILQ_FOREACH(wp, &w->panes, entry) {
if (data->hide_preview_this_pane && wp == data->wp)
continue;
if (wp == w->active)
break;
current++;
@@ -653,6 +662,8 @@ window_tree_draw_window(struct window_tree_modedata *data, struct session *s,
i = loop = 0;
TAILQ_FOREACH(wp, &w->panes, entry) {
if (data->hide_preview_this_pane && wp == data->wp)
continue;
if (loop == end)
break;
if (loop < start) {
@@ -704,6 +715,7 @@ static void
window_tree_draw(void *modedata, void *itemdata, struct screen_write_ctx *ctx,
u_int sx, u_int sy)
{
struct window_tree_modedata *data = modedata;
struct window_tree_itemdata *item = itemdata;
struct session *sp;
struct winlink *wl;
@@ -723,7 +735,8 @@ window_tree_draw(void *modedata, void *itemdata, struct screen_write_ctx *ctx,
window_tree_draw_window(modedata, sp, wl, ctx, sx, sy);
break;
case WINDOW_TREE_PANE:
screen_write_preview(ctx, &wp->base, sx, sy);
if (!data->hide_preview_this_pane || wp != data->wp)
screen_write_preview(ctx, &wp->base, sx, sy);
break;
}
}
@@ -932,6 +945,7 @@ window_tree_init(struct window_mode_entry *wme, struct cmd_find_state *fs,
else
data->command = xstrdup(args_string(args, 0));
data->squash_groups = !args_has(args, 'G');
data->hide_preview_this_pane = args_has(args, 'h');
if (args_has(args, 'y'))
data->prompt_flags = PROMPT_ACCEPT;

View File

@@ -1280,6 +1280,7 @@ window_pane_set_mode(struct window_pane *wp, struct window_pane *swp,
TAILQ_INSERT_HEAD(&wp->modes, wme, entry);
wme->screen = wme->mode->init(wme, fs, args);
}
wme->kill = args_has(args, 'k');
wp->screen = wme->screen;
wp->flags |= (PANE_REDRAW|PANE_REDRAWSCROLLBAR|PANE_CHANGED);
@@ -1297,11 +1298,13 @@ window_pane_reset_mode(struct window_pane *wp)
{
struct window_mode_entry *wme, *next;
struct window *w = wp->window;
int kill;
if (TAILQ_EMPTY(&wp->modes))
return;
wme = TAILQ_FIRST(&wp->modes);
kill = wme->kill;
TAILQ_REMOVE(&wp->modes, wme, entry);
wme->mode->free(wme);
free(wme);
@@ -1324,6 +1327,9 @@ window_pane_reset_mode(struct window_pane *wp)
server_redraw_window_borders(wp->window);
server_status_window(wp->window);
notify_pane("pane-mode-changed", wp);
if (kill)
server_kill_pane(wp);
}
void