110 Commits
3.4 ... 3.5

Author SHA1 Message Date
Nicholas Marriott
ac44566c9c tmux 3.5. 2024-09-27 08:56:39 +01:00
Thomas Adam
64f1076d97 Merge branch 'obsd-master' 2024-09-17 00:01:09 +01:00
nicm
489c69f5ed Add copy mode commands which were missed when descriptions were added,
from Julian Prein, GitHub issue 4121.
2024-09-16 20:46:58 +00:00
nicm
f897049935 Change the behaviour of extended-keys always slightly so that
applications can still enter mode 2 if they want, they just cannot turn
extended keys off entirely. From Stanislav Kljuhhin.
2024-09-16 20:38:48 +00:00
nicm
d8b66110f7 Add a prefix timeout option, from Conor Taylor in GitHub issue 4108. 2024-09-16 20:28:22 +00:00
Nicholas Marriott
8b1a3bb2e5 Only default --enable-debug if the user has not turned it off, from Ken Lau. 2024-09-16 21:19:43 +01:00
Thomas Adam
37771a5a8d Merge branch 'obsd-master' 2024-09-11 22:01:10 +01:00
nicm
3a8a31d8d2 Mouse move keys are not useful as key bindings because we do not turn
them on unless the application requests them. Ignore them so they do not
cause the prefix to be canceled, GitHub issue 4111.
2024-09-11 19:12:33 +00:00
Nicholas Marriott
c36ffcbe56 Typo from Bastian Venthur. 2024-09-06 13:09:43 +01:00
Thomas Adam
3d8ead8a97 Merge branch 'obsd-master' 2024-08-28 10:27:21 +01:00
nicm
141cd78407 Display hyperlinks in copy mode and add copy_cursor_hyperlink format to
get the hyperlink under the cursor.
2024-08-27 07:49:07 +00:00
nicm
d0c8124661 Add search_count and search_count_partial formats in copy mode, GitHub
issue 4091.
2024-08-27 07:31:26 +00:00
nicm
2917bc5274 Do not reset mouse pane if clicked on status line, it may have been set
by a range.
2024-08-27 07:25:27 +00:00
nicm
2d1e93447e Use strtonum instead of atoi. 2024-08-26 13:02:15 +00:00
nicm
31b6c9356c C-h should not be treated specially and represented internally as \b but
as C-h like the other Ctrl keys. Backspace is already handled separately
if it VERASE.
2024-08-26 07:45:05 +00:00
nicm
9e2a7c28f5 Pass the screen_redraw_ctx struct into more functions instead of
individual arguments (for example for the pane status), from Michael
Grant.
2024-08-26 07:34:40 +00:00
nicm
73b2277af8 Client flags was changed to uint64_t a while ago, fix a few cases where
it is still int (do not matter now but will with some new flags). From
Michael Grant.
2024-08-26 07:30:46 +00:00
nicm
a84c109604 Add window_pane_mode helper function to tell if a pane is in copy mode,
from Michael Grant.
2024-08-26 07:14:40 +00:00
nicm
4823acca8f Add copy-mode -d flag to scroll a page down if in copy mode already,
from Michael Grant.
2024-08-26 07:09:34 +00:00
Thomas Adam
34807388b0 Merge branch 'obsd-master' 2024-08-23 16:01:10 +01:00
nicm
08be883297 Ignore internal function keys if they have not got an entry in the key
table.
2024-08-23 13:25:39 +00:00
Thomas Adam
13bd0e46db Merge branch 'obsd-master' 2024-08-23 14:01:08 +01:00
nicm
6e9a914014 Check for exact match for layout name before looking for a prefix match. 2024-08-23 10:19:06 +00:00
Thomas Adam
7990e5fa8f Merge branch 'obsd-master' 2024-08-22 12:01:07 +01:00
nicm
4860a58d07 Clear overlay when command prompt is entered. Also fix some spacing in
man page pointed out by jmc.
2024-08-22 09:05:51 +00:00
Thomas Adam
99af9f23bd Merge branch 'obsd-master' 2024-08-22 08:01:08 +01:00
nicm
9ebbe2cca7 Short Ctrl keys like ^A need to be converted to lowercase so they end up
as 'a'|KEYC_CTRL to match the new internal representation. Problem
reported by naddy@.
2024-08-22 05:39:55 +00:00
Thomas Adam
692bae9ea6 Merge branch 'obsd-master' 2024-08-21 08:01:09 +01:00
nicm
a6645c4de4 Mention that load- and save-buffer can use stdin, from Ramon Fischer. 2024-08-21 05:06:45 +00:00
nicm
06292baadc Add mirrored versions of the main-horizontal and main-vertical layouts where
the main pane is bottom or right instead of top or left, from Sherwyn Sen.
2024-08-21 05:03:13 +00:00
nicm
ceda0a68ae C-Space and Meta keys should not be translated in mode 1 extended keys. 2024-08-21 04:55:57 +00:00
nicm
4fa90c9acf Set the default for extended-keys back to off because it appears emacs turns
the keys on but does not correctly handle them except in xterm (!). Also fix so
that off takes effect as expected.
2024-08-21 04:37:42 +00:00
nicm
c7e61a01e5 Revamp extended keys support to more closely match xterm and support
mode 2 as well as mode 1. From Stanislav Kljuhhin (GitHub issue 4038).

This changes tmux to always request mode 2 from parent terminal, change
to an unambiguous internal representation of keys, and adds an option
(extended-keys-format) to control the format similar to the xterm(1)
formatOtherKeys resource.
2024-08-21 04:17:09 +00:00
Thomas Adam
963e824f5f Merge branch 'obsd-master' 2024-08-19 12:01:09 +01:00
nicm
de6bce057a Allow REP to work with Unicode characters, GitHub issue 3687. 2024-08-19 08:31:36 +00:00
nicm
937ba1d8dd Both terminators \007 and \033\\ leave the index pointing to the final
character of the terminator, so correct the size calculation to always
add one. GitHub issue 4082.
2024-08-19 08:29:16 +00:00
Thomas Adam
651891c3bd Merge branch 'obsd-master' 2024-08-04 12:01:09 +01:00
nicm
4008e2ff6d Make a little effort to treate CRLF as LF in config files. GitHub issue
3720.
2024-08-04 09:42:23 +00:00
nicm
b88130d24b The Linux console has some bugs with bright colours. It seems likely
that it is emulating them by setting a bright (or bold) flag; however,
when the colour is changed from a bright colour (say SGR 96) to a
non-bright (say SGR 36), the flag is not reset, so the new colour
remains as bright. SGR 39 (default colour) also does not reset, so you
end up with the bright default colour. Work around this by sending SGR 0
when switching away from a bright colour, and disable AX for TERM=linux.
Also make the check for AX simpler and do not check for the op
capability is not actually used. GitHub issue 3976.
2024-08-04 09:35:30 +00:00
nicm
fc7ee7efc7 -l should be before -r, pointed out by jmc a while ago. 2024-08-04 09:01:18 +00:00
Nicholas Marriott
d0eb3fe543 Use terminal-features instead of terminal-overrides to enable truecolor support
in example_tmux.conf, from Simon Hengel.
2024-08-04 09:59:18 +01:00
Nicholas Marriott
2ac0faf119 If built with systemd, remove some environment variables it uses. From Ciprian
Dorin Craciun, GitHub issue 4035.
2024-08-04 09:58:13 +01:00
Nicholas Marriott
775789fbd5 Rename header guards on compat/queue.h to avoid it conflicting if the system
header is included first. This matters on some platforms (macOS) where queue.h
is old. From Saagar Jha in GitHub issue 4041.
2024-08-04 09:57:26 +01:00
nicm
7b6fbe7262 Adjust the logic when deleting last buffer to better preserve the
selection: if selecting the element below the deleted one fails (because
as the last one), select the one above it instead. From Daniel Mueller,
GitHub issue 4043.
2024-08-04 08:53:43 +00:00
Thomas Adam
109d2bda1a Merge branch 'obsd-master' 2024-07-22 18:01:09 +01:00
nicm
ddd4e57c65 Expand full array option values if no index is provided, GitHub issue
4051.
2024-07-22 15:27:42 +00:00
Nicholas Marriott
3c2621b41b Support building with jemalloc memory allocator, from Romain Francoise. 2024-07-15 11:25:15 +01:00
Nicholas Marriott
5039be657c utf8proc bits for utf8_fromwc. 2024-07-12 14:30:56 +01:00
Thomas Adam
d02254f754 Merge branch 'obsd-master' 2024-07-12 14:01:09 +01:00
nicm
aa1353947e UTF-8 keys now contain the internal representation and not the Unicode
codepoint, so convert extended keys properly. From Stanislav Kljuhhin.
2024-07-12 11:21:18 +00:00
Nicholas Marriott
171004dfd0 Use mdoc on Illumos which uses mandoc, from Andy Fiddaman. 2024-07-08 10:57:32 +01:00
Thomas Adam
c773fe89e7 Merge branch 'obsd-master' 2024-06-24 12:01:10 +01:00
nicm
093b5a5518 Add a way (refresh-client -r) for control mode clients to provide OSC 10
and 11 responses to tmux so they can set the default foreground and
background colours, from George Nachman in GitHub issue 4014.
2024-06-24 08:30:50 +00:00
nicm
db1665868f Check the underline style colour against the correct default value again
(it was changed from 0 to 8), from Romain Francoise.
2024-06-24 08:11:46 +00:00
Thomas Adam
c07e856d24 Merge branch 'obsd-master' 2024-05-24 16:01:08 +01:00
nicm
692ce59bce Do not escape $ unless DQ is set, that is the only case where we need to
escape it.
2024-05-24 12:41:24 +00:00
nicm
9e7c1aee48 Add N to search backwards in tree modes, from Fadi Afani in GitHub issue
3982.
2024-05-24 12:39:06 +00:00
Thomas Adam
4c2eedca5a Merge branch 'obsd-master' 2024-05-19 06:01:09 +01:00
jsg
ac6c1e9589 remove prototype with no matching function 2024-05-19 03:27:58 +00:00
Thomas Adam
0903790b00 Merge branch 'obsd-master' 2024-05-18 12:01:09 +01:00
jsg
03de52653e remove prototypes with no matching function; ok nicm@ 2024-05-18 08:51:26 +00:00
jsg
da06719309 remove externs with no matching var; ok nicm@ 2024-05-18 08:50:11 +00:00
Thomas Adam
fc84097379 Merge branch 'obsd-master' 2024-05-15 14:01:09 +01:00
Thomas Adam
4fd725c6e1 Merge branch 'obsd-master' 2024-05-15 12:01:10 +01:00
nicm
d39dcea30a Use default-shell for command prompt #() and popups as well 2024-05-15 09:59:12 +00:00
nicm
bfd65398a9 Fix memory leaks reported by Lu Ming Yin. 2024-05-15 08:39:30 +00:00
Thomas Adam
452d987e0e Merge branch 'obsd-master' 2024-05-14 14:01:10 +01:00
Thomas Adam
8ef899f315 Merge branch 'obsd-master' 2024-05-14 12:01:09 +01:00
nicm
a18d1146aa Add missing time.h to tty.c (from Ismail Donmez), also remove some stray
spaces.
2024-05-14 10:11:09 +00:00
nicm
5b5004e5ac Revert part of the change for GitHub issue 3675 because it does not work
correctly, it was intended to skip lines that are already being searched
as part of a previous wrapped line but in fact is skipping all lines
except the last in wrapped lines.

Also revert the search-wrapped-lines option (I didn't realize it was
intended to work around this).
2024-05-14 09:32:37 +00:00
Thomas Adam
6ff8f8fbf9 Merge branch 'obsd-master' 2024-05-14 10:01:10 +01:00
nicm
c9616700ca Add a command-error hook when a command fails, from Hugh Davenport in
GitHub issue 3973.
2024-05-14 07:52:19 +00:00
nicm
4c928dce74 Add an option to disable unwrapping lines for searching, from
meanderingprogrammer at gmail dot com, GitHub issue 3975.
2024-05-14 07:40:39 +00:00
nicm
fb37d52dde Restore previous behaviour or writing to stdout if available. 2024-05-14 07:33:01 +00:00
Thomas Adam
363d9c401e Merge branch 'obsd-master' 2024-05-13 14:01:10 +01:00
nicm
8643ece345 Fix memory leak, from Fadi Afani. 2024-05-13 11:45:05 +00:00
Nicholas Marriott
9ba433e521 Use printf not echo -e, from Joyce Lin. 2024-05-13 12:42:14 +01:00
Nicholas Marriott
3823fa2c57 Send SIGHUP since some programs ignore SIGTERM, from Eduardo Grajeda in GitHub
issue 3958.
2024-04-30 12:38:58 +01:00
Thomas Adam
0a8571b6fe Merge branch 'obsd-master' 2024-04-23 16:09:50 +01:00
jsg
ea9f416c99 correct indentation; no functional change
ok tb@
2024-04-23 13:34:51 +00:00
Thomas Adam
036d8993e6 Merge branch 'obsd-master' 2024-04-15 12:01:11 +01:00
nicm
e8530c9fee Fixes for memory leaks reported by Lu Ming Yin, fixes from Howard Chu. 2024-04-15 08:19:55 +00:00
Nicholas Marriott
dd4c0109a9 Missing headers for Android, from Biswapriyo Nath. 2024-04-15 09:07:41 +01:00
Thomas Adam
43530d4397 Merge branch 'obsd-master' 2024-04-10 10:01:13 +01:00
nicm
553d4cba79 Add an option allow-set-title to forbid applications from changing the
pane title, from someone in GitHub issue 3930.
2024-04-10 07:36:25 +00:00
nicm
c62a9ca16b Correct handling of mouse up events (don't ignore all but the last
released button), and always process down event for double click. From
Rudy Dellomas III in GitHub issue 3919.
2024-04-10 07:29:15 +00:00
nicm
424f13fe13 Do not get muddled and crash if focusing a pane that is exiting,
reported by Saul Nogueras in GitHub issue 3776.
2024-04-10 07:15:21 +00:00
Thomas Adam
4bb6da75ba Merge branch 'obsd-master' 2024-04-05 02:01:09 +01:00
nicm
a28175dbfd Pick newest session as documented, not oldest, from Magnus Gross. 2024-04-04 22:44:40 +00:00
Thomas Adam
fc204bb5e5 Merge branch 'obsd-master' 2024-03-26 12:01:11 +00:00
nicm
6207a45139 Fix selection present check, reported by M Kelly. 2024-03-26 10:20:20 +00:00
Thomas Adam
3c3643f580 Merge branch 'obsd-master' 2024-03-21 14:01:10 +00:00
nicm
89c1c43ef9 Write padding character into the right position. 2024-03-21 12:10:57 +00:00
nicm
2e9d7ebf15 Reduce escape-time default to 10 milliseconds, 500 is far too long for
modern terminals and networks. Case made by Kurtis Rader in GitHub issue
3844.
2024-03-21 11:53:11 +00:00
nicm
d8ddeec7db Add -M to always turn mouse on in a menu, GitHub issue 3779. 2024-03-21 11:51:32 +00:00
nicm
6f0254e6a8 Look for feature code 21 for DECSLRM and 28 for DECFRA in the device
attributes and also accept level 1 (there is no hardware with this but
some emulators may use it). Pointed out by James Holderness.
2024-03-21 11:47:55 +00:00
Nicholas Marriott
aa17f0e0c1 Fix crash if SIXEL colour register is invalid and remove SIXEL images before
reflow to avoid a different crash, from Anindya Mukherjee.
2024-03-21 11:37:09 +00:00
nicm
0ae8b681b2 Use -p for default paste-buffer command in buffer mode, it will only do
anything if the application asked for it. From Gregory Anders.
2024-03-21 11:32:49 +00:00
nicm
6c0067c103 Do not notify window-layout-changed if the window is about to be
destroyed (since it may have been freed by the time the notify happens),
from Romain Francoise in GitHub issue 3860.
2024-03-21 11:30:42 +00:00
nicm
5458cb2850 Revert detach-client part of last, did not intend this to go in. 2024-03-21 11:27:18 +00:00
nicm
0c374868ca Do not consider a selection present if it is empty, from Michael Grant
(GitHub issue 3869). Also a typo fix from GitHub issue 3877.
2024-03-21 11:26:28 +00:00
Nicholas Marriott
bf5d3f2e26 Typo, GitHub issue 3877. 2024-03-21 11:19:59 +00:00
Nicholas Marriott
d5ef837f63 Remove duplicate .tmux.conf mention, from Valentin Rylenko. 2024-03-21 11:18:49 +00:00
Thomas Adam
b79e28b2c3 Merge branch 'obsd-master' 2024-03-13 14:01:09 +00:00
nicm
8ffd5458ff Make the attach-session description clearer - do not mention creating a
client which is not important, explicitly say the session must exist,
and mention new-session and new-session -A. Prompted by Theo.
2024-03-13 11:25:50 +00:00
Thomas Adam
b54e1fc4f7 Merge branch 'obsd-master' 2024-03-07 00:01:10 +00:00
Nicholas Marriott
bdb6321229 Update lock.yml. 2024-03-06 21:45:26 +00:00
nicm
bd29a48b56 Check for the right flag to fix split-window -p, from Bryan Childs. 2024-03-06 21:32:39 +00:00
Nicholas Marriott
f3f1c3db58 Add missing headers, from Marvin Schmidt. 2024-03-06 21:29:28 +00:00
Nicholas Marriott
608d113486 next-3.5 2024-02-13 10:20:18 +00:00
65 changed files with 2013 additions and 641 deletions

View File

@@ -3,27 +3,32 @@ name: 'Lock Threads'
on: on:
schedule: schedule:
- cron: '0 0 * * *' - cron: '0 0 * * *'
workflow_dispatch:
permissions: permissions:
contents: read issues: write
pull-requests: write
discussions: write
concurrency:
group: lock-threads
jobs: jobs:
lock: action:
permissions:
issues: write # for dessant/lock-threads to lock issues
pull-requests: write # for dessant/lock-threads to lock PRs
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: dessant/lock-threads@v2 - uses: dessant/lock-threads@v5
with: with:
github-token: ${{ github.token }} github-token: ${{ github.token }}
issue-lock-inactive-days: '30' issue-inactive-days: '30'
pr-lock-inactive-days: '60' issue-comment: >
issue-lock-comment: >
This issue has been automatically locked since there This issue has been automatically locked since there
has not been any recent activity after it was closed. has not been any recent activity after it was closed.
Please open a new issue for related bugs. pr-inactive-days: '60'
pr-lock-comment: > pr-comment: >
This pull request has been automatically locked since there This pull request has been automatically locked since there
has not been any recent activity after it was closed. has not been any recent activity after it was closed.
Please open a new issue for related bugs. discussion-inactive-days: '60'
discussion-comment: >
This discussion has been automatically locked since there
has not been any recent activity after it was closed.

93
CHANGES
View File

@@ -1,4 +1,93 @@
CHANGES FROM 3.3a to 3.4 CHANGES FROM 3.4 TO 3.5
* Revamp extended keys support to more closely match xterm and support mode 2
as well as mode 1. This is a substantial change to key handling which changes
tmux to always request mode 2 from parent terminal, changes to an unambiguous
internal representation of keys, and adds an option (extended-keys-format) to
control the format similar to the xterm(1) formatOtherKeys resource.
* Clear an overlay (popup or menu) when command prompt is entered.
* Add copy-mode -d flag to scroll a page down if in copy mode already (matching
-e).
* Display hyperlinks in copy mode and add copy_cursor_hyperlink format to get
the hyperlink under the cursor.
* Add a prefix timeout option.
* Mouse move keys are not useful as key bindings because we do not turn them on
unless the application requests them. Ignore them so they do not cause the
prefix to be canceled
* Add search_count and search_count_partial formats in copy mode.
* Do not reset mouse pane if clicked on status line,
* Add mirrored versions of the main-horizontal and main-vertical layouts where
the main pane is bottom or right instead of top or left.
* Allow REP to work with Unicode characters.
* Fix size calculation of terminators for clipboard escape sequences.
* Treat CRLF as LF in config files where it is easy to do so.
* The Linux console has some bugs with bright colours, so add some workarounds
for it.
* If built with systemd, remove some environment variables it uses.
* Adjust the logic when deleting last buffer to better preserve the selection:
if selecting the element below the deleted one fails (because as the last
one), select the one above it instead.
* Add --enable-jemalloc to build with jemalloc memory allocator (since glibc
malloc is so poor).
* Add a way (refresh-client -r) for control mode clients to provide OSC 10 and
11 responses to tmux so they can set the default foreground and background
colours.
* Add N to search backwards in tree modes.
* Use default-shell for command prompt, #() and popups.
* Revert part of a change intended to improve search performance by skipping
parts of lines already searched, but which in fact skipped the ends of lines
altogether.
* Add a command-error hook when a command fails.
* Add an option allow-set-title to forbid applications from changing the pane
title.
* Correct handling of mouse up events (don't ignore all but the last released
button), and always process down event for double click.
* Fix a crash if focusing a pane that is exiting.
* Pick newest session (as documented) when looking for next session for
detach-on-destroy.
* Reduce default escape-time to 10 milliseconds.
* Add display-menu -M to always turn mouse on in a menu.
* Look for feature code 21 for DECSLRM and 28 for DECFRA in the device
attributes and also accept level 1.
* Fix crash if built with SIXEL and the SIXEL colour register is invalid; also
remove SIXEL images before reflow.
* Do not notify window-layout-changed if the window is about to be destroyed.
* Do not consider a selection present if it is empty for the selection_active
and selection_present format variables.
* Fix split-window -p.
CHANGES FROM 3.3a TO 3.4
* Add options keep-last and keep-group to destroy-unattached to keep the last * Add options keep-last and keep-group to destroy-unattached to keep the last
session whether in a group. session whether in a group.
@@ -84,7 +173,7 @@ CHANGES FROM 3.3a to 3.4
* Add message-line option to control where message and prompt go. * Add message-line option to control where message and prompt go.
* Notification when a when a paste buffer is deleted. * Notification when a paste buffer is deleted.
* Add a Nobr terminfo(5) capability to tell tmux the terminal does not use bright * Add a Nobr terminfo(5) capability to tell tmux the terminal does not use bright
colours for bold. colours for bold.

View File

@@ -164,10 +164,14 @@ args_parse_flag_argument(struct args_value *values, u_int count, char **cause,
argument = &values[*i]; argument = &values[*i];
if (argument->type != ARGS_STRING) { if (argument->type != ARGS_STRING) {
xasprintf(cause, "-%c argument must be a string", flag); xasprintf(cause, "-%c argument must be a string", flag);
args_free_value(new);
free(new);
return (-1); return (-1);
} }
} }
if (argument == NULL) { if (argument == NULL) {
args_free_value(new);
free(new);
if (optional_argument) { if (optional_argument) {
log_debug("%s: -%c (optional)", __func__, flag); log_debug("%s: -%c (optional)", __func__, flag);
args_set(args, flag, NULL, ARGS_ENTRY_OPTIONAL_VALUE); args_set(args, flag, NULL, ARGS_ENTRY_OPTIONAL_VALUE);
@@ -662,6 +666,8 @@ args_set(struct args *args, u_char flag, struct args_value *value, int flags)
entry->count++; entry->count++;
if (value != NULL && value->type != ARGS_NONE) if (value != NULL && value->type != ARGS_NONE)
TAILQ_INSERT_TAIL(&entry->values, value, entry); TAILQ_INSERT_TAIL(&entry->values, value, entry);
else
free(value);
} }
/* Get argument value. Will be NULL if it isn't present. */ /* Get argument value. Will be NULL if it isn't present. */

View File

@@ -452,11 +452,12 @@ client_send_identify(const char *ttynam, const char *termname, char **caps,
{ {
char **ss; char **ss;
size_t sslen; size_t sslen;
int fd, flags = client_flags; int fd;
uint64_t flags = client_flags;
pid_t pid; pid_t pid;
u_int i; u_int i;
proc_send(client_peer, MSG_IDENTIFY_FLAGS, -1, &flags, sizeof flags); proc_send(client_peer, MSG_IDENTIFY_LONGFLAGS, -1, &flags, sizeof flags);
proc_send(client_peer, MSG_IDENTIFY_LONGFLAGS, -1, &client_flags, proc_send(client_peer, MSG_IDENTIFY_LONGFLAGS, -1, &client_flags,
sizeof client_flags); sizeof client_flags);
@@ -497,20 +498,10 @@ client_send_identify(const char *ttynam, const char *termname, char **caps,
static __dead void static __dead void
client_exec(const char *shell, const char *shellcmd) client_exec(const char *shell, const char *shellcmd)
{ {
const char *name, *ptr; char *argv0;
char *argv0;
log_debug("shell %s, command %s", shell, shellcmd); log_debug("shell %s, command %s", shell, shellcmd);
argv0 = shell_argv0(shell, !!(client_flags & CLIENT_LOGIN));
ptr = strrchr(shell, '/');
if (ptr != NULL && *(ptr + 1) != '\0')
name = ptr + 1;
else
name = shell;
if (client_flags & CLIENT_LOGIN)
xasprintf(&argv0, "-%s", name);
else
xasprintf(&argv0, "%s", name);
setenv("SHELL", shell, 1); setenv("SHELL", shell, 1);
proc_clear_signals(client_proc, 1); proc_clear_signals(client_proc, 1);

View File

@@ -143,6 +143,7 @@ cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
cdata->prompt_type = status_prompt_type(type); cdata->prompt_type = status_prompt_type(type);
if (cdata->prompt_type == PROMPT_TYPE_INVALID) { if (cdata->prompt_type == PROMPT_TYPE_INVALID) {
cmdq_error(item, "unknown type: %s", type); cmdq_error(item, "unknown type: %s", type);
cmd_command_prompt_free(cdata);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} else } else

View File

@@ -76,8 +76,10 @@ cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item)
cdata = xcalloc(1, sizeof *cdata); cdata = xcalloc(1, sizeof *cdata);
cdata->cmdlist = args_make_commands_now(self, item, 0, 1); cdata->cmdlist = args_make_commands_now(self, item, 0, 1);
if (cdata->cmdlist == NULL) if (cdata->cmdlist == NULL) {
free(cdata);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
}
if (wait) if (wait)
cdata->item = item; cdata->item = item;
@@ -90,6 +92,7 @@ cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item)
cdata->confirm_key = confirm_key[0]; cdata->confirm_key = confirm_key[0];
else { else {
cmdq_error(item, "invalid confirm key"); cmdq_error(item, "invalid confirm key");
free(cdata);
return (CMD_RETURN_ERROR); return (CMD_RETURN_ERROR);
} }
} }
@@ -100,8 +103,8 @@ cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item)
xasprintf(&new_prompt, "%s ", prompt); xasprintf(&new_prompt, "%s ", prompt);
else { else {
cmd = cmd_get_entry(cmd_list_first(cdata->cmdlist))->name; cmd = cmd_get_entry(cmd_list_first(cdata->cmdlist))->name;
xasprintf(&new_prompt, "Confirm '%s'? (%c/n) ", xasprintf(&new_prompt, "Confirm '%s'? (%c/n) ", cmd,
cmd, cdata->confirm_key); cdata->confirm_key);
} }
status_prompt_set(tc, target, new_prompt, NULL, status_prompt_set(tc, target, new_prompt, NULL,

View File

@@ -30,8 +30,8 @@ const struct cmd_entry cmd_copy_mode_entry = {
.name = "copy-mode", .name = "copy-mode",
.alias = NULL, .alias = NULL,
.args = { "eHMs:t:uq", 0, 0, NULL }, .args = { "deHMs:t:uq", 0, 0, NULL },
.usage = "[-eHMuq] [-s src-pane] " CMD_TARGET_PANE_USAGE, .usage = "[-deHMuq] [-s src-pane] " CMD_TARGET_PANE_USAGE,
.source = { 's', CMD_FIND_PANE, 0 }, .source = { 's', CMD_FIND_PANE, 0 },
.target = { 't', CMD_FIND_PANE, 0 }, .target = { 't', CMD_FIND_PANE, 0 },
@@ -91,6 +91,8 @@ cmd_copy_mode_exec(struct cmd *self, struct cmdq_item *item)
} }
if (args_has(args, 'u')) if (args_has(args, 'u'))
window_copy_pageup(wp, 0); window_copy_pageup(wp, 0);
if (args_has(args, 'd'))
window_copy_pagedown(wp, 0, args_has(args, 'e'));
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }

View File

@@ -38,8 +38,8 @@ const struct cmd_entry cmd_display_menu_entry = {
.name = "display-menu", .name = "display-menu",
.alias = "menu", .alias = "menu",
.args = { "b:c:C:H:s:S:Ot:T:x:y:", 1, -1, cmd_display_menu_args_parse }, .args = { "b:c:C:H:s:S:MOt:T:x:y:", 1, -1, cmd_display_menu_args_parse },
.usage = "[-O] [-b border-lines] [-c target-client] " .usage = "[-MO] [-b border-lines] [-c target-client] "
"[-C starting-choice] [-H selected-style] [-s style] " "[-C starting-choice] [-H selected-style] [-s style] "
"[-S border-style] " CMD_TARGET_PANE_USAGE "[-T title] " "[-S border-style] " CMD_TARGET_PANE_USAGE "[-T title] "
"[-x position] [-y position] name key command ...", "[-x position] [-y position] name key command ...",
@@ -373,7 +373,7 @@ cmd_display_menu_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(args, 'O')) if (args_has(args, 'O'))
flags |= MENU_STAYOPEN; flags |= MENU_STAYOPEN;
if (!event->m.valid) if (!event->m.valid && !args_has(args, 'M'))
flags |= MENU_NOMOUSE; flags |= MENU_NOMOUSE;
if (menu_display(menu, flags, starting_choice, item, px, py, tc, lines, if (menu_display(menu, flags, starting_choice, item, px, py, tc, lines,
style, selected_style, border_style, target, NULL, NULL) != 0) style, selected_style, border_style, target, NULL, NULL) != 0)

View File

@@ -246,7 +246,7 @@ cmd_display_panes_key(struct client *c, void *data, struct key_event *event)
wp = window_pane_at_index(w, index); wp = window_pane_at_index(w, index);
if (wp == NULL) if (wp == NULL)
return (1); return (1);
window_unzoom(w); window_unzoom(w, 1);
xasprintf(&expanded, "%%%u", wp->id); xasprintf(&expanded, "%%%u", wp->id);

View File

@@ -1273,6 +1273,16 @@ yylex(void)
continue; continue;
} }
if (ch == '\r') {
/*
* Treat \r\n as \n.
*/
ch = yylex_getc();
if (ch != '\n') {
yylex_ungetc(ch);
ch = '\r';
}
}
if (ch == '\n') { if (ch == '\n') {
/* /*
* End of line. Update the line number. * End of line. Update the line number.
@@ -1619,6 +1629,13 @@ yylex_token(int ch)
log_debug("%s: end at EOF", __func__); log_debug("%s: end at EOF", __func__);
break; break;
} }
if (state == NONE && ch == '\r') {
ch = yylex_getc();
if (ch != '\n') {
yylex_ungetc(ch);
ch = '\r';
}
}
if (state == NONE && ch == '\n') { if (state == NONE && ch == '\n') {
log_debug("%s: end at EOL", __func__); log_debug("%s: end at EOL", __func__);
break; break;

View File

@@ -664,9 +664,18 @@ cmdq_fire_command(struct cmdq_item *item)
out: out:
item->client = saved; item->client = saved;
if (retval == CMD_RETURN_ERROR) if (retval == CMD_RETURN_ERROR) {
fsp = NULL;
if (cmd_find_valid_state(&item->target))
fsp = &item->target;
else if (cmd_find_valid_state(&item->state->current))
fsp = &item->state->current;
else if (cmd_find_from_client(&fs, item->client, 0) == 0)
fsp = &fs;
cmdq_insert_hook(fsp != NULL ? fsp->s : NULL, item, fsp,
"command-error");
cmdq_guard(item, "error", flags); cmdq_guard(item, "error", flags);
else } else
cmdq_guard(item, "end", flags); cmdq_guard(item, "end", flags);
return (retval); return (retval);
} }
@@ -805,10 +814,10 @@ cmdq_running(struct client *c)
struct cmdq_list *queue = cmdq_get(c); struct cmdq_list *queue = cmdq_get(c);
if (queue->item == NULL) if (queue->item == NULL)
return (NULL); return (NULL);
if (queue->item->flags & CMDQ_WAITING) if (queue->item->flags & CMDQ_WAITING)
return (NULL); return (NULL);
return (queue->item); return (queue->item);
} }
/* Print a guard line. */ /* Print a guard line. */

View File

@@ -34,9 +34,10 @@ const struct cmd_entry cmd_refresh_client_entry = {
.name = "refresh-client", .name = "refresh-client",
.alias = "refresh", .alias = "refresh",
.args = { "A:B:cC:Df:F:l::LRSt:U", 0, 1, NULL }, .args = { "A:B:cC:Df:r:F:l::LRSt:U", 0, 1, NULL },
.usage = "[-cDlLRSU] [-A pane:state] [-B name:what:format] " .usage = "[-cDlLRSU] [-A pane:state] [-B name:what:format] "
"[-C XxY] [-f flags] " CMD_TARGET_CLIENT_USAGE " [adjustment]", "[-C XxY] [-f flags] [-r pane:report]" CMD_TARGET_CLIENT_USAGE
" [adjustment]",
.flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG, .flags = CMD_AFTERHOOK|CMD_CLIENT_TFLAG,
.exec = cmd_refresh_client_exec .exec = cmd_refresh_client_exec
@@ -193,6 +194,34 @@ cmd_refresh_client_clipboard(struct cmd *self, struct cmdq_item *item)
return (CMD_RETURN_NORMAL); return (CMD_RETURN_NORMAL);
} }
static void
cmd_refresh_report(struct tty *tty, const char *value)
{
struct window_pane *wp;
u_int pane;
size_t size = 0;
char *copy, *split;
if (*value != '%')
return;
copy = xstrdup(value);
if ((split = strchr(copy, ':')) == NULL)
goto out;
*split++ = '\0';
if (sscanf(copy, "%%%u", &pane) != 1)
goto out;
wp = window_pane_find_by_id(pane);
if (wp == NULL)
goto out;
tty_keys_colours(tty, split, strlen(split), &size, &wp->control_fg,
&wp->control_bg);
out:
free(copy);
}
static enum cmd_retval static enum cmd_retval
cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item) cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
{ {
@@ -262,6 +291,8 @@ cmd_refresh_client_exec(struct cmd *self, struct cmdq_item *item)
server_client_set_flags(tc, args_get(args, 'F')); server_client_set_flags(tc, args_get(args, 'F'));
if (args_has(args, 'f')) if (args_has(args, 'f'))
server_client_set_flags(tc, args_get(args, 'f')); server_client_set_flags(tc, args_get(args, 'f'));
if (args_has(args, 'r'))
cmd_refresh_report(tty, args_get(args, 'r'));
if (args_has(args, 'A')) { if (args_has(args, 'A')) {
if (~tc->flags & CLIENT_CONTROL) if (~tc->flags & CLIENT_CONTROL)

View File

@@ -87,7 +87,7 @@ cmd_resize_pane_exec(struct cmd *self, struct cmdq_item *item)
if (args_has(args, 'Z')) { if (args_has(args, 'Z')) {
if (w->flags & WINDOW_ZOOMED) if (w->flags & WINDOW_ZOOMED)
window_unzoom(w); window_unzoom(w, 1);
else else
window_zoom(wp); window_zoom(wp);
server_redraw_window(w); server_redraw_window(w);

View File

@@ -85,12 +85,18 @@ cmd_run_shell_print(struct job *job, const char *msg)
if (cdata->wp_id != -1) if (cdata->wp_id != -1)
wp = window_pane_find_by_id(cdata->wp_id); wp = window_pane_find_by_id(cdata->wp_id);
if (wp == NULL && cdata->item != NULL && cdata->client != NULL) if (wp == NULL) {
wp = server_client_get_pane(cdata->client); if (cdata->item != NULL) {
if (wp == NULL && cmd_find_from_nothing(&fs, 0) == 0) cmdq_print(cdata->item, "%s", msg);
wp = fs.wp; return;
if (wp == NULL) }
return; if (cdata->item != NULL && cdata->client != NULL)
wp = server_client_get_pane(cdata->client);
if (wp == NULL && cmd_find_from_nothing(&fs, 0) == 0)
wp = fs.wp;
if (wp == NULL)
return;
}
wme = TAILQ_FIRST(&wp->modes); wme = TAILQ_FIRST(&wp->modes);
if (wme == NULL || wme->mode != &window_view_mode) if (wme == NULL || wme->mode != &window_view_mode)

View File

@@ -93,10 +93,10 @@ cmd_split_window_exec(struct cmd *self, struct cmdq_item *item)
size = -1; size = -1;
if (args_has(args, 'l')) { if (args_has(args, 'l')) {
size = args_percentage_and_expand(args, 'l', 0, INT_MAX, curval, size = args_percentage_and_expand(args, 'l', 0, INT_MAX, curval,
item, &cause); item, &cause);
} else if (args_has(args, 'p')) { } else if (args_has(args, 'p')) {
size = args_strtonum_and_expand(args, 'l', 0, 100, item, size = args_strtonum_and_expand(args, 'p', 0, 100, item,
&cause); &cause);
if (cause == NULL) if (cause == NULL)
size = curval * size / 100; size = curval * size / 100;
} }

2
cmd.c
View File

@@ -47,7 +47,6 @@ extern const struct cmd_entry cmd_display_menu_entry;
extern const struct cmd_entry cmd_display_message_entry; extern const struct cmd_entry cmd_display_message_entry;
extern const struct cmd_entry cmd_display_popup_entry; extern const struct cmd_entry cmd_display_popup_entry;
extern const struct cmd_entry cmd_display_panes_entry; extern const struct cmd_entry cmd_display_panes_entry;
extern const struct cmd_entry cmd_down_pane_entry;
extern const struct cmd_entry cmd_find_window_entry; extern const struct cmd_entry cmd_find_window_entry;
extern const struct cmd_entry cmd_has_session_entry; extern const struct cmd_entry cmd_has_session_entry;
extern const struct cmd_entry cmd_if_shell_entry; extern const struct cmd_entry cmd_if_shell_entry;
@@ -117,7 +116,6 @@ extern const struct cmd_entry cmd_swap_window_entry;
extern const struct cmd_entry cmd_switch_client_entry; extern const struct cmd_entry cmd_switch_client_entry;
extern const struct cmd_entry cmd_unbind_key_entry; extern const struct cmd_entry cmd_unbind_key_entry;
extern const struct cmd_entry cmd_unlink_window_entry; extern const struct cmd_entry cmd_unlink_window_entry;
extern const struct cmd_entry cmd_up_pane_entry;
extern const struct cmd_entry cmd_wait_for_entry; extern const struct cmd_entry cmd_wait_for_entry;
const struct cmd_entry *cmd_table[] = { const struct cmd_entry *cmd_table[] = {

View File

@@ -942,13 +942,17 @@ colour_byname(const char *name)
{ "yellow3", 0xcdcd00 }, { "yellow3", 0xcdcd00 },
{ "yellow4", 0x8b8b00 } { "yellow4", 0x8b8b00 }
}; };
u_int i; u_int i;
int c; int c;
const char *errstr;
if (strncmp(name, "grey", 4) == 0 || strncmp(name, "gray", 4) == 0) { if (strncmp(name, "grey", 4) == 0 || strncmp(name, "gray", 4) == 0) {
if (!isdigit((u_char)name[4])) if (name[4] == '\0')
return (0xbebebe|COLOUR_FLAG_RGB); return (-1);
c = round(2.55 * atoi(name + 4)); c = strtonum(name + 4, 0, 100, &errstr);
if (errstr != NULL)
return (-1);
c = round(2.55 * c);
if (c < 0 || c > 255) if (c < 0 || c > 255)
return (-1); return (-1);
return (colour_join_rgb(c, c, c)); return (colour_join_rgb(c, c, c));

View File

@@ -289,6 +289,11 @@ void explicit_bzero(void *, size_t);
int getdtablecount(void); int getdtablecount(void);
#endif #endif
#ifndef HAVE_GETDTABLESIZE
/* getdtablesize.c */
int getdtablesize(void);
#endif
#ifndef HAVE_CLOSEFROM #ifndef HAVE_CLOSEFROM
/* closefrom.c */ /* closefrom.c */
void closefrom(int); void closefrom(int);

View File

@@ -14,6 +14,7 @@
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
#include <arpa/inet.h>
#include <sys/types.h> #include <sys/types.h>
#include "compat.h" #include "compat.h"

View File

@@ -14,6 +14,7 @@
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/ */
#include <arpa/inet.h>
#include <sys/types.h> #include <sys/types.h>
#include "compat.h" #include "compat.h"

View File

@@ -32,8 +32,8 @@
* @(#)queue.h 8.5 (Berkeley) 8/20/94 * @(#)queue.h 8.5 (Berkeley) 8/20/94
*/ */
#ifndef _SYS_QUEUE_H_ #ifndef _COMPAT_QUEUE_H_
#define _SYS_QUEUE_H_ #define _COMPAT_QUEUE_H_
/* /*
* This file defines five types of data structures: singly-linked lists, * This file defines five types of data structures: singly-linked lists,
@@ -530,4 +530,4 @@ struct { \
} \ } \
} while (0) } while (0)
#endif /* !_SYS_QUEUE_H_ */ #endif /* !_COMPAT_QUEUE_H_ */

View File

@@ -17,6 +17,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include "compat.h" #include "compat.h"

View File

@@ -24,7 +24,9 @@
#include <systemd/sd-login.h> #include <systemd/sd-login.h>
#include <systemd/sd-id128.h> #include <systemd/sd-id128.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <unistd.h>
#include "tmux.h" #include "tmux.h"
@@ -142,6 +144,17 @@ systemd_move_pid_to_new_cgroup(pid_t pid, char **cause)
goto finish; goto finish;
} }
/*
* Make sure that the session shells are terminated with SIGHUP since
* bash and friends tend to ignore SIGTERM.
*/
r = sd_bus_message_append(m, "(sv)", "SendSIGHUP", "b", 1);
if (r < 0) {
xasprintf(cause, "failed to append to properties: %s",
strerror(-r));
goto finish;
}
/* /*
* Inherit the slice from the parent process, or default to * Inherit the slice from the parent process, or default to
* "app-tmux.slice" if that fails. * "app-tmux.slice" if that fails.

View File

@@ -1,6 +1,6 @@
# configure.ac # configure.ac
AC_INIT([tmux], 3.4) AC_INIT([tmux], 3.5)
AC_PREREQ([2.60]) AC_PREREQ([2.60])
AC_CONFIG_AUX_DIR(etc) AC_CONFIG_AUX_DIR(etc)
@@ -56,10 +56,11 @@ AC_USE_SYSTEM_EXTENSIONS
test "$sysconfdir" = '${prefix}/etc' && sysconfdir=/etc test "$sysconfdir" = '${prefix}/etc' && sysconfdir=/etc
# Is this --enable-debug? # Is this --enable-debug?
case "x$VERSION" in xnext*) enable_debug=yes;; esac
AC_ARG_ENABLE( AC_ARG_ENABLE(
debug, debug,
AS_HELP_STRING(--enable-debug, enable debug build flags), AS_HELP_STRING(--enable-debug, enable debug build flags),
,
[case "x$VERSION" in xnext*) enable_debug=yes;; esac]
) )
AM_CONDITIONAL(IS_DEBUG, test "x$enable_debug" = xyes) AM_CONDITIONAL(IS_DEBUG, test "x$enable_debug" = xyes)
@@ -548,6 +549,24 @@ if test "x$found_malloc_trim" = xyes; then
AC_DEFINE(HAVE_MALLOC_TRIM) AC_DEFINE(HAVE_MALLOC_TRIM)
fi fi
# Build against jemalloc if requested.
AC_ARG_ENABLE(
jemalloc,
AS_HELP_STRING(--enable-jemalloc, use jemalloc if it is installed)
)
if test "x$enable_jemalloc" = xyes; then
PKG_CHECK_MODULES(
JEMALLOC,
jemalloc,
[
AM_CPPFLAGS="$JEMALLOC_CFLAGS $AM_CPPFLAGS"
CPPFLAGS="$AM_CPPFLAGS $SAVED_CPPFLAGS"
LIBS="$LIBS $JEMALLOC_LIBS"
],
AC_MSG_ERROR("jemalloc not found")
)
fi
# Check for CMSG_DATA. On some platforms like HP-UX this requires UNIX 95 # Check for CMSG_DATA. On some platforms like HP-UX this requires UNIX 95
# (_XOPEN_SOURCE and _XOPEN_SOURCE_EXTENDED) (see xopen_networking(7)). On # (_XOPEN_SOURCE and _XOPEN_SOURCE_EXTENDED) (see xopen_networking(7)). On
# others, UNIX 03 (_XOPEN_SOURCE 600, see standards(7) on Solaris). # others, UNIX 03 (_XOPEN_SOURCE 600, see standards(7) on Solaris).
@@ -926,8 +945,13 @@ case "$host_os" in
MANFORMAT=mdoc MANFORMAT=mdoc
;; ;;
*) *)
# Solaris 2.0 to 11.3 use AT&T nroff. if test `uname -o 2>/dev/null` = illumos; then
MANFORMAT=man # Illumos uses mandoc.
MANFORMAT=mdoc
else
# Solaris 2.0 to 11.3 use AT&T nroff.
MANFORMAT=man
fi
;; ;;
esac esac
;; ;;

View File

@@ -264,6 +264,12 @@ environ_for_session(struct session *s, int no_TERM)
environ_set(env, "TERM_PROGRAM_VERSION", 0, "%s", getversion()); environ_set(env, "TERM_PROGRAM_VERSION", 0, "%s", getversion());
} }
#ifdef HAVE_SYSTEMD
environ_clear(env, "LISTEN_PID");
environ_clear(env, "LISTEN_FDS");
environ_clear(env, "LISTEN_FDNAMES");
#endif
if (s != NULL) if (s != NULL)
idx = s->id; idx = s->id;
else else

View File

@@ -14,7 +14,7 @@ set -g status-bg red
%endif %endif
# Enable RGB colour if running in xterm(1) # Enable RGB colour if running in xterm(1)
set-option -sa terminal-overrides ",xterm*:Tc" set-option -sa terminal-features ",xterm*:RGB"
# Change the default $TERM to tmux-256color # Change the default $TERM to tmux-256color
set -g default-terminal "tmux-256color" set -g default-terminal "tmux-256color"

View File

@@ -1136,8 +1136,7 @@ format_cb_mouse_word(struct format_tree *ft)
return (NULL); return (NULL);
if (!TAILQ_EMPTY(&wp->modes)) { if (!TAILQ_EMPTY(&wp->modes)) {
if (TAILQ_FIRST(&wp->modes)->mode == &window_copy_mode || if (window_pane_mode(wp) != WINDOW_PANE_NO_MODE)
TAILQ_FIRST(&wp->modes)->mode == &window_view_mode)
return (window_copy_get_word(wp, x, y)); return (window_copy_get_word(wp, x, y));
return (NULL); return (NULL);
} }
@@ -1181,8 +1180,7 @@ format_cb_mouse_line(struct format_tree *ft)
return (NULL); return (NULL);
if (!TAILQ_EMPTY(&wp->modes)) { if (!TAILQ_EMPTY(&wp->modes)) {
if (TAILQ_FIRST(&wp->modes)->mode == &window_copy_mode || if (window_pane_mode(wp) != WINDOW_PANE_NO_MODE)
TAILQ_FIRST(&wp->modes)->mode == &window_view_mode)
return (window_copy_get_line(wp, y)); return (window_copy_get_line(wp, y));
return (NULL); return (NULL);
} }
@@ -1962,6 +1960,23 @@ format_cb_pane_unseen_changes(struct format_tree *ft)
return (NULL); return (NULL);
} }
/* Callback for pane_key_mode. */
static void *
format_cb_pane_key_mode(struct format_tree *ft)
{
if (ft->wp != NULL && ft->wp->screen != NULL) {
switch (ft->wp->screen->mode & EXTENDED_KEY_MODES) {
case MODE_KEYS_EXTENDED:
return (xstrdup("Ext 1"));
case MODE_KEYS_EXTENDED_2:
return (xstrdup("Ext 2"));
default:
return (xstrdup("VT10x"));
}
}
return (NULL);
}
/* Callback for pane_last. */ /* Callback for pane_last. */
static void * static void *
format_cb_pane_last(struct format_tree *ft) format_cb_pane_last(struct format_tree *ft)
@@ -2997,6 +3012,9 @@ static const struct format_table_entry format_table[] = {
{ "pane_input_off", FORMAT_TABLE_STRING, { "pane_input_off", FORMAT_TABLE_STRING,
format_cb_pane_input_off format_cb_pane_input_off
}, },
{ "pane_key_mode", FORMAT_TABLE_STRING,
format_cb_pane_key_mode
},
{ "pane_last", FORMAT_TABLE_STRING, { "pane_last", FORMAT_TABLE_STRING,
format_cb_pane_last format_cb_pane_last
}, },

View File

@@ -35,7 +35,7 @@ LLVMFuzzerTestOneInput(const u_char *data, size_t size)
int error; int error;
/* /*
* Since AFL doesn't support -max_len paramenter we have to * Since AFL doesn't support -max_len parameter we have to
* discard long inputs manually. * discard long inputs manually.
*/ */
if (size > FUZZER_MAXLEN) if (size > FUZZER_MAXLEN)

2
grid.c
View File

@@ -88,7 +88,7 @@ grid_need_extended_cell(const struct grid_cell_entry *gce,
return (1); return (1);
if ((gc->fg & COLOUR_FLAG_RGB) || (gc->bg & COLOUR_FLAG_RGB)) if ((gc->fg & COLOUR_FLAG_RGB) || (gc->bg & COLOUR_FLAG_RGB))
return (1); return (1);
if (gc->us != 0) /* only supports 256 or RGB */ if (gc->us != 8) /* only supports 256 or RGB */
return (1); return (1);
if (gc->link != 0) if (gc->link != 0)
return (1); return (1);

View File

@@ -68,6 +68,7 @@ struct hyperlinks {
u_int next_inner; u_int next_inner;
struct hyperlinks_by_inner_tree by_inner; struct hyperlinks_by_inner_tree by_inner;
struct hyperlinks_by_uri_tree by_uri; struct hyperlinks_by_uri_tree by_uri;
u_int references;
}; };
static int static int
@@ -205,6 +206,15 @@ hyperlinks_init(void)
hl->next_inner = 1; hl->next_inner = 1;
RB_INIT(&hl->by_uri); RB_INIT(&hl->by_uri);
RB_INIT(&hl->by_inner); RB_INIT(&hl->by_inner);
hl->references = 1;
return (hl);
}
/* Copy hyperlink set. */
struct hyperlinks *
hyperlinks_copy(struct hyperlinks *hl)
{
hl->references++;
return (hl); return (hl);
} }
@@ -222,6 +232,8 @@ hyperlinks_reset(struct hyperlinks *hl)
void void
hyperlinks_free(struct hyperlinks *hl) hyperlinks_free(struct hyperlinks *hl)
{ {
hyperlinks_reset(hl); if (--hl->references == 0) {
free(hl); hyperlinks_reset(hl);
free(hl);
}
} }

View File

@@ -489,6 +489,9 @@ sixel_print(struct sixel_image *si, struct sixel_image *map, size_t *size)
colours = si->colours; colours = si->colours;
ncolours = si->ncolours; ncolours = si->ncolours;
} }
if (ncolours == 0)
return (NULL);
contains = xcalloc(1, ncolours); contains = xcalloc(1, ncolours);
len = 8192; len = 8192;

View File

@@ -307,20 +307,6 @@ static struct input_key_entry input_key_defaults[] = {
{ .key = KEYC_DC|KEYC_BUILD_MODIFIERS, { .key = KEYC_DC|KEYC_BUILD_MODIFIERS,
.data = "\033[3;_~" .data = "\033[3;_~"
}, },
/* Tab and modifiers. */
{ .key = '\011'|KEYC_CTRL,
.data = "\011"
},
{ .key = '\011'|KEYC_CTRL|KEYC_EXTENDED,
.data = "\033[9;5u"
},
{ .key = '\011'|KEYC_CTRL|KEYC_SHIFT,
.data = "\033[Z"
},
{ .key = '\011'|KEYC_CTRL|KEYC_SHIFT|KEYC_EXTENDED,
.data = "\033[1;5Z"
}
}; };
static const key_code input_key_modifiers[] = { static const key_code input_key_modifiers[] = {
0, 0,
@@ -426,126 +412,18 @@ input_key_write(const char *from, struct bufferevent *bev, const char *data,
bufferevent_write(bev, data, size); bufferevent_write(bev, data, size);
} }
/* Translate a key code into an output key sequence. */ /*
int * Encode and write an extended key escape sequence in one of the two
input_key(struct screen *s, struct bufferevent *bev, key_code key) * possible formats, depending on the configured output mode.
*/
static int
input_key_extended(struct bufferevent *bev, key_code key)
{ {
struct input_key_entry *ike = NULL; char tmp[64], modifier;
key_code justkey, newkey, outkey, modifiers; struct utf8_data ud;
struct utf8_data ud; wchar_t wc;
char tmp[64], modifier;
/* Mouse keys need a pane. */ switch (key & KEYC_MASK_MODIFIERS) {
if (KEYC_IS_MOUSE(key))
return (0);
/* Literal keys go as themselves (can't be more than eight bits). */
if (key & KEYC_LITERAL) {
ud.data[0] = (u_char)key;
input_key_write(__func__, bev, &ud.data[0], 1);
return (0);
}
/* Is this backspace? */
if ((key & KEYC_MASK_KEY) == KEYC_BSPACE) {
newkey = options_get_number(global_options, "backspace");
if (newkey >= 0x7f)
newkey = '\177';
key = newkey|(key & (KEYC_MASK_MODIFIERS|KEYC_MASK_FLAGS));
}
/*
* If this is a normal 7-bit key, just send it, with a leading escape
* if necessary. If it is a UTF-8 key, split it and send it.
*/
justkey = (key & ~(KEYC_META|KEYC_IMPLIED_META));
if (justkey <= 0x7f) {
if (key & KEYC_META)
input_key_write(__func__, bev, "\033", 1);
ud.data[0] = justkey;
input_key_write(__func__, bev, &ud.data[0], 1);
return (0);
}
if (KEYC_IS_UNICODE(justkey)) {
if (key & KEYC_META)
input_key_write(__func__, bev, "\033", 1);
utf8_to_data(justkey, &ud);
input_key_write(__func__, bev, ud.data, ud.size);
return (0);
}
/*
* Look up in the tree. If not in application keypad or cursor mode,
* remove the flags from the key.
*/
if (~s->mode & MODE_KKEYPAD)
key &= ~KEYC_KEYPAD;
if (~s->mode & MODE_KCURSOR)
key &= ~KEYC_CURSOR;
if (s->mode & MODE_KEXTENDED)
ike = input_key_get(key|KEYC_EXTENDED);
if (ike == NULL)
ike = input_key_get(key);
if (ike == NULL && (key & KEYC_META) && (~key & KEYC_IMPLIED_META))
ike = input_key_get(key & ~KEYC_META);
if (ike == NULL && (key & KEYC_CURSOR))
ike = input_key_get(key & ~KEYC_CURSOR);
if (ike == NULL && (key & KEYC_KEYPAD))
ike = input_key_get(key & ~KEYC_KEYPAD);
if (ike == NULL && (key & KEYC_EXTENDED))
ike = input_key_get(key & ~KEYC_EXTENDED);
if (ike != NULL) {
log_debug("found key 0x%llx: \"%s\"", key, ike->data);
if ((key == KEYC_PASTE_START || key == KEYC_PASTE_END) &&
(~s->mode & MODE_BRACKETPASTE))
return (0);
if ((key & KEYC_META) && (~key & KEYC_IMPLIED_META))
input_key_write(__func__, bev, "\033", 1);
input_key_write(__func__, bev, ike->data, strlen(ike->data));
return (0);
}
/* No builtin key sequence; construct an extended key sequence. */
if (~s->mode & MODE_KEXTENDED) {
if ((key & KEYC_MASK_MODIFIERS) != KEYC_CTRL)
goto missing;
justkey = (key & KEYC_MASK_KEY);
switch (justkey) {
case ' ':
case '2':
key = 0|(key & ~KEYC_MASK_KEY);
break;
case '|':
key = 28|(key & ~KEYC_MASK_KEY);
break;
case '6':
key = 30|(key & ~KEYC_MASK_KEY);
break;
case '-':
case '/':
key = 31|(key & ~KEYC_MASK_KEY);
break;
case '?':
key = 127|(key & ~KEYC_MASK_KEY);
break;
default:
if (justkey >= 'A' && justkey <= '_')
key = (justkey - 'A')|(key & ~KEYC_MASK_KEY);
else if (justkey >= 'a' && justkey <= '~')
key = (justkey - 96)|(key & ~KEYC_MASK_KEY);
else
return (0);
break;
}
return (input_key(s, bev, key & ~KEYC_CTRL));
}
outkey = (key & KEYC_MASK_KEY);
modifiers = (key & KEYC_MASK_MODIFIERS);
if (outkey < 32 && outkey != 9 && outkey != 13 && outkey != 27) {
outkey = 64 + outkey;
modifiers |= KEYC_CTRL;
}
switch (modifiers) {
case KEYC_SHIFT: case KEYC_SHIFT:
modifier = '2'; modifier = '2';
break; break;
@@ -568,17 +446,247 @@ input_key(struct screen *s, struct bufferevent *bev, key_code key)
modifier = '8'; modifier = '8';
break; break;
default: default:
goto missing; return (-1);
} }
xsnprintf(tmp, sizeof tmp, "\033[%llu;%cu", outkey, modifier);
if (KEYC_IS_UNICODE(key)) {
utf8_to_data(key & KEYC_MASK_KEY, &ud);
if (utf8_towc(&ud, &wc) == UTF8_DONE)
key = wc;
else
return (-1);
} else
key &= KEYC_MASK_KEY;
if (options_get_number(global_options, "extended-keys-format") == 1)
xsnprintf(tmp, sizeof tmp, "\033[27;%c;%llu~", modifier, key);
else
xsnprintf(tmp, sizeof tmp, "\033[%llu;%cu", key, modifier);
input_key_write(__func__, bev, tmp, strlen(tmp)); input_key_write(__func__, bev, tmp, strlen(tmp));
return (0); return (0);
}
/*
* Outputs the key in the "standard" mode. This is by far the most
* complicated output mode, with a lot of remapping in order to
* emulate quirks of terminals that today can be only found in museums.
*/
static int
input_key_vt10x(struct bufferevent *bev, key_code key)
{
struct utf8_data ud;
key_code onlykey;
char *p;
static const char *standard_map[2] = {
"1!9(0)=+;:'\",<.>/-8? 2",
"119900=+;;'',,..\x1f\x1f\x7f\x7f\0\0",
};
log_debug("%s: key in %llx", __func__, key);
if (key & KEYC_META)
input_key_write(__func__, bev, "\033", 1);
/*
* There's no way to report modifiers for unicode keys in standard mode
* so lose the modifiers.
*/
if (KEYC_IS_UNICODE(key)) {
utf8_to_data(key, &ud);
input_key_write(__func__, bev, ud.data, ud.size);
return (0);
}
/* Prevent TAB and RET from being swallowed by C0 remapping logic. */
onlykey = key & KEYC_MASK_KEY;
if (onlykey == '\r' || onlykey == '\t')
key &= ~KEYC_CTRL;
/*
* Convert keys with Ctrl modifier into corresponding C0 control codes,
* with the exception of *some* keys, which are remapped into printable
* ASCII characters.
*
* There is no special handling for Shift modifier, which is pretty
* much redundant anyway, as no terminal will send <base key>|SHIFT,
* but only <shifted key>|SHIFT.
*/
if (key & KEYC_CTRL) {
p = strchr(standard_map[0], onlykey);
if (p != NULL)
key = standard_map[1][p - standard_map[0]];
else if (onlykey >= '3' && onlykey <= '7')
key = onlykey - '\030';
else if (onlykey >= '@' && onlykey <= '~')
key = onlykey & 0x1f;
else
return (-1);
}
log_debug("%s: key out %llx", __func__, key);
ud.data[0] = key & 0x7f;
input_key_write(__func__, bev, &ud.data[0], 1);
return (0);
}
/* Pick keys that are reported as vt10x keys in modifyOtherKeys=1 mode. */
static int
input_key_mode1(struct bufferevent *bev, key_code key)
{
key_code onlykey;
log_debug("%s: key in %llx", __func__, key);
/*
* As per
* https://invisible-island.net/xterm/modified-keys-us-pc105.html.
*/
onlykey = key & KEYC_MASK_KEY;
if ((key & (KEYC_META | KEYC_CTRL)) == KEYC_CTRL &&
(onlykey == ' ' ||
onlykey == '/' ||
onlykey == '@' ||
onlykey == '^' ||
(onlykey >= '2' && onlykey <= '8') ||
(onlykey >= '@' && onlykey <= '~')))
return (input_key_vt10x(bev, key));
/*
* A regular key + Meta. In the absence of a standard to back this, we
* mimic what iTerm 2 does.
*/
if ((key & (KEYC_CTRL | KEYC_META)) == KEYC_META)
return (input_key_vt10x(bev, key));
missing:
log_debug("key 0x%llx missing", key);
return (-1); return (-1);
} }
/* Translate a key code into an output key sequence. */
int
input_key(struct screen *s, struct bufferevent *bev, key_code key)
{
struct input_key_entry *ike = NULL;
key_code newkey;
struct utf8_data ud;
/* Mouse keys need a pane. */
if (KEYC_IS_MOUSE(key))
return (0);
/* Literal keys go as themselves (can't be more than eight bits). */
if (key & KEYC_LITERAL) {
ud.data[0] = (u_char)key;
input_key_write(__func__, bev, &ud.data[0], 1);
return (0);
}
/* Is this backspace? */
if ((key & KEYC_MASK_KEY) == KEYC_BSPACE) {
newkey = options_get_number(global_options, "backspace");
if (newkey >= 0x7f)
newkey = '\177';
key = newkey|(key & (KEYC_MASK_MODIFIERS|KEYC_MASK_FLAGS));
}
/* Is this backtab? */
if ((key & KEYC_MASK_KEY) == KEYC_BTAB) {
if ((s->mode & EXTENDED_KEY_MODES) != 0) {
/* When in xterm extended mode, remap into S-Tab. */
key = '\011' | (key & ~KEYC_MASK_KEY) | KEYC_SHIFT;
} else {
/* Otherwise clear modifiers. */
key &= ~KEYC_MASK_MODIFIERS;
}
}
/*
* A trivial case, that is a 7-bit key, excluding C0 control characters
* that can't be entered from the keyboard, and no modifiers; or a UTF-8
* key and no modifiers.
*/
if (!(key & ~KEYC_MASK_KEY)) {
if (key == C0_HT ||
key == C0_CR ||
key == C0_ESC ||
(key >= 0x20 && key <= 0x7f)) {
ud.data[0] = key;
input_key_write(__func__, bev, &ud.data[0], 1);
return (0);
}
if (KEYC_IS_UNICODE(key)) {
utf8_to_data(key, &ud);
input_key_write(__func__, bev, ud.data, ud.size);
return (0);
}
}
/*
* Look up the standard VT10x keys in the tree. If not in application
* keypad or cursor mode, remove the respective flags from the key.
*/
if (~s->mode & MODE_KKEYPAD)
key &= ~KEYC_KEYPAD;
if (~s->mode & MODE_KCURSOR)
key &= ~KEYC_CURSOR;
if (ike == NULL)
ike = input_key_get(key);
if (ike == NULL && (key & KEYC_META) && (~key & KEYC_IMPLIED_META))
ike = input_key_get(key & ~KEYC_META);
if (ike == NULL && (key & KEYC_CURSOR))
ike = input_key_get(key & ~KEYC_CURSOR);
if (ike == NULL && (key & KEYC_KEYPAD))
ike = input_key_get(key & ~KEYC_KEYPAD);
if (ike != NULL) {
log_debug("%s: found key 0x%llx: \"%s\"", __func__, key,
ike->data);
if ((key == KEYC_PASTE_START || key == KEYC_PASTE_END) &&
(~s->mode & MODE_BRACKETPASTE))
return (0);
if ((key & KEYC_META) && (~key & KEYC_IMPLIED_META))
input_key_write(__func__, bev, "\033", 1);
input_key_write(__func__, bev, ike->data, strlen(ike->data));
return (0);
}
/* Ignore internal function key codes. */
if ((key >= KEYC_BASE && key < KEYC_BASE_END) ||
(key >= KEYC_USER && key < KEYC_USER_END)) {
log_debug("%s: ignoring key 0x%llx", __func__, key);
return (0);
}
/*
* No builtin key sequence; construct an extended key sequence
* depending on the client mode.
*
* If something invalid reaches here, an invalid output may be
* produced. For example Ctrl-Shift-2 is invalid (as there's
* no way to enter it). The correct form is Ctrl-Shift-@, at
* least in US English keyboard layout.
*/
switch (s->mode & EXTENDED_KEY_MODES) {
case MODE_KEYS_EXTENDED_2:
/*
* The simplest mode to handle - *all* modified keys are
* reported in the extended form.
*/
return (input_key_extended(bev, key));
case MODE_KEYS_EXTENDED:
/*
* Some keys are still reported in standard mode, to maintain
* compatibility with applications unaware of extended keys.
*/
if (input_key_mode1(bev, key) == -1)
return (input_key_extended(bev, key));
return (0);
default:
/* The standard mode. */
return (input_key_vt10x(bev, key));
}
}
/* Get mouse event string. */ /* Get mouse event string. */
int int
input_key_get_mouse(struct screen *s, struct mouse_event *m, u_int x, u_int y, input_key_get_mouse(struct screen *s, struct mouse_event *m, u_int x, u_int y,

140
input.c
View File

@@ -109,10 +109,11 @@ struct input_ctx {
int utf8started; int utf8started;
int ch; int ch;
int last; struct utf8_data last;
int flags; int flags;
#define INPUT_DISCARD 0x1 #define INPUT_DISCARD 0x1
#define INPUT_LAST 0x2
const struct input_state *state; const struct input_state *state;
@@ -867,8 +868,6 @@ input_reset(struct input_ctx *ictx, int clear)
input_clear(ictx); input_clear(ictx);
ictx->last = -1;
ictx->state = &input_state_ground; ictx->state = &input_state_ground;
ictx->flags = 0; ictx->flags = 0;
} }
@@ -1149,7 +1148,9 @@ input_print(struct input_ctx *ictx)
utf8_set(&ictx->cell.cell.data, ictx->ch); utf8_set(&ictx->cell.cell.data, ictx->ch);
screen_write_collect_add(sctx, &ictx->cell.cell); screen_write_collect_add(sctx, &ictx->cell.cell);
ictx->last = ictx->ch;
utf8_copy(&ictx->last, &ictx->cell.cell.data);
ictx->flags |= INPUT_LAST;
ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET; ictx->cell.cell.attr &= ~GRID_ATTR_CHARSET;
@@ -1261,7 +1262,7 @@ input_c0_dispatch(struct input_ctx *ictx)
break; break;
} }
ictx->last = -1; ictx->flags &= ~INPUT_LAST;
return (0); return (0);
} }
@@ -1337,7 +1338,7 @@ input_esc_dispatch(struct input_ctx *ictx)
break; break;
} }
ictx->last = -1; ictx->flags &= ~INPUT_LAST;
return (0); return (0);
} }
@@ -1348,7 +1349,7 @@ input_csi_dispatch(struct input_ctx *ictx)
struct screen_write_ctx *sctx = &ictx->ctx; struct screen_write_ctx *sctx = &ictx->ctx;
struct screen *s = sctx->s; struct screen *s = sctx->s;
struct input_table_entry *entry; struct input_table_entry *entry;
int i, n, m; int i, n, m, ek;
u_int cx, bg = ictx->cell.cell.bg; u_int cx, bg = ictx->cell.cell.bg;
if (ictx->flags & INPUT_DISCARD) if (ictx->flags & INPUT_DISCARD)
@@ -1406,18 +1407,36 @@ input_csi_dispatch(struct input_ctx *ictx)
break; break;
case INPUT_CSI_MODSET: case INPUT_CSI_MODSET:
n = input_get(ictx, 0, 0, 0); n = input_get(ictx, 0, 0, 0);
m = input_get(ictx, 1, 0, 0); if (n != 4)
if (options_get_number(global_options, "extended-keys") == 2)
break; break;
if (n == 0 || (n == 4 && m == 0)) m = input_get(ictx, 1, 0, 0);
screen_write_mode_clear(sctx, MODE_KEXTENDED);
else if (n == 4 && (m == 1 || m == 2)) /*
screen_write_mode_set(sctx, MODE_KEXTENDED); * Set the extended key reporting mode as per the client
* request, unless "extended-keys" is set to "off".
*/
ek = options_get_number(global_options, "extended-keys");
if (ek == 0)
break;
screen_write_mode_clear(sctx, EXTENDED_KEY_MODES);
if (m == 2)
screen_write_mode_set(sctx, MODE_KEYS_EXTENDED_2);
else if (m == 1 || ek == 2)
screen_write_mode_set(sctx, MODE_KEYS_EXTENDED);
break; break;
case INPUT_CSI_MODOFF: case INPUT_CSI_MODOFF:
n = input_get(ictx, 0, 0, 0); n = input_get(ictx, 0, 0, 0);
if (n == 4) if (n != 4)
screen_write_mode_clear(sctx, MODE_KEXTENDED); break;
/*
* Clear the extended key reporting mode as per the client
* request, unless "extended-keys always" forces into mode 1.
*/
screen_write_mode_clear(sctx,
MODE_KEYS_EXTENDED|MODE_KEYS_EXTENDED_2);
if (options_get_number(global_options, "extended-keys") == 2)
screen_write_mode_set(sctx, MODE_KEYS_EXTENDED);
break; break;
case INPUT_CSI_WINOPS: case INPUT_CSI_WINOPS:
input_csi_dispatch_winops(ictx); input_csi_dispatch_winops(ictx);
@@ -1574,12 +1593,12 @@ input_csi_dispatch(struct input_ctx *ictx)
if (n > m) if (n > m)
n = m; n = m;
if (ictx->last == -1) if (~ictx->flags & INPUT_LAST)
break; break;
ictx->ch = ictx->last;
utf8_copy(&ictx->cell.cell.data, &ictx->last);
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
input_print(ictx); screen_write_collect_add(sctx, &ictx->cell.cell);
break; break;
case INPUT_CSI_RCP: case INPUT_CSI_RCP:
input_restore_state(ictx); input_restore_state(ictx);
@@ -1649,7 +1668,7 @@ input_csi_dispatch(struct input_ctx *ictx)
} }
ictx->last = -1; ictx->flags &= ~INPUT_LAST;
return (0); return (0);
} }
@@ -1839,7 +1858,7 @@ input_csi_dispatch_sm_private(struct input_ctx *ictx)
/* Handle CSI graphics SM. */ /* Handle CSI graphics SM. */
static void static void
input_csi_dispatch_sm_graphics(struct input_ctx *ictx) input_csi_dispatch_sm_graphics(__unused struct input_ctx *ictx)
{ {
#ifdef ENABLE_SIXEL #ifdef ENABLE_SIXEL
int n, m, o; int n, m, o;
@@ -2284,7 +2303,7 @@ input_enter_dcs(struct input_ctx *ictx)
input_clear(ictx); input_clear(ictx);
input_start_timer(ictx); input_start_timer(ictx);
ictx->last = -1; ictx->flags &= ~INPUT_LAST;
} }
/* DCS terminator (ST) received. */ /* DCS terminator (ST) received. */
@@ -2341,7 +2360,7 @@ input_enter_osc(struct input_ctx *ictx)
input_clear(ictx); input_clear(ictx);
input_start_timer(ictx); input_start_timer(ictx);
ictx->last = -1; ictx->flags &= ~INPUT_LAST;
} }
/* OSC terminator (ST) received. */ /* OSC terminator (ST) received. */
@@ -2372,7 +2391,9 @@ input_exit_osc(struct input_ctx *ictx)
switch (option) { switch (option) {
case 0: case 0:
case 2: case 2:
if (screen_set_title(sctx->s, p) && wp != NULL) { if (wp != NULL &&
options_get_number(wp->options, "allow-set-title") &&
screen_set_title(sctx->s, p)) {
notify_pane("pane-title-changed", wp); notify_pane("pane-title-changed", wp);
server_redraw_window_borders(wp->window); server_redraw_window_borders(wp->window);
server_status_window(wp->window); server_status_window(wp->window);
@@ -2434,7 +2455,7 @@ input_enter_apc(struct input_ctx *ictx)
input_clear(ictx); input_clear(ictx);
input_start_timer(ictx); input_start_timer(ictx);
ictx->last = -1; ictx->flags &= ~INPUT_LAST;
} }
/* APC terminator (ST) received. */ /* APC terminator (ST) received. */
@@ -2463,7 +2484,7 @@ input_enter_rename(struct input_ctx *ictx)
input_clear(ictx); input_clear(ictx);
input_start_timer(ictx); input_start_timer(ictx);
ictx->last = -1; ictx->flags &= ~INPUT_LAST;
} }
/* Rename terminator (ST) received. */ /* Rename terminator (ST) received. */
@@ -2507,7 +2528,7 @@ input_top_bit_set(struct input_ctx *ictx)
struct screen_write_ctx *sctx = &ictx->ctx; struct screen_write_ctx *sctx = &ictx->ctx;
struct utf8_data *ud = &ictx->utf8data; struct utf8_data *ud = &ictx->utf8data;
ictx->last = -1; ictx->flags &= ~INPUT_LAST;
if (!ictx->utf8started) { if (!ictx->utf8started) {
if (utf8_open(ud, ictx->ch) != UTF8_MORE) if (utf8_open(ud, ictx->ch) != UTF8_MORE)
@@ -2533,6 +2554,9 @@ input_top_bit_set(struct input_ctx *ictx)
utf8_copy(&ictx->cell.cell.data, ud); utf8_copy(&ictx->cell.cell.data, ud);
screen_write_collect_add(sctx, &ictx->cell.cell); screen_write_collect_add(sctx, &ictx->cell.cell);
utf8_copy(&ictx->last, &ictx->cell.cell.data);
ictx->flags |= INPUT_LAST;
return (0); return (0);
} }
@@ -2681,6 +2705,44 @@ input_get_bg_client(struct window_pane *wp)
return (-1); return (-1);
} }
/*
* If any control mode client exists that has provided a bg color, return it.
* Otherwise, return -1.
*/
static int
input_get_bg_control_client(struct window_pane *wp)
{
struct client *c;
if (wp->control_bg == -1)
return (-1);
TAILQ_FOREACH(c, &clients, entry) {
if (c->flags & CLIENT_CONTROL)
return (wp->control_bg);
}
return (-1);
}
/*
* If any control mode client exists that has provided a fg color, return it.
* Otherwise, return -1.
*/
static int
input_get_fg_control_client(struct window_pane *wp)
{
struct client *c;
if (wp->control_fg == -1)
return (-1);
TAILQ_FOREACH(c, &clients, entry) {
if (c->flags & CLIENT_CONTROL)
return (wp->control_fg);
}
return (-1);
}
/* Handle the OSC 10 sequence for setting and querying foreground colour. */ /* Handle the OSC 10 sequence for setting and querying foreground colour. */
static void static void
input_osc_10(struct input_ctx *ictx, const char *p) input_osc_10(struct input_ctx *ictx, const char *p)
@@ -2692,11 +2754,14 @@ input_osc_10(struct input_ctx *ictx, const char *p)
if (strcmp(p, "?") == 0) { if (strcmp(p, "?") == 0) {
if (wp == NULL) if (wp == NULL)
return; return;
tty_default_colours(&defaults, wp); c = input_get_fg_control_client(wp);
if (COLOUR_DEFAULT(defaults.fg)) if (c == -1) {
c = input_get_fg_client(wp); tty_default_colours(&defaults, wp);
else if (COLOUR_DEFAULT(defaults.fg))
c = defaults.fg; c = input_get_fg_client(wp);
else
c = defaults.fg;
}
input_osc_colour_reply(ictx, 10, c); input_osc_colour_reply(ictx, 10, c);
return; return;
} }
@@ -2740,11 +2805,14 @@ input_osc_11(struct input_ctx *ictx, const char *p)
if (strcmp(p, "?") == 0) { if (strcmp(p, "?") == 0) {
if (wp == NULL) if (wp == NULL)
return; return;
tty_default_colours(&defaults, wp); c = input_get_bg_control_client(wp);
if (COLOUR_DEFAULT(defaults.bg)) if (c == -1) {
c = input_get_bg_client(wp); tty_default_colours(&defaults, wp);
else if (COLOUR_DEFAULT(defaults.bg))
c = defaults.bg; c = input_get_bg_client(wp);
else
c = defaults.bg;
}
input_osc_colour_reply(ictx, 11, c); input_osc_colour_reply(ictx, 11, c);
return; return;
} }

31
job.c
View File

@@ -77,19 +77,28 @@ job_run(const char *cmd, int argc, char **argv, struct environ *e, struct sessio
struct environ *env; struct environ *env;
pid_t pid; pid_t pid;
int nullfd, out[2], master; int nullfd, out[2], master;
const char *home; const char *home, *shell;
sigset_t set, oldset; sigset_t set, oldset;
struct winsize ws; struct winsize ws;
char **argvp, tty[TTY_NAME_MAX]; char **argvp, tty[TTY_NAME_MAX], *argv0;
/* /*
* Do not set TERM during .tmux.conf, it is nice to be able to use * Do not set TERM during .tmux.conf (second argument here), it is nice
* if-shell to decide on default-terminal based on outside TERM. * to be able to use if-shell to decide on default-terminal based on
* outside TERM.
*/ */
env = environ_for_session(s, !cfg_finished); env = environ_for_session(s, !cfg_finished);
if (e != NULL) if (e != NULL)
environ_copy(e, env); environ_copy(e, env);
if (s != NULL)
shell = options_get_string(s->options, "default-shell");
else
shell = options_get_string(global_s_options, "default-shell");
if (!checkshell(shell))
shell = _PATH_BSHELL;
argv0 = shell_argv0(shell, 0);
sigfillset(&set); sigfillset(&set);
sigprocmask(SIG_BLOCK, &set, &oldset); sigprocmask(SIG_BLOCK, &set, &oldset);
@@ -105,10 +114,11 @@ job_run(const char *cmd, int argc, char **argv, struct environ *e, struct sessio
} }
if (cmd == NULL) { if (cmd == NULL) {
cmd_log_argv(argc, argv, "%s:", __func__); cmd_log_argv(argc, argv, "%s:", __func__);
log_debug("%s: cwd=%s", __func__, cwd == NULL ? "" : cwd); log_debug("%s: cwd=%s, shell=%s", __func__,
cwd == NULL ? "" : cwd, shell);
} else { } else {
log_debug("%s: cmd=%s, cwd=%s", __func__, cmd, log_debug("%s: cmd=%s, cwd=%s, shell=%s", __func__, cmd,
cwd == NULL ? "" : cwd); cwd == NULL ? "" : cwd, shell);
} }
switch (pid) { switch (pid) {
@@ -150,7 +160,8 @@ job_run(const char *cmd, int argc, char **argv, struct environ *e, struct sessio
closefrom(STDERR_FILENO + 1); closefrom(STDERR_FILENO + 1);
if (cmd != NULL) { if (cmd != NULL) {
execl(_PATH_BSHELL, "sh", "-c", cmd, (char *) NULL); setenv("SHELL", shell, 1);
execl(shell, argv0, "-c", cmd, (char *)NULL);
fatal("execl failed"); fatal("execl failed");
} else { } else {
argvp = cmd_copy_argv(argc, argv); argvp = cmd_copy_argv(argc, argv);
@@ -161,6 +172,7 @@ job_run(const char *cmd, int argc, char **argv, struct environ *e, struct sessio
sigprocmask(SIG_SETMASK, &oldset, NULL); sigprocmask(SIG_SETMASK, &oldset, NULL);
environ_free(env); environ_free(env);
free(argv0);
job = xmalloc(sizeof *job); job = xmalloc(sizeof *job);
job->state = JOB_RUNNING; job->state = JOB_RUNNING;
@@ -194,12 +206,13 @@ job_run(const char *cmd, int argc, char **argv, struct environ *e, struct sessio
fatalx("out of memory"); fatalx("out of memory");
bufferevent_enable(job->event, EV_READ|EV_WRITE); bufferevent_enable(job->event, EV_READ|EV_WRITE);
log_debug("run job %p: %s, pid %ld", job, job->cmd, (long) job->pid); log_debug("run job %p: %s, pid %ld", job, job->cmd, (long)job->pid);
return (job); return (job);
fail: fail:
sigprocmask(SIG_SETMASK, &oldset, NULL); sigprocmask(SIG_SETMASK, &oldset, NULL);
environ_free(env); environ_free(env);
free(argv0);
return (NULL); return (NULL);
} }

View File

@@ -413,6 +413,8 @@ key_bindings_init(void)
"bind -N 'Set the main-horizontal layout' M-3 { select-layout main-horizontal }", "bind -N 'Set the main-horizontal layout' M-3 { select-layout main-horizontal }",
"bind -N 'Set the main-vertical layout' M-4 { select-layout main-vertical }", "bind -N 'Set the main-vertical layout' M-4 { select-layout main-vertical }",
"bind -N 'Select the tiled layout' M-5 { select-layout tiled }", "bind -N 'Select the tiled layout' M-5 { select-layout tiled }",
"bind -N 'Set the main-horizontal-mirrored layout' M-6 { select-layout main-horizontal-mirrored }",
"bind -N 'Set the main-vertical-mirrored layout' M-7 { select-layout main-vertical-mirrored }",
"bind -N 'Select the next window with an alert' M-n { next-window -a }", "bind -N 'Select the next window with an alert' M-n { next-window -a }",
"bind -N 'Rotate through the panes in reverse' M-o { rotate-window -D }", "bind -N 'Rotate through the panes in reverse' M-o { rotate-window -D }",
"bind -N 'Select the previous window with an alert' M-p { previous-window -a }", "bind -N 'Select the previous window with an alert' M-p { previous-window -a }",

View File

@@ -18,6 +18,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <ctype.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <wchar.h> #include <wchar.h>
@@ -56,12 +57,47 @@ static const struct {
{ "PPage", KEYC_PPAGE|KEYC_IMPLIED_META }, { "PPage", KEYC_PPAGE|KEYC_IMPLIED_META },
{ "PageUp", KEYC_PPAGE|KEYC_IMPLIED_META }, { "PageUp", KEYC_PPAGE|KEYC_IMPLIED_META },
{ "PgUp", KEYC_PPAGE|KEYC_IMPLIED_META }, { "PgUp", KEYC_PPAGE|KEYC_IMPLIED_META },
{ "Tab", '\011' },
{ "BTab", KEYC_BTAB }, { "BTab", KEYC_BTAB },
{ "Space", ' ' }, { "Space", ' ' },
{ "BSpace", KEYC_BSPACE }, { "BSpace", KEYC_BSPACE },
{ "Enter", '\r' },
{ "Escape", '\033' }, /*
* C0 control characters, with the exception of Tab, Enter,
* and Esc, should never appear as keys. We still render them,
* so to be able to spot them in logs in case of an abnormality.
*/
{ "[NUL]", C0_NUL },
{ "[SOH]", C0_SOH },
{ "[STX]", C0_STX },
{ "[ETX]", C0_ETX },
{ "[EOT]", C0_EOT },
{ "[ENQ]", C0_ENQ },
{ "[ASC]", C0_ASC },
{ "[BEL]", C0_BEL },
{ "[BS]", C0_BS },
{ "Tab", C0_HT },
{ "[LF]", C0_LF },
{ "[VT]", C0_VT },
{ "[FF]", C0_FF },
{ "Enter", C0_CR },
{ "[SO]", C0_SO },
{ "[SI]", C0_SI },
{ "[DLE]", C0_DLE },
{ "[DC1]", C0_DC1 },
{ "[DC2]", C0_DC2 },
{ "[DC3]", C0_DC3 },
{ "[DC4]", C0_DC4 },
{ "[NAK]", C0_NAK },
{ "[SYN]", C0_SYN },
{ "[ETB]", C0_ETB },
{ "[CAN]", C0_CAN },
{ "[EM]", C0_EM },
{ "[SUB]", C0_SUB },
{ "Escape", C0_ESC },
{ "[FS]", C0_FS },
{ "[GS]", C0_GS },
{ "[RS]", C0_RS },
{ "[US]", C0_US },
/* Arrow keys. */ /* Arrow keys. */
{ "Up", KEYC_UP|KEYC_CURSOR|KEYC_IMPLIED_META }, { "Up", KEYC_UP|KEYC_CURSOR|KEYC_IMPLIED_META },
@@ -206,8 +242,7 @@ key_string_get_modifiers(const char **string)
key_code key_code
key_string_lookup_string(const char *string) key_string_lookup_string(const char *string)
{ {
static const char *other = "!#()+,-.0123456789:;<=>'\r\t\177`/"; key_code key, modifiers = 0;
key_code key, modifiers;
u_int u, i; u_int u, i;
struct utf8_data ud, *udp; struct utf8_data ud, *udp;
enum utf8_state more; enum utf8_state more;
@@ -244,12 +279,15 @@ key_string_lookup_string(const char *string)
return (uc); return (uc);
} }
/* Check for modifiers. */ /* Check for short Ctrl key. */
modifiers = 0;
if (string[0] == '^' && string[1] != '\0') { if (string[0] == '^' && string[1] != '\0') {
if (string[2] == '\0')
return (tolower((u_char)string[1])|KEYC_CTRL);
modifiers |= KEYC_CTRL; modifiers |= KEYC_CTRL;
string++; string++;
} }
/* Check for modifiers. */
modifiers |= key_string_get_modifiers(&string); modifiers |= key_string_get_modifiers(&string);
if (string == NULL || string[0] == '\0') if (string == NULL || string[0] == '\0')
return (KEYC_UNKNOWN); return (KEYC_UNKNOWN);
@@ -281,26 +319,6 @@ key_string_lookup_string(const char *string)
key &= ~KEYC_IMPLIED_META; key &= ~KEYC_IMPLIED_META;
} }
/* Convert the standard control keys. */
if (key <= 127 &&
(modifiers & KEYC_CTRL) &&
strchr(other, key) == NULL &&
key != 9 &&
key != 13 &&
key != 27) {
if (key >= 97 && key <= 122)
key -= 96;
else if (key >= 64 && key <= 95)
key -= 64;
else if (key == 32)
key = 0;
else if (key == 63)
key = 127;
else
return (KEYC_UNKNOWN);
modifiers &= ~KEYC_CTRL;
}
return (key|modifiers); return (key|modifiers);
} }
@@ -324,10 +342,6 @@ key_string_lookup_key(key_code key, int with_flags)
goto out; goto out;
} }
/* Display C-@ as C-Space. */
if ((key & (KEYC_MASK_KEY|KEYC_MASK_MODIFIERS)) == 0)
key = ' '|KEYC_CTRL;
/* Fill in the modifiers. */ /* Fill in the modifiers. */
if (key & KEYC_CTRL) if (key & KEYC_CTRL)
strlcat(out, "C-", sizeof out); strlcat(out, "C-", sizeof out);
@@ -396,7 +410,7 @@ key_string_lookup_key(key_code key, int with_flags)
s = "MouseMoveBorder"; s = "MouseMoveBorder";
goto append; goto append;
} }
if (key >= KEYC_USER && key < KEYC_USER + KEYC_NUSER) { if (key >= KEYC_USER && key < KEYC_USER_END) {
snprintf(tmp, sizeof tmp, "User%u", (u_int)(key - KEYC_USER)); snprintf(tmp, sizeof tmp, "User%u", (u_int)(key - KEYC_USER));
strlcat(out, tmp, sizeof out); strlcat(out, tmp, sizeof out);
goto out; goto out;
@@ -427,13 +441,8 @@ key_string_lookup_key(key_code key, int with_flags)
goto out; goto out;
} }
/* Check for standard or control key. */ /* Printable ASCII keys. */
if (key <= 32) { if (key > 32 && key <= 126) {
if (key == 0 || key > 26)
xsnprintf(tmp, sizeof tmp, "C-%c", (int)(64 + key));
else
xsnprintf(tmp, sizeof tmp, "C-%c", (int)(96 + key));
} else if (key >= 32 && key <= 126) {
tmp[0] = key; tmp[0] = key;
tmp[1] = '\0'; tmp[1] = '\0';
} else if (key == 127) } else if (key == 127)
@@ -460,8 +469,6 @@ out:
strlcat(out, "I", sizeof out); strlcat(out, "I", sizeof out);
if (saved & KEYC_BUILD_MODIFIERS) if (saved & KEYC_BUILD_MODIFIERS)
strlcat(out, "B", sizeof out); strlcat(out, "B", sizeof out);
if (saved & KEYC_EXTENDED)
strlcat(out, "E", sizeof out);
if (saved & KEYC_SENT) if (saved & KEYC_SENT)
strlcat(out, "S", sizeof out); strlcat(out, "S", sizeof out);
strlcat(out, "]", sizeof out); strlcat(out, "]", sizeof out);

View File

@@ -230,7 +230,7 @@ layout_parse(struct window *w, const char *layout, char **cause)
/* Check the new layout. */ /* Check the new layout. */
if (!layout_check(lc)) { if (!layout_check(lc)) {
*cause = xstrdup("size mismatch after applying layout"); *cause = xstrdup("size mismatch after applying layout");
return (-1); goto fail;
} }
/* Resize to the layout size. */ /* Resize to the layout size. */

View File

@@ -31,7 +31,9 @@
static void layout_set_even_h(struct window *); static void layout_set_even_h(struct window *);
static void layout_set_even_v(struct window *); static void layout_set_even_v(struct window *);
static void layout_set_main_h(struct window *); static void layout_set_main_h(struct window *);
static void layout_set_main_h_mirrored(struct window *);
static void layout_set_main_v(struct window *); static void layout_set_main_v(struct window *);
static void layout_set_main_v_mirrored(struct window *);
static void layout_set_tiled(struct window *); static void layout_set_tiled(struct window *);
static const struct { static const struct {
@@ -41,7 +43,9 @@ static const struct {
{ "even-horizontal", layout_set_even_h }, { "even-horizontal", layout_set_even_h },
{ "even-vertical", layout_set_even_v }, { "even-vertical", layout_set_even_v },
{ "main-horizontal", layout_set_main_h }, { "main-horizontal", layout_set_main_h },
{ "main-horizontal-mirrored", layout_set_main_h_mirrored },
{ "main-vertical", layout_set_main_v }, { "main-vertical", layout_set_main_v },
{ "main-vertical-mirrored", layout_set_main_v_mirrored },
{ "tiled", layout_set_tiled }, { "tiled", layout_set_tiled },
}; };
@@ -51,6 +55,10 @@ layout_set_lookup(const char *name)
u_int i; u_int i;
int matched = -1; int matched = -1;
for (i = 0; i < nitems(layout_sets); i++) {
if (strcmp(layout_sets[i].name, name) == 0)
return (i);
}
for (i = 0; i < nitems(layout_sets); i++) { for (i = 0; i < nitems(layout_sets); i++) {
if (strncmp(layout_sets[i].name, name, strlen(name)) == 0) { if (strncmp(layout_sets[i].name, name, strlen(name)) == 0) {
if (matched != -1) /* ambiguous */ if (matched != -1) /* ambiguous */
@@ -279,6 +287,104 @@ layout_set_main_h(struct window *w)
server_redraw_window(w); server_redraw_window(w);
} }
static void
layout_set_main_h_mirrored(struct window *w)
{
struct window_pane *wp;
struct layout_cell *lc, *lcmain, *lcother, *lcchild;
u_int n, mainh, otherh, sx, sy;
char *cause;
const char *s;
layout_print_cell(w->layout_root, __func__, 1);
/* Get number of panes. */
n = window_count_panes(w);
if (n <= 1)
return;
n--; /* take off main pane */
/* Find available height - take off one line for the border. */
sy = w->sy - 1;
/* Get the main pane height. */
s = options_get_string(w->options, "main-pane-height");
mainh = args_string_percentage(s, 0, sy, sy, &cause);
if (cause != NULL) {
mainh = 24;
free(cause);
}
/* Work out the other pane height. */
if (mainh + PANE_MINIMUM >= sy) {
if (sy <= PANE_MINIMUM + PANE_MINIMUM)
mainh = PANE_MINIMUM;
else
mainh = sy - PANE_MINIMUM;
otherh = PANE_MINIMUM;
} else {
s = options_get_string(w->options, "other-pane-height");
otherh = args_string_percentage(s, 0, sy, sy, &cause);
if (cause != NULL || otherh == 0) {
otherh = sy - mainh;
free(cause);
} else if (otherh > sy || sy - otherh < mainh)
otherh = sy - mainh;
else
mainh = sy - otherh;
}
/* Work out what width is needed. */
sx = (n * (PANE_MINIMUM + 1)) - 1;
if (sx < w->sx)
sx = w->sx;
/* Free old tree and create a new root. */
layout_free(w);
lc = w->layout_root = layout_create_cell(NULL);
layout_set_size(lc, sx, mainh + otherh + 1, 0, 0);
layout_make_node(lc, LAYOUT_TOPBOTTOM);
/* Create the other pane. */
lcother = layout_create_cell(lc);
layout_set_size(lcother, sx, otherh, 0, 0);
if (n == 1) {
wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry);
layout_make_leaf(lcother, wp);
TAILQ_INSERT_TAIL(&lc->cells, lcother, entry);
} else {
layout_make_node(lcother, LAYOUT_LEFTRIGHT);
TAILQ_INSERT_TAIL(&lc->cells, lcother, entry);
/* Add the remaining panes as children. */
TAILQ_FOREACH(wp, &w->panes, entry) {
if (wp == TAILQ_FIRST(&w->panes))
continue;
lcchild = layout_create_cell(lcother);
layout_set_size(lcchild, PANE_MINIMUM, otherh, 0, 0);
layout_make_leaf(lcchild, wp);
TAILQ_INSERT_TAIL(&lcother->cells, lcchild, entry);
}
layout_spread_cell(w, lcother);
}
/* Create the main pane. */
lcmain = layout_create_cell(lc);
layout_set_size(lcmain, sx, mainh, 0, 0);
layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes));
TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry);
/* Fix cell offsets. */
layout_fix_offsets(w);
layout_fix_panes(w, NULL);
layout_print_cell(w->layout_root, __func__, 1);
window_resize(w, lc->sx, lc->sy, -1, -1);
notify_window("window-layout-changed", w);
server_redraw_window(w);
}
static void static void
layout_set_main_v(struct window *w) layout_set_main_v(struct window *w)
{ {
@@ -377,6 +483,104 @@ layout_set_main_v(struct window *w)
server_redraw_window(w); server_redraw_window(w);
} }
static void
layout_set_main_v_mirrored(struct window *w)
{
struct window_pane *wp;
struct layout_cell *lc, *lcmain, *lcother, *lcchild;
u_int n, mainw, otherw, sx, sy;
char *cause;
const char *s;
layout_print_cell(w->layout_root, __func__, 1);
/* Get number of panes. */
n = window_count_panes(w);
if (n <= 1)
return;
n--; /* take off main pane */
/* Find available width - take off one line for the border. */
sx = w->sx - 1;
/* Get the main pane width. */
s = options_get_string(w->options, "main-pane-width");
mainw = args_string_percentage(s, 0, sx, sx, &cause);
if (cause != NULL) {
mainw = 80;
free(cause);
}
/* Work out the other pane width. */
if (mainw + PANE_MINIMUM >= sx) {
if (sx <= PANE_MINIMUM + PANE_MINIMUM)
mainw = PANE_MINIMUM;
else
mainw = sx - PANE_MINIMUM;
otherw = PANE_MINIMUM;
} else {
s = options_get_string(w->options, "other-pane-width");
otherw = args_string_percentage(s, 0, sx, sx, &cause);
if (cause != NULL || otherw == 0) {
otherw = sx - mainw;
free(cause);
} else if (otherw > sx || sx - otherw < mainw)
otherw = sx - mainw;
else
mainw = sx - otherw;
}
/* Work out what height is needed. */
sy = (n * (PANE_MINIMUM + 1)) - 1;
if (sy < w->sy)
sy = w->sy;
/* Free old tree and create a new root. */
layout_free(w);
lc = w->layout_root = layout_create_cell(NULL);
layout_set_size(lc, mainw + otherw + 1, sy, 0, 0);
layout_make_node(lc, LAYOUT_LEFTRIGHT);
/* Create the other pane. */
lcother = layout_create_cell(lc);
layout_set_size(lcother, otherw, sy, 0, 0);
if (n == 1) {
wp = TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry);
layout_make_leaf(lcother, wp);
TAILQ_INSERT_TAIL(&lc->cells, lcother, entry);
} else {
layout_make_node(lcother, LAYOUT_TOPBOTTOM);
TAILQ_INSERT_TAIL(&lc->cells, lcother, entry);
/* Add the remaining panes as children. */
TAILQ_FOREACH(wp, &w->panes, entry) {
if (wp == TAILQ_FIRST(&w->panes))
continue;
lcchild = layout_create_cell(lcother);
layout_set_size(lcchild, otherw, PANE_MINIMUM, 0, 0);
layout_make_leaf(lcchild, wp);
TAILQ_INSERT_TAIL(&lcother->cells, lcchild, entry);
}
layout_spread_cell(w, lcother);
}
/* Create the main pane. */
lcmain = layout_create_cell(lc);
layout_set_size(lcmain, mainw, sy, 0, 0);
layout_make_leaf(lcmain, TAILQ_FIRST(&w->panes));
TAILQ_INSERT_TAIL(&lc->cells, lcmain, entry);
/* Fix cell offsets. */
layout_fix_offsets(w);
layout_fix_panes(w, NULL);
layout_print_cell(w->layout_root, __func__, 1);
window_resize(w, lc->sx, lc->sy, -1, -1);
notify_window("window-layout-changed", w);
server_redraw_window(w);
}
void void
layout_set_tiled(struct window *w) layout_set_tiled(struct window *w)
{ {

8
menu.c
View File

@@ -335,7 +335,7 @@ menu_key_cb(struct client *c, void *data, struct key_event *event)
c->flags |= CLIENT_REDRAWOVERLAY; c->flags |= CLIENT_REDRAWOVERLAY;
return (0); return (0);
case KEYC_PPAGE: case KEYC_PPAGE:
case '\002': /* C-b */ case 'b'|KEYC_CTRL:
if (md->choice < 6) if (md->choice < 6)
md->choice = 0; md->choice = 0;
else { else {
@@ -394,13 +394,13 @@ menu_key_cb(struct client *c, void *data, struct key_event *event)
} }
c->flags |= CLIENT_REDRAWOVERLAY; c->flags |= CLIENT_REDRAWOVERLAY;
break; break;
case '\006': /* C-f */ case 'f'|KEYC_CTRL:
break; break;
case '\r': case '\r':
goto chosen; goto chosen;
case '\033': /* Escape */ case '\033': /* Escape */
case '\003': /* C-c */ case 'c'|KEYC_CTRL:
case '\007': /* C-g */ case 'g'|KEYC_CTRL:
case 'q': case 'q':
return (1); return (1);
} }

View File

@@ -25,6 +25,11 @@
#include "tmux.h" #include "tmux.h"
enum mode_tree_search_dir {
MODE_TREE_SEARCH_FORWARD,
MODE_TREE_SEARCH_BACKWARD
};
struct mode_tree_item; struct mode_tree_item;
TAILQ_HEAD(mode_tree_list, mode_tree_item); TAILQ_HEAD(mode_tree_list, mode_tree_item);
@@ -68,6 +73,7 @@ struct mode_tree_data {
char *search; char *search;
char *filter; char *filter;
int no_matches; int no_matches;
enum mode_tree_search_dir search_dir;
}; };
struct mode_tree_item { struct mode_tree_item {
@@ -255,19 +261,21 @@ mode_tree_up(struct mode_tree_data *mtd, int wrap)
} }
} }
void int
mode_tree_down(struct mode_tree_data *mtd, int wrap) mode_tree_down(struct mode_tree_data *mtd, int wrap)
{ {
if (mtd->current == mtd->line_size - 1) { if (mtd->current == mtd->line_size - 1) {
if (wrap) { if (wrap) {
mtd->current = 0; mtd->current = 0;
mtd->offset = 0; mtd->offset = 0;
} } else
return (0);
} else { } else {
mtd->current++; mtd->current++;
if (mtd->current > mtd->offset + mtd->height - 1) if (mtd->current > mtd->offset + mtd->height - 1)
mtd->offset++; mtd->offset++;
} }
return (1);
} }
void * void *
@@ -786,7 +794,49 @@ done:
} }
static struct mode_tree_item * static struct mode_tree_item *
mode_tree_search_for(struct mode_tree_data *mtd) mode_tree_search_backward(struct mode_tree_data *mtd)
{
struct mode_tree_item *mti, *last, *prev;
if (mtd->search == NULL)
return (NULL);
mti = last = mtd->line_list[mtd->current].item;
for (;;) {
if ((prev = TAILQ_PREV(mti, mode_tree_list, entry)) != NULL) {
/* Point to the last child in the previous subtree. */
while (!TAILQ_EMPTY(&prev->children))
prev = TAILQ_LAST(&prev->children, mode_tree_list);
mti = prev;
} else {
/* If prev is NULL, jump to the parent. */
mti = mti->parent;
}
if (mti == NULL) {
/* Point to the last child in the last root subtree. */
prev = TAILQ_LAST(&mtd->children, mode_tree_list);
while (!TAILQ_EMPTY(&prev->children))
prev = TAILQ_LAST(&prev->children, mode_tree_list);
mti = prev;
}
if (mti == last)
break;
if (mtd->searchcb == NULL) {
if (strstr(mti->name, mtd->search) != NULL)
return (mti);
continue;
}
if (mtd->searchcb(mtd->modedata, mti->itemdata, mtd->search))
return (mti);
}
return (NULL);
}
static struct mode_tree_item *
mode_tree_search_forward(struct mode_tree_data *mtd)
{ {
struct mode_tree_item *mti, *last, *next; struct mode_tree_item *mti, *last, *next;
@@ -832,7 +882,10 @@ mode_tree_search_set(struct mode_tree_data *mtd)
struct mode_tree_item *mti, *loop; struct mode_tree_item *mti, *loop;
uint64_t tag; uint64_t tag;
mti = mode_tree_search_for(mtd); if (mtd->search_dir == MODE_TREE_SEARCH_FORWARD)
mti = mode_tree_search_forward(mtd);
else
mti = mode_tree_search_backward(mtd);
if (mti == NULL) if (mti == NULL)
return; return;
tag = mti->tag; tag = mti->tag;
@@ -1035,22 +1088,22 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
switch (*key) { switch (*key) {
case 'q': case 'q':
case '\033': /* Escape */ case '\033': /* Escape */
case '\007': /* C-g */ case 'g'|KEYC_CTRL:
return (1); return (1);
case KEYC_UP: case KEYC_UP:
case 'k': case 'k':
case KEYC_WHEELUP_PANE: case KEYC_WHEELUP_PANE:
case '\020': /* C-p */ case 'p'|KEYC_CTRL:
mode_tree_up(mtd, 1); mode_tree_up(mtd, 1);
break; break;
case KEYC_DOWN: case KEYC_DOWN:
case 'j': case 'j':
case KEYC_WHEELDOWN_PANE: case KEYC_WHEELDOWN_PANE:
case '\016': /* C-n */ case 'n'|KEYC_CTRL:
mode_tree_down(mtd, 1); mode_tree_down(mtd, 1);
break; break;
case KEYC_PPAGE: case KEYC_PPAGE:
case '\002': /* C-b */ case 'b'|KEYC_CTRL:
for (i = 0; i < mtd->height; i++) { for (i = 0; i < mtd->height; i++) {
if (mtd->current == 0) if (mtd->current == 0)
break; break;
@@ -1058,7 +1111,7 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
} }
break; break;
case KEYC_NPAGE: case KEYC_NPAGE:
case '\006': /* C-f */ case 'f'|KEYC_CTRL:
for (i = 0; i < mtd->height; i++) { for (i = 0; i < mtd->height; i++) {
if (mtd->current == mtd->line_size - 1) if (mtd->current == mtd->line_size - 1)
break; break;
@@ -1102,7 +1155,7 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
for (i = 0; i < mtd->line_size; i++) for (i = 0; i < mtd->line_size; i++)
mtd->line_list[i].item->tagged = 0; mtd->line_list[i].item->tagged = 0;
break; break;
case '\024': /* C-t */ case 't'|KEYC_CTRL:
for (i = 0; i < mtd->line_size; i++) { for (i = 0; i < mtd->line_size; i++) {
if ((mtd->line_list[i].item->parent == NULL && if ((mtd->line_list[i].item->parent == NULL &&
!mtd->line_list[i].item->no_tag) || !mtd->line_list[i].item->no_tag) ||
@@ -1158,13 +1211,18 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
break; break;
case '?': case '?':
case '/': case '/':
case '\023': /* C-s */ case 's'|KEYC_CTRL:
mtd->references++; mtd->references++;
status_prompt_set(c, NULL, "(search) ", "", status_prompt_set(c, NULL, "(search) ", "",
mode_tree_search_callback, mode_tree_search_free, mtd, mode_tree_search_callback, mode_tree_search_free, mtd,
PROMPT_NOFORMAT, PROMPT_TYPE_SEARCH); PROMPT_NOFORMAT, PROMPT_TYPE_SEARCH);
break; break;
case 'n': case 'n':
mtd->search_dir = MODE_TREE_SEARCH_FORWARD;
mode_tree_search_set(mtd);
break;
case 'N':
mtd->search_dir = MODE_TREE_SEARCH_BACKWARD;
mode_tree_search_set(mtd); mode_tree_search_set(mtd);
break; break;
case 'f': case 'f':

View File

@@ -93,6 +93,9 @@ static const char *options_table_detach_on_destroy_list[] = {
static const char *options_table_extended_keys_list[] = { static const char *options_table_extended_keys_list[] = {
"off", "on", "always", NULL "off", "on", "always", NULL
}; };
static const char *options_table_extended_keys_format_list[] = {
"csi-u", "xterm", NULL
};
static const char *options_table_allow_passthrough_list[] = { static const char *options_table_allow_passthrough_list[] = {
"off", "on", "all", NULL "off", "on", "all", NULL
}; };
@@ -285,7 +288,7 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_SERVER, .scope = OPTIONS_TABLE_SERVER,
.minimum = 0, .minimum = 0,
.maximum = INT_MAX, .maximum = INT_MAX,
.default_num = 500, .default_num = 10,
.unit = "milliseconds", .unit = "milliseconds",
.text = "Time to wait before assuming a key is Escape." .text = "Time to wait before assuming a key is Escape."
}, },
@@ -314,6 +317,14 @@ const struct options_table_entry options_table[] = {
"that support it." "that support it."
}, },
{ .name = "extended-keys-format",
.type = OPTIONS_TABLE_CHOICE,
.scope = OPTIONS_TABLE_SERVER,
.choices = options_table_extended_keys_format_list,
.default_num = 1,
.text = "The format of emitted extended key sequences."
},
{ .name = "focus-events", { .name = "focus-events",
.type = OPTIONS_TABLE_FLAG, .type = OPTIONS_TABLE_FLAG,
.scope = OPTIONS_TABLE_SERVER, .scope = OPTIONS_TABLE_SERVER,
@@ -374,6 +385,17 @@ const struct options_table_entry options_table[] = {
.text = "Maximum number of server messages to keep." .text = "Maximum number of server messages to keep."
}, },
{ .name = "prefix-timeout",
.type = OPTIONS_TABLE_NUMBER,
.scope = OPTIONS_TABLE_SERVER,
.minimum = 0,
.maximum = INT_MAX,
.default_num = 0,
.unit = "milliseconds",
.text = "The timeout for the prefix key if no subsequent key is "
"pressed. Zero means disabled."
},
{ .name = "prompt-history-limit", { .name = "prompt-history-limit",
.type = OPTIONS_TABLE_NUMBER, .type = OPTIONS_TABLE_NUMBER,
.scope = OPTIONS_TABLE_SERVER, .scope = OPTIONS_TABLE_SERVER,
@@ -397,7 +419,7 @@ const struct options_table_entry options_table[] = {
.type = OPTIONS_TABLE_STRING, .type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER, .scope = OPTIONS_TABLE_SERVER,
.flags = OPTIONS_TABLE_IS_ARRAY, .flags = OPTIONS_TABLE_IS_ARRAY,
.default_str = "", .default_str = "linux*:AX@",
.separator = ",", .separator = ",",
.text = "List of terminal capabilities overrides." .text = "List of terminal capabilities overrides."
}, },
@@ -613,7 +635,7 @@ const struct options_table_entry options_table[] = {
{ .name = "prefix", { .name = "prefix",
.type = OPTIONS_TABLE_KEY, .type = OPTIONS_TABLE_KEY,
.scope = OPTIONS_TABLE_SESSION, .scope = OPTIONS_TABLE_SESSION,
.default_num = '\002', .default_num = 'b'|KEYC_CTRL,
.text = "The prefix key." .text = "The prefix key."
}, },
@@ -875,6 +897,14 @@ const struct options_table_entry options_table[] = {
"to rename windows." "to rename windows."
}, },
{ .name = "allow-set-title",
.type = OPTIONS_TABLE_FLAG,
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
.default_num = 1,
.text = "Whether applications are allowed to use the escape sequence "
"to set the pane title."
},
{ .name = "alternate-screen", { .name = "alternate-screen",
.type = OPTIONS_TABLE_FLAG, .type = OPTIONS_TABLE_FLAG,
.scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE, .scope = OPTIONS_TABLE_WINDOW|OPTIONS_TABLE_PANE,
@@ -1317,6 +1347,7 @@ const struct options_table_entry options_table[] = {
OPTIONS_TABLE_HOOK("client-focus-out", ""), OPTIONS_TABLE_HOOK("client-focus-out", ""),
OPTIONS_TABLE_HOOK("client-resized", ""), OPTIONS_TABLE_HOOK("client-resized", ""),
OPTIONS_TABLE_HOOK("client-session-changed", ""), OPTIONS_TABLE_HOOK("client-session-changed", ""),
OPTIONS_TABLE_HOOK("command-error", ""),
OPTIONS_TABLE_PANE_HOOK("pane-died", ""), OPTIONS_TABLE_PANE_HOOK("pane-died", ""),
OPTIONS_TABLE_PANE_HOOK("pane-exited", ""), OPTIONS_TABLE_PANE_HOOK("pane-exited", ""),
OPTIONS_TABLE_PANE_HOOK("pane-focus-in", ""), OPTIONS_TABLE_PANE_HOOK("pane-focus-in", ""),

View File

@@ -578,10 +578,28 @@ char *
options_to_string(struct options_entry *o, int idx, int numeric) options_to_string(struct options_entry *o, int idx, int numeric)
{ {
struct options_array_item *a; struct options_array_item *a;
char *result = NULL;
char *last = NULL;
char *next;
if (OPTIONS_IS_ARRAY(o)) { if (OPTIONS_IS_ARRAY(o)) {
if (idx == -1) if (idx == -1) {
return (xstrdup("")); RB_FOREACH(a, options_array, &o->value.array) {
next = options_value_to_string(o, &a->value,
numeric);
if (last == NULL)
result = next;
else {
xasprintf(&result, "%s %s", last, next);
free(last);
free(next);
}
last = result;
}
if (result == NULL)
return (xstrdup(""));
return (result);
}
a = options_array_item(o, idx); a = options_array_item(o, idx);
if (a == NULL) if (a == NULL)
return (xstrdup("")); return (xstrdup(""));

View File

@@ -345,7 +345,7 @@ popup_make_pane(struct popup_data *pd, enum layout_type type)
u_int hlimit; u_int hlimit;
const char *shell; const char *shell;
window_unzoom(w); window_unzoom(w, 1);
lc = layout_split_pane(wp, type, -1, 0); lc = layout_split_pane(wp, type, -1, 0);
hlimit = options_get_number(s->options, "history-limit"); hlimit = options_get_number(s->options, "history-limit");
@@ -542,7 +542,7 @@ popup_key_cb(struct client *c, void *data, struct key_event *event)
} }
if ((((pd->flags & (POPUP_CLOSEEXIT|POPUP_CLOSEEXITZERO)) == 0) || if ((((pd->flags & (POPUP_CLOSEEXIT|POPUP_CLOSEEXITZERO)) == 0) ||
pd->job == NULL) && pd->job == NULL) &&
(event->key == '\033' || event->key == '\003')) (event->key == '\033' || event->key == ('c'|KEYC_CTRL)))
return (1); return (1);
if (pd->job != NULL) { if (pd->job != NULL) {
if (KEYC_IS_MOUSE(event->key)) { if (KEYC_IS_MOUSE(event->key)) {

View File

@@ -42,14 +42,14 @@ $TMUX send-keys -X begin-selection
$TMUX send-keys -X next-word-end $TMUX send-keys -X next-word-end
$TMUX send-keys -X next-word-end $TMUX send-keys -X next-word-end
$TMUX send-keys -X copy-selection $TMUX send-keys -X copy-selection
[ "$($TMUX show-buffer)" = "$(echo -e "words\n Indented")" ] || exit 1 [ "$($TMUX show-buffer)" = "$(printf "words\n Indented")" ] || exit 1
# Test that `next-word` wraps around un-indented line breaks. # Test that `next-word` wraps around un-indented line breaks.
$TMUX send-keys -X next-word $TMUX send-keys -X next-word
$TMUX send-keys -X begin-selection $TMUX send-keys -X begin-selection
$TMUX send-keys -X next-word $TMUX send-keys -X next-word
$TMUX send-keys -X copy-selection $TMUX send-keys -X copy-selection
[ "$($TMUX show-buffer)" = "$(echo -e "line\n")" ] || exit 1 [ "$($TMUX show-buffer)" = "$(printf "line\n")" ] || exit 1
# Test that `next-word-end` treats periods as letters. # Test that `next-word-end` treats periods as letters.
$TMUX send-keys -X next-word $TMUX send-keys -X next-word
@@ -63,14 +63,14 @@ $TMUX send-keys -X previous-word
$TMUX send-keys -X begin-selection $TMUX send-keys -X begin-selection
$TMUX send-keys -X next-word $TMUX send-keys -X next-word
$TMUX send-keys -X copy-selection $TMUX send-keys -X copy-selection
[ "$($TMUX show-buffer)" = "$(echo -e "line...\n")" ] || exit 1 [ "$($TMUX show-buffer)" = "$(printf "line...\n")" ] || exit 1
# Test that `previous-space` and `next-space` treat periods as letters. # Test that `previous-space` and `next-space` treat periods as letters.
$TMUX send-keys -X previous-space $TMUX send-keys -X previous-space
$TMUX send-keys -X begin-selection $TMUX send-keys -X begin-selection
$TMUX send-keys -X next-space $TMUX send-keys -X next-space
$TMUX send-keys -X copy-selection $TMUX send-keys -X copy-selection
[ "$($TMUX show-buffer)" = "$(echo -e "line...\n")" ] || exit 1 [ "$($TMUX show-buffer)" = "$(printf "line...\n")" ] || exit 1
# Test that `next-word` and `next-word-end` treat other symbols as letters. # Test that `next-word` and `next-word-end` treat other symbols as letters.
$TMUX send-keys -X begin-selection $TMUX send-keys -X begin-selection
@@ -87,7 +87,7 @@ $TMUX send-keys -X previous-word
$TMUX send-keys -X begin-selection $TMUX send-keys -X begin-selection
$TMUX send-keys -X next-word $TMUX send-keys -X next-word
$TMUX send-keys -X copy-selection $TMUX send-keys -X copy-selection
[ "$($TMUX show-buffer)" = "$(echo -e "\$ym_bols[]{}\n ")" ] || exit 1 [ "$($TMUX show-buffer)" = "$(printf "\$ym_bols[]{}\n ")" ] || exit 1
# Test that `next-word-end` treats digits as letters # Test that `next-word-end` treats digits as letters
$TMUX send-keys -X next-word-end $TMUX send-keys -X next-word-end

View File

@@ -41,14 +41,14 @@ $TMUX send-keys -X begin-selection
$TMUX send-keys -X next-word-end $TMUX send-keys -X next-word-end
$TMUX send-keys -X next-word-end $TMUX send-keys -X next-word-end
$TMUX send-keys -X copy-selection $TMUX send-keys -X copy-selection
[ "$($TMUX show-buffer)" = "$(echo -e "words\n Indented")" ] || exit 1 [ "$($TMUX show-buffer)" = "$(printf "words\n Indented")" ] || exit 1
# Test that `next-word` wraps around un-indented line breaks. # Test that `next-word` wraps around un-indented line breaks.
$TMUX send-keys -X next-word $TMUX send-keys -X next-word
$TMUX send-keys -X begin-selection $TMUX send-keys -X begin-selection
$TMUX send-keys -X next-word $TMUX send-keys -X next-word
$TMUX send-keys -X copy-selection $TMUX send-keys -X copy-selection
[ "$($TMUX show-buffer)" = "$(echo -e "line\nA")" ] || exit 1 [ "$($TMUX show-buffer)" = "$(printf "line\nA")" ] || exit 1
# Test that `next-word-end` does not treat periods as letters. # Test that `next-word-end` does not treat periods as letters.
$TMUX send-keys -X next-word $TMUX send-keys -X next-word
@@ -69,7 +69,7 @@ $TMUX send-keys -X previous-space
$TMUX send-keys -X begin-selection $TMUX send-keys -X begin-selection
$TMUX send-keys -X next-space $TMUX send-keys -X next-space
$TMUX send-keys -X copy-selection $TMUX send-keys -X copy-selection
[ "$($TMUX show-buffer)" = "$(echo -e "line...\n.")" ] || exit 1 [ "$($TMUX show-buffer)" = "$(printf "line...\n.")" ] || exit 1
# Test that `next-word` and `next-word-end` do not treat other symbols as letters. # Test that `next-word` and `next-word-end` do not treat other symbols as letters.
$TMUX send-keys -X begin-selection $TMUX send-keys -X begin-selection
@@ -85,7 +85,7 @@ $TMUX send-keys -X next-space
$TMUX send-keys -X begin-selection $TMUX send-keys -X begin-selection
$TMUX send-keys -X next-space $TMUX send-keys -X next-space
$TMUX send-keys -X copy-selection $TMUX send-keys -X copy-selection
[ "$($TMUX show-buffer)" = "$(echo -e "\$ym_bols[]{}\n ?")" ] || exit 1 [ "$($TMUX show-buffer)" = "$(printf "\$ym_bols[]{}\n ?")" ] || exit 1
# Test that `next-word-end` treats digits as letters # Test that `next-word-end` treats digits as letters
$TMUX send-keys -X next-word-end $TMUX send-keys -X next-word-end

View File

@@ -40,7 +40,7 @@ resize_window(struct window *w, u_int sx, u_int sy, int xpixel, int ypixel)
/* If the window is zoomed, unzoom. */ /* If the window is zoomed, unzoom. */
zoomed = w->flags & WINDOW_ZOOMED; zoomed = w->flags & WINDOW_ZOOMED;
if (zoomed) if (zoomed)
window_unzoom(w); window_unzoom(w, 1);
/* Resize the layout first. */ /* Resize the layout first. */
layout_resize(w, sx, sy); layout_resize(w, sx, sy);

View File

@@ -109,12 +109,13 @@ screen_redraw_two_panes(struct window *w, int direction)
/* Check if cell is on the border of a pane. */ /* Check if cell is on the border of a pane. */
static enum screen_redraw_border_type static enum screen_redraw_border_type
screen_redraw_pane_border(struct window_pane *wp, u_int px, u_int py, screen_redraw_pane_border(struct screen_redraw_ctx *ctx, struct window_pane *wp,
int pane_status) u_int px, u_int py)
{ {
struct options *oo = wp->window->options; struct options *oo = wp->window->options;
int split = 0; int split = 0;
u_int ex = wp->xoff + wp->sx, ey = wp->yoff + wp->sy; u_int ex = wp->xoff + wp->sx, ey = wp->yoff + wp->sy;
int pane_status = ctx->pane_status;
/* Inside pane. */ /* Inside pane. */
if (px >= wp->xoff && px < ex && py >= wp->yoff && py < ey) if (px >= wp->xoff && px < ex && py >= wp->yoff && py < ey)
@@ -189,8 +190,9 @@ screen_redraw_pane_border(struct window_pane *wp, u_int px, u_int py,
/* Check if a cell is on a border. */ /* Check if a cell is on a border. */
static int static int
screen_redraw_cell_border(struct client *c, u_int px, u_int py, int pane_status) screen_redraw_cell_border(struct screen_redraw_ctx *ctx, u_int px, u_int py)
{ {
struct client *c = ctx->c;
struct window *w = c->session->curw->window; struct window *w = c->session->curw->window;
struct window_pane *wp; struct window_pane *wp;
@@ -206,7 +208,7 @@ screen_redraw_cell_border(struct client *c, u_int px, u_int py, int pane_status)
TAILQ_FOREACH(wp, &w->panes, entry) { TAILQ_FOREACH(wp, &w->panes, entry) {
if (!window_pane_visible(wp)) if (!window_pane_visible(wp))
continue; continue;
switch (screen_redraw_pane_border(wp, px, py, pane_status)) { switch (screen_redraw_pane_border(ctx, wp, px, py)) {
case SCREEN_REDRAW_INSIDE: case SCREEN_REDRAW_INSIDE:
return (0); return (0);
case SCREEN_REDRAW_OUTSIDE: case SCREEN_REDRAW_OUTSIDE:
@@ -221,9 +223,10 @@ screen_redraw_cell_border(struct client *c, u_int px, u_int py, int pane_status)
/* Work out type of border cell from surrounding cells. */ /* Work out type of border cell from surrounding cells. */
static int static int
screen_redraw_type_of_cell(struct client *c, u_int px, u_int py, screen_redraw_type_of_cell(struct screen_redraw_ctx *ctx, u_int px, u_int py)
int pane_status)
{ {
struct client *c = ctx->c;
int pane_status = ctx->pane_status;
struct window *w = c->session->curw->window; struct window *w = c->session->curw->window;
u_int sx = w->sx, sy = w->sy; u_int sx = w->sx, sy = w->sy;
int borders = 0; int borders = 0;
@@ -236,28 +239,28 @@ screen_redraw_type_of_cell(struct client *c, u_int px, u_int py,
* Construct a bitmask of whether the cells to the left (bit 4), right, * Construct a bitmask of whether the cells to the left (bit 4), right,
* top, and bottom (bit 1) of this cell are borders. * top, and bottom (bit 1) of this cell are borders.
*/ */
if (px == 0 || screen_redraw_cell_border(c, px - 1, py, pane_status)) if (px == 0 || screen_redraw_cell_border(ctx, px - 1, py))
borders |= 8; borders |= 8;
if (px <= sx && screen_redraw_cell_border(c, px + 1, py, pane_status)) if (px <= sx && screen_redraw_cell_border(ctx, px + 1, py))
borders |= 4; borders |= 4;
if (pane_status == PANE_STATUS_TOP) { if (pane_status == PANE_STATUS_TOP) {
if (py != 0 && if (py != 0 &&
screen_redraw_cell_border(c, px, py - 1, pane_status)) screen_redraw_cell_border(ctx, px, py - 1))
borders |= 2; borders |= 2;
if (screen_redraw_cell_border(c, px, py + 1, pane_status)) if (screen_redraw_cell_border(ctx, px, py + 1))
borders |= 1; borders |= 1;
} else if (pane_status == PANE_STATUS_BOTTOM) { } else if (pane_status == PANE_STATUS_BOTTOM) {
if (py == 0 || if (py == 0 ||
screen_redraw_cell_border(c, px, py - 1, pane_status)) screen_redraw_cell_border(ctx, px, py - 1))
borders |= 2; borders |= 2;
if (py != sy - 1 && if (py != sy - 1 &&
screen_redraw_cell_border(c, px, py + 1, pane_status)) screen_redraw_cell_border(ctx, px, py + 1))
borders |= 1; borders |= 1;
} else { } else {
if (py == 0 || if (py == 0 ||
screen_redraw_cell_border(c, px, py - 1, pane_status)) screen_redraw_cell_border(ctx, px, py - 1))
borders |= 2; borders |= 2;
if (screen_redraw_cell_border(c, px, py + 1, pane_status)) if (screen_redraw_cell_border(ctx, px, py + 1))
borders |= 1; borders |= 1;
} }
@@ -295,11 +298,13 @@ screen_redraw_type_of_cell(struct client *c, u_int px, u_int py,
/* Check if cell inside a pane. */ /* Check if cell inside a pane. */
static int static int
screen_redraw_check_cell(struct client *c, u_int px, u_int py, int pane_status, screen_redraw_check_cell(struct screen_redraw_ctx *ctx, u_int px, u_int py,
struct window_pane **wpp) struct window_pane **wpp)
{ {
struct client *c = ctx->c;
struct window *w = c->session->curw->window; struct window *w = c->session->curw->window;
struct window_pane *wp, *active; struct window_pane *wp, *active;
int pane_status = ctx->pane_status;
int border; int border;
u_int right, line; u_int right, line;
@@ -308,7 +313,7 @@ screen_redraw_check_cell(struct client *c, u_int px, u_int py, int pane_status,
if (px > w->sx || py > w->sy) if (px > w->sx || py > w->sy)
return (CELL_OUTSIDE); return (CELL_OUTSIDE);
if (px == w->sx || py == w->sy) /* window border */ if (px == w->sx || py == w->sy) /* window border */
return (screen_redraw_type_of_cell(c, px, py, pane_status)); return (screen_redraw_type_of_cell(ctx, px, py));
if (pane_status != PANE_STATUS_OFF) { if (pane_status != PANE_STATUS_OFF) {
active = wp = server_client_get_pane(c); active = wp = server_client_get_pane(c);
@@ -342,12 +347,12 @@ screen_redraw_check_cell(struct client *c, u_int px, u_int py, int pane_status,
* If definitely inside, return. If not on border, skip. * If definitely inside, return. If not on border, skip.
* Otherwise work out the cell. * Otherwise work out the cell.
*/ */
border = screen_redraw_pane_border(wp, px, py, pane_status); border = screen_redraw_pane_border(ctx, wp, px, py);
if (border == SCREEN_REDRAW_INSIDE) if (border == SCREEN_REDRAW_INSIDE)
return (CELL_INSIDE); return (CELL_INSIDE);
if (border == SCREEN_REDRAW_OUTSIDE) if (border == SCREEN_REDRAW_OUTSIDE)
goto next2; goto next2;
return (screen_redraw_type_of_cell(c, px, py, pane_status)); return (screen_redraw_type_of_cell(ctx, px, py));
next2: next2:
wp = TAILQ_NEXT(wp, entry); wp = TAILQ_NEXT(wp, entry);
@@ -360,12 +365,12 @@ screen_redraw_check_cell(struct client *c, u_int px, u_int py, int pane_status,
/* Check if the border of a particular pane. */ /* Check if the border of a particular pane. */
static int static int
screen_redraw_check_is(u_int px, u_int py, int pane_status, screen_redraw_check_is(struct screen_redraw_ctx *ctx, u_int px, u_int py,
struct window_pane *wp) struct window_pane *wp)
{ {
enum screen_redraw_border_type border; enum screen_redraw_border_type border;
border = screen_redraw_pane_border(wp, px, py, pane_status); border = screen_redraw_pane_border(ctx, wp, px, py);
if (border != SCREEN_REDRAW_INSIDE && border != SCREEN_REDRAW_OUTSIDE) if (border != SCREEN_REDRAW_INSIDE && border != SCREEN_REDRAW_OUTSIDE)
return (1); return (1);
return (0); return (0);
@@ -409,11 +414,11 @@ screen_redraw_make_pane_status(struct client *c, struct window_pane *wp,
for (i = 0; i < width; i++) { for (i = 0; i < width; i++) {
px = wp->xoff + 2 + i; px = wp->xoff + 2 + i;
if (rctx->pane_status == PANE_STATUS_TOP) if (pane_status == PANE_STATUS_TOP)
py = wp->yoff - 1; py = wp->yoff - 1;
else else
py = wp->yoff + wp->sy; py = wp->yoff + wp->sy;
cell_type = screen_redraw_type_of_cell(c, px, py, pane_status); cell_type = screen_redraw_type_of_cell(rctx, px, py);
screen_redraw_border_set(w, wp, pane_lines, cell_type, &gc); screen_redraw_border_set(w, wp, pane_lines, cell_type, &gc);
screen_write_cell(&ctx, &gc); screen_write_cell(&ctx, &gc);
} }
@@ -496,8 +501,8 @@ screen_redraw_draw_pane_status(struct screen_redraw_ctx *ctx)
} }
/* Update status line and change flags if unchanged. */ /* Update status line and change flags if unchanged. */
static int static uint64_t
screen_redraw_update(struct client *c, int flags) screen_redraw_update(struct client *c, uint64_t flags)
{ {
struct window *w = c->session->curw->window; struct window *w = c->session->curw->window;
struct window_pane *wp; struct window_pane *wp;
@@ -567,7 +572,7 @@ void
screen_redraw_screen(struct client *c) screen_redraw_screen(struct client *c)
{ {
struct screen_redraw_ctx ctx; struct screen_redraw_ctx ctx;
int flags; uint64_t flags;
if (c->flags & CLIENT_SUSPENDED) if (c->flags & CLIENT_SUSPENDED)
return; return;
@@ -638,7 +643,7 @@ screen_redraw_draw_borders_style(struct screen_redraw_ctx *ctx, u_int x,
wp->border_gc_set = 1; wp->border_gc_set = 1;
ft = format_create_defaults(NULL, c, s, s->curw, wp); ft = format_create_defaults(NULL, c, s, s->curw, wp);
if (screen_redraw_check_is(x, y, ctx->pane_status, active)) if (screen_redraw_check_is(ctx, x, y, active))
style_apply(&wp->border_gc, oo, "pane-active-border-style", ft); style_apply(&wp->border_gc, oo, "pane-active-border-style", ft);
else else
style_apply(&wp->border_gc, oo, "pane-border-style", ft); style_apply(&wp->border_gc, oo, "pane-border-style", ft);
@@ -663,7 +668,7 @@ screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int i, u_int j)
struct overlay_ranges r; struct overlay_ranges r;
u_int cell_type, x = ctx->ox + i, y = ctx->oy + j; u_int cell_type, x = ctx->ox + i, y = ctx->oy + j;
int arrows = 0, border; int arrows = 0, border;
int pane_status = ctx->pane_status, isolates; int isolates;
if (c->overlay_check != NULL) { if (c->overlay_check != NULL) {
c->overlay_check(c, c->overlay_data, x, y, 1, &r); c->overlay_check(c, c->overlay_data, x, y, 1, &r);
@@ -671,7 +676,7 @@ screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int i, u_int j)
return; return;
} }
cell_type = screen_redraw_check_cell(c, x, y, pane_status, &wp); cell_type = screen_redraw_check_cell(ctx, x, y, &wp);
if (cell_type == CELL_INSIDE) if (cell_type == CELL_INSIDE)
return; return;
@@ -692,7 +697,7 @@ screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int i, u_int j)
memcpy(&gc, tmp, sizeof gc); memcpy(&gc, tmp, sizeof gc);
if (server_is_marked(s, s->curw, marked_pane.wp) && if (server_is_marked(s, s->curw, marked_pane.wp) &&
screen_redraw_check_is(x, y, pane_status, marked_pane.wp)) screen_redraw_check_is(ctx, x, y, marked_pane.wp))
gc.attr ^= GRID_ATTR_REVERSE; gc.attr ^= GRID_ATTR_REVERSE;
} }
screen_redraw_border_set(w, wp, ctx->pane_lines, cell_type, &gc); screen_redraw_border_set(w, wp, ctx->pane_lines, cell_type, &gc);
@@ -719,7 +724,7 @@ screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int i, u_int j)
} }
if (wp != NULL && arrows) { if (wp != NULL && arrows) {
border = screen_redraw_pane_border(active, x, y, pane_status); border = screen_redraw_pane_border(ctx, active, x, y);
if (((i == wp->xoff + 1 && if (((i == wp->xoff + 1 &&
(cell_type == CELL_LEFTRIGHT || (cell_type == CELL_LEFTRIGHT ||
(cell_type == CELL_TOPJOIN && (cell_type == CELL_TOPJOIN &&
@@ -732,7 +737,7 @@ screen_redraw_draw_borders_cell(struct screen_redraw_ctx *ctx, u_int i, u_int j)
border == SCREEN_REDRAW_BORDER_RIGHT) || border == SCREEN_REDRAW_BORDER_RIGHT) ||
(cell_type == CELL_RIGHTJOIN && (cell_type == CELL_RIGHTJOIN &&
border == SCREEN_REDRAW_BORDER_LEFT)))) && border == SCREEN_REDRAW_BORDER_LEFT)))) &&
screen_redraw_check_is(x, y, pane_status, active)) { screen_redraw_check_is(ctx, x, y, active)) {
gc.attr |= GRID_ATTR_CHARSET; gc.attr |= GRID_ATTR_CHARSET;
utf8_set(&gc.data, BORDER_MARKERS[border]); utf8_set(&gc.data, BORDER_MARKERS[border]);
} }
@@ -751,7 +756,7 @@ screen_redraw_draw_borders(struct screen_redraw_ctx *ctx)
struct session *s = c->session; struct session *s = c->session;
struct window *w = s->curw->window; struct window *w = s->curw->window;
struct window_pane *wp; struct window_pane *wp;
u_int i, j; u_int i, j;
log_debug("%s: %s @%u", __func__, c->name, w->id); log_debug("%s: %s @%u", __func__, c->name, w->id);

View File

@@ -326,8 +326,9 @@ screen_write_reset(struct screen_write_ctx *ctx)
screen_write_scrollregion(ctx, 0, screen_size_y(s) - 1); screen_write_scrollregion(ctx, 0, screen_size_y(s) - 1);
s->mode = MODE_CURSOR|MODE_WRAP; s->mode = MODE_CURSOR|MODE_WRAP;
if (options_get_number(global_options, "extended-keys") == 2) if (options_get_number(global_options, "extended-keys") == 2)
s->mode |= MODE_KEXTENDED; s->mode = (s->mode & ~EXTENDED_KEY_MODES)|MODE_KEYS_EXTENDED;
screen_write_clearscreen(ctx, 8); screen_write_clearscreen(ctx, 8);
screen_write_set_cursor(ctx, 0, 0); screen_write_set_cursor(ctx, 0, 0);
@@ -2148,7 +2149,7 @@ screen_write_combine(struct screen_write_ctx *ctx, const struct grid_cell *gc)
/* Set the new cell. */ /* Set the new cell. */
grid_view_set_cell(gd, cx - n, cy, &last); grid_view_set_cell(gd, cx - n, cy, &last);
if (force_wide) if (force_wide)
grid_view_set_padding(gd, cx, cy); grid_view_set_padding(gd, cx - 1, cy);
/* /*
* Redraw the combined cell. If forcing the cell to width 2, reset the * Redraw the combined cell. If forcing the cell to width 2, reset the
@@ -2283,6 +2284,10 @@ screen_write_sixelimage(struct screen_write_ctx *ctx, struct sixel_image *si,
new = sixel_scale(si, 0, 0, 0, y - sy, sx, sy, 1); new = sixel_scale(si, 0, 0, 0, y - sy, sx, sy, 1);
sixel_free(si); sixel_free(si);
si = new; si = new;
/* Bail out if the image cannot be scaled. */
if (si == NULL)
return;
sixel_size_in_cells(si, &x, &y); sixel_size_in_cells(si, &x, &y);
} }

View File

@@ -110,8 +110,9 @@ screen_reinit(struct screen *s)
s->rlower = screen_size_y(s) - 1; s->rlower = screen_size_y(s) - 1;
s->mode = MODE_CURSOR|MODE_WRAP|(s->mode & MODE_CRLF); s->mode = MODE_CURSOR|MODE_WRAP|(s->mode & MODE_CRLF);
if (options_get_number(global_options, "extended-keys") == 2) if (options_get_number(global_options, "extended-keys") == 2)
s->mode |= MODE_KEXTENDED; s->mode = (s->mode & ~EXTENDED_KEY_MODES)|MODE_KEYS_EXTENDED;
if (s->saved_grid != NULL) if (s->saved_grid != NULL)
screen_alternate_off(s, NULL, 0); screen_alternate_off(s, NULL, 0);
@@ -308,12 +309,12 @@ screen_resize_cursor(struct screen *s, u_int sx, u_int sy, int reflow,
if (sy != screen_size_y(s)) if (sy != screen_size_y(s))
screen_resize_y(s, sy, eat_empty, &cy); screen_resize_y(s, sy, eat_empty, &cy);
if (reflow) {
#ifdef ENABLE_SIXEL #ifdef ENABLE_SIXEL
image_free_all(s); image_free_all(s);
#endif #endif
if (reflow)
screen_reflow(s, sx, &cx, &cy, cursor); screen_reflow(s, sx, &cx, &cy, cursor);
}
if (cy >= s->grid->hsize) { if (cy >= s->grid->hsize) {
s->cx = cx; s->cx = cx;
@@ -400,7 +401,7 @@ screen_resize_y(struct screen *s, u_int sy, int eat_empty, u_int *cy)
/* /*
* Try to pull as much as possible out of scrolled history, if * Try to pull as much as possible out of scrolled history, if
* is is enabled. * it is enabled.
*/ */
available = gd->hscrolled; available = gd->hscrolled;
if (gd->flags & GRID_HISTORY && available > 0) { if (gd->flags & GRID_HISTORY && available > 0) {
@@ -730,8 +731,10 @@ screen_mode_to_string(int mode)
strlcat(tmp, "ORIGIN,", sizeof tmp); strlcat(tmp, "ORIGIN,", sizeof tmp);
if (mode & MODE_CRLF) if (mode & MODE_CRLF)
strlcat(tmp, "CRLF,", sizeof tmp); strlcat(tmp, "CRLF,", sizeof tmp);
if (mode & MODE_KEXTENDED) if (mode & MODE_KEYS_EXTENDED)
strlcat(tmp, "KEXTENDED,", sizeof tmp); strlcat(tmp, "KEYS_EXTENDED,", sizeof tmp);
if (mode & MODE_KEYS_EXTENDED_2)
strlcat(tmp, "KEYS_EXTENDED_2,", sizeof tmp);
tmp[strlen(tmp) - 1] = '\0'; tmp[strlen(tmp) - 1] = '\0';
return (tmp); return (tmp);
} }

View File

@@ -222,6 +222,17 @@ server_client_set_key_table(struct client *c, const char *name)
key_bindings_unref_table(c->keytable); key_bindings_unref_table(c->keytable);
c->keytable = key_bindings_get_table(name, 1); c->keytable = key_bindings_get_table(name, 1);
c->keytable->references++; c->keytable->references++;
if (gettimeofday(&c->keytable->activity_time, NULL) != 0)
fatal("gettimeofday failed");
}
static uint64_t
server_client_key_table_activity_diff(struct client *c)
{
struct timeval diff;
timersub(&c->activity_time, &c->keytable->activity_time, &diff);
return ((diff.tv_sec * 1000ULL) + (diff.tv_usec / 1000ULL));
} }
/* Get default key table. */ /* Get default key table. */
@@ -622,6 +633,8 @@ server_client_check_mouse(struct client *c, struct key_event *event)
} else if (MOUSE_RELEASE(m->b)) { } else if (MOUSE_RELEASE(m->b)) {
type = UP; type = UP;
x = m->x, y = m->y, b = m->lb; x = m->x, y = m->y, b = m->lb;
if (m->sgr_type == 'm')
b = m->sgr_b;
log_debug("up at %u,%u", x, y); log_debug("up at %u,%u", x, y);
} else { } else {
if (c->flags & CLIENT_DOUBLECLICK) { if (c->flags & CLIENT_DOUBLECLICK) {
@@ -642,7 +655,10 @@ server_client_check_mouse(struct client *c, struct key_event *event)
log_debug("triple-click at %u,%u", x, y); log_debug("triple-click at %u,%u", x, y);
goto have_event; goto have_event;
} }
} else { }
/* DOWN is the only remaining event type. */
if (type == NOTYPE) {
type = DOWN; type = DOWN;
x = m->x, y = m->y, b = m->b; x = m->x, y = m->y, b = m->b;
log_debug("down at %u,%u", x, y); log_debug("down at %u,%u", x, y);
@@ -774,8 +790,7 @@ have_event:
log_debug("mouse on pane %%%u border", wp->id); log_debug("mouse on pane %%%u border", wp->id);
m->wp = wp->id; m->wp = wp->id;
m->w = wp->window->id; m->w = wp->window->id;
} else }
m->wp = -1;
/* Stop dragging if needed. */ /* Stop dragging if needed. */
if (type != DRAG && type != WHEEL && c->tty.mouse_drag_flag != 0) { if (type != DRAG && type != WHEEL && c->tty.mouse_drag_flag != 0) {
@@ -1861,7 +1876,8 @@ server_client_key_callback(struct cmdq_item *item, void *data)
struct timeval tv; struct timeval tv;
struct key_table *table, *first; struct key_table *table, *first;
struct key_binding *bd; struct key_binding *bd;
int xtimeout, flags; int xtimeout;
uint64_t flags, prefix_delay;
struct cmd_find_state fs; struct cmd_find_state fs;
key_code key0, prefix, prefix2; key_code key0, prefix, prefix2;
@@ -1956,8 +1972,34 @@ try_again:
if (c->flags & CLIENT_REPEAT) if (c->flags & CLIENT_REPEAT)
log_debug("currently repeating"); log_debug("currently repeating");
/* Try to see if there is a key binding in the current table. */
bd = key_bindings_get(table, key0); bd = key_bindings_get(table, key0);
/*
* If prefix-timeout is enabled and we're in the prefix table, see if
* the timeout has been exceeded. Revert to the root table if so.
*/
prefix_delay = options_get_number(global_options, "prefix-timeout");
if (prefix_delay > 0 &&
strcmp(table->name, "prefix") == 0 &&
server_client_key_table_activity_diff(c) > prefix_delay) {
/*
* If repeating is active and this is a repeating binding,
* ignore the timeout.
*/
if (bd != NULL &&
(c->flags & CLIENT_REPEAT) &&
(bd->flags & KEY_BINDING_REPEAT)) {
log_debug("prefix timeout ignored, repeat is active");
} else {
log_debug("prefix timeout exceeded");
server_client_set_key_table(c, NULL);
first = table = c->keytable;
server_status_client(c);
goto table_changed;
}
}
/* Try to see if there is a key binding in the current table. */
if (bd != NULL) { if (bd != NULL) {
/* /*
* Key was matched in this table. If currently repeating but a * Key was matched in this table. If currently repeating but a
@@ -2015,7 +2057,19 @@ try_again:
} }
/* /*
* No match in this table. If not in the root table or if repeating, * Binding movement keys is useless since we only turn them on when the
* application requests, so don't let them exit the prefix table.
*/
if (key == KEYC_MOUSEMOVE_PANE ||
key == KEYC_MOUSEMOVE_STATUS ||
key == KEYC_MOUSEMOVE_STATUS_LEFT ||
key == KEYC_MOUSEMOVE_STATUS_RIGHT ||
key == KEYC_MOUSEMOVE_STATUS_DEFAULT ||
key == KEYC_MOUSEMOVE_BORDER)
goto forward_key;
/*
* No match in this table. If not in the root table or if repeating
* switch the client back to the root table and try again. * switch the client back to the root table and try again.
*/ */
log_debug("not found in key table %s", table->name); log_debug("not found in key table %s", table->name);
@@ -2560,7 +2614,8 @@ server_client_check_redraw(struct client *c)
struct tty *tty = &c->tty; struct tty *tty = &c->tty;
struct window *w = c->session->curw->window; struct window *w = c->session->curw->window;
struct window_pane *wp; struct window_pane *wp;
int needed, flags, mode = tty->mode, new_flags = 0; int needed, tty_flags, mode = tty->mode;
uint64_t client_flags = 0;
int redraw; int redraw;
u_int bit = 0; u_int bit = 0;
struct timeval tv = { .tv_usec = 1000 }; struct timeval tv = { .tv_usec = 1000 };
@@ -2594,7 +2649,7 @@ server_client_check_redraw(struct client *c)
} }
} }
if (needed) if (needed)
new_flags |= CLIENT_REDRAWPANES; client_flags |= CLIENT_REDRAWPANES;
} }
if (needed && (left = EVBUFFER_LENGTH(tty->out)) != 0) { if (needed && (left = EVBUFFER_LENGTH(tty->out)) != 0) {
log_debug("%s: redraw deferred (%zu left)", c->name, left); log_debug("%s: redraw deferred (%zu left)", c->name, left);
@@ -2617,20 +2672,20 @@ server_client_check_redraw(struct client *c)
* If more that 64 panes, give up and * If more that 64 panes, give up and
* just redraw the window. * just redraw the window.
*/ */
new_flags &= CLIENT_REDRAWPANES; client_flags &= CLIENT_REDRAWPANES;
new_flags |= CLIENT_REDRAWWINDOW; client_flags |= CLIENT_REDRAWWINDOW;
break; break;
} }
} }
if (c->redraw_panes != 0) if (c->redraw_panes != 0)
c->flags |= CLIENT_REDRAWPANES; c->flags |= CLIENT_REDRAWPANES;
} }
c->flags |= new_flags; c->flags |= client_flags;
return; return;
} else if (needed) } else if (needed)
log_debug("%s: redraw needed", c->name); log_debug("%s: redraw needed", c->name);
flags = tty->flags & (TTY_BLOCK|TTY_FREEZE|TTY_NOCURSOR); tty_flags = tty->flags & (TTY_BLOCK|TTY_FREEZE|TTY_NOCURSOR);
tty->flags = (tty->flags & ~(TTY_BLOCK|TTY_FREEZE))|TTY_NOCURSOR; tty->flags = (tty->flags & ~(TTY_BLOCK|TTY_FREEZE))|TTY_NOCURSOR;
if (~c->flags & CLIENT_REDRAWWINDOW) { if (~c->flags & CLIENT_REDRAWWINDOW) {
@@ -2662,9 +2717,10 @@ server_client_check_redraw(struct client *c)
screen_redraw_screen(c); screen_redraw_screen(c);
} }
tty->flags = (tty->flags & ~TTY_NOCURSOR)|(flags & TTY_NOCURSOR); tty->flags = (tty->flags & ~TTY_NOCURSOR)|(tty_flags & TTY_NOCURSOR);
tty_update_mode(tty, mode, NULL); tty_update_mode(tty, mode, NULL);
tty->flags = (tty->flags & ~(TTY_BLOCK|TTY_FREEZE|TTY_NOCURSOR))|flags; tty->flags = (tty->flags & ~(TTY_BLOCK|TTY_FREEZE|TTY_NOCURSOR))|
tty_flags;
c->flags &= ~(CLIENT_ALLREDRAWFLAGS|CLIENT_STATUSFORCE); c->flags &= ~(CLIENT_ALLREDRAWFLAGS|CLIENT_STATUSFORCE);

View File

@@ -411,7 +411,7 @@ server_find_session(struct session *s,
static int static int
server_newer_session(struct session *s_loop, struct session *s_out) server_newer_session(struct session *s_loop, struct session *s_out)
{ {
return (timercmp(&s_loop->activity_time, &s_out->activity_time, <)); return (timercmp(&s_loop->activity_time, &s_out->activity_time, >));
} }
static int static int
@@ -488,6 +488,6 @@ server_check_unattached(void)
void void
server_unzoom_window(struct window *w) server_unzoom_window(struct window *w)
{ {
if (window_unzoom(w) == 0) if (window_unzoom(w, 1) == 0)
server_redraw_window(w); server_redraw_window(w);
} }

View File

@@ -103,7 +103,7 @@ server_check_marked(void)
/* Create server socket. */ /* Create server socket. */
int int
server_create_socket(int flags, char **cause) server_create_socket(uint64_t flags, char **cause)
{ {
struct sockaddr_un sa; struct sockaddr_un sa;
size_t size; size_t size;
@@ -172,7 +172,7 @@ server_tidy_event(__unused int fd, __unused short events, __unused void *data)
/* Fork new server. */ /* Fork new server. */
int int
server_start(struct tmuxproc *client, int flags, struct event_base *base, server_start(struct tmuxproc *client, uint64_t flags, struct event_base *base,
int lockfd, char *lockfile) int lockfd, char *lockfile)
{ {
int fd; int fd;
@@ -264,7 +264,7 @@ server_loop(void)
struct client *c; struct client *c;
u_int items; u_int items;
current_time = time (NULL); current_time = time(NULL);
do { do {
items = cmdq_next(NULL); items = cmdq_next(NULL);

119
status.c
View File

@@ -607,6 +607,8 @@ status_prompt_set(struct client *c, struct cmd_find_state *fs,
struct format_tree *ft; struct format_tree *ft;
char *tmp; char *tmp;
server_client_clear_overlay(c);
if (fs != NULL) if (fs != NULL)
ft = format_create_from_state(NULL, c, fs); ft = format_create_from_state(NULL, c, fs);
else else
@@ -839,19 +841,19 @@ status_prompt_translate_key(struct client *c, key_code key, key_code *new_key)
{ {
if (c->prompt_mode == PROMPT_ENTRY) { if (c->prompt_mode == PROMPT_ENTRY) {
switch (key) { switch (key) {
case '\001': /* C-a */ case 'a'|KEYC_CTRL:
case '\003': /* C-c */ case 'c'|KEYC_CTRL:
case '\005': /* C-e */ case 'e'|KEYC_CTRL:
case '\007': /* C-g */ case 'g'|KEYC_CTRL:
case '\010': /* C-h */ case 'h'|KEYC_CTRL:
case '\011': /* Tab */ case '\011': /* Tab */
case '\013': /* C-k */ case 'k'|KEYC_CTRL:
case '\016': /* C-n */ case 'n'|KEYC_CTRL:
case '\020': /* C-p */ case 'p'|KEYC_CTRL:
case '\024': /* C-t */ case 't'|KEYC_CTRL:
case '\025': /* C-u */ case 'u'|KEYC_CTRL:
case '\027': /* C-w */ case 'w'|KEYC_CTRL:
case '\031': /* C-y */ case 'y'|KEYC_CTRL:
case '\n': case '\n':
case '\r': case '\r':
case KEYC_LEFT|KEYC_CTRL: case KEYC_LEFT|KEYC_CTRL:
@@ -890,7 +892,7 @@ status_prompt_translate_key(struct client *c, key_code key, key_code *new_key)
case 'S': case 'S':
c->prompt_mode = PROMPT_ENTRY; c->prompt_mode = PROMPT_ENTRY;
c->flags |= CLIENT_REDRAWSTATUS; c->flags |= CLIENT_REDRAWSTATUS;
*new_key = '\025'; /* C-u */ *new_key = 'u'|KEYC_CTRL;
return (1); return (1);
case 'i': case 'i':
case '\033': /* Escape */ case '\033': /* Escape */
@@ -911,7 +913,7 @@ status_prompt_translate_key(struct client *c, key_code key, key_code *new_key)
return (1); return (1);
case 'C': case 'C':
case 'D': case 'D':
*new_key = '\013'; /* C-k */ *new_key = 'k'|KEYC_CTRL;
return (1); return (1);
case KEYC_BSPACE: case KEYC_BSPACE:
case 'X': case 'X':
@@ -924,7 +926,7 @@ status_prompt_translate_key(struct client *c, key_code key, key_code *new_key)
*new_key = 'B'|KEYC_VI; *new_key = 'B'|KEYC_VI;
return (1); return (1);
case 'd': case 'd':
*new_key = '\025'; /* C-u */ *new_key = 'u'|KEYC_CTRL;
return (1); return (1);
case 'e': case 'e':
*new_key = 'e'|KEYC_VI; *new_key = 'e'|KEYC_VI;
@@ -939,10 +941,10 @@ status_prompt_translate_key(struct client *c, key_code key, key_code *new_key)
*new_key = 'W'|KEYC_VI; *new_key = 'W'|KEYC_VI;
return (1); return (1);
case 'p': case 'p':
*new_key = '\031'; /* C-y */ *new_key = 'y'|KEYC_CTRL;
return (1); return (1);
case 'q': case 'q':
*new_key = '\003'; /* C-c */ *new_key = 'c'|KEYC_CTRL;
return (1); return (1);
case 's': case 's':
case KEYC_DC: case KEYC_DC:
@@ -966,8 +968,8 @@ status_prompt_translate_key(struct client *c, key_code key, key_code *new_key)
case 'k': case 'k':
*new_key = KEYC_UP; *new_key = KEYC_UP;
return (1); return (1);
case '\010' /* C-h */: case 'h'|KEYC_CTRL:
case '\003' /* C-c */: case 'c'|KEYC_CTRL:
case '\n': case '\n':
case '\r': case '\r':
return (1); return (1);
@@ -994,8 +996,7 @@ status_prompt_paste(struct client *c)
if ((pb = paste_get_top(NULL)) == NULL) if ((pb = paste_get_top(NULL)) == NULL)
return (0); return (0);
bufdata = paste_buffer_data(pb, &bufsize); bufdata = paste_buffer_data(pb, &bufsize);
ud = xreallocarray(NULL, bufsize + 1, sizeof *ud); ud = udp = xreallocarray(NULL, bufsize + 1, sizeof *ud);
udp = ud;
for (i = 0; i != bufsize; /* nothing */) { for (i = 0; i != bufsize; /* nothing */) {
more = utf8_open(udp, bufdata[i]); more = utf8_open(udp, bufdata[i]);
if (more == UTF8_MORE) { if (more == UTF8_MORE) {
@@ -1016,25 +1017,24 @@ status_prompt_paste(struct client *c)
udp->size = 0; udp->size = 0;
n = udp - ud; n = udp - ud;
} }
if (n == 0) if (n != 0) {
return (0); c->prompt_buffer = xreallocarray(c->prompt_buffer, size + n + 1,
sizeof *c->prompt_buffer);
c->prompt_buffer = xreallocarray(c->prompt_buffer, size + n + 1, if (c->prompt_index == size) {
sizeof *c->prompt_buffer); memcpy(c->prompt_buffer + c->prompt_index, ud,
if (c->prompt_index == size) { n * sizeof *c->prompt_buffer);
memcpy(c->prompt_buffer + c->prompt_index, ud, c->prompt_index += n;
n * sizeof *c->prompt_buffer); c->prompt_buffer[c->prompt_index].size = 0;
c->prompt_index += n; } else {
c->prompt_buffer[c->prompt_index].size = 0; memmove(c->prompt_buffer + c->prompt_index + n,
} else { c->prompt_buffer + c->prompt_index,
memmove(c->prompt_buffer + c->prompt_index + n, (size + 1 - c->prompt_index) *
c->prompt_buffer + c->prompt_index, sizeof *c->prompt_buffer);
(size + 1 - c->prompt_index) * sizeof *c->prompt_buffer); memcpy(c->prompt_buffer + c->prompt_index, ud,
memcpy(c->prompt_buffer + c->prompt_index, ud, n * sizeof *c->prompt_buffer);
n * sizeof *c->prompt_buffer); c->prompt_index += n;
c->prompt_index += n; }
} }
if (ud != c->prompt_saved) if (ud != c->prompt_saved)
free(ud); free(ud);
return (1); return (1);
@@ -1265,28 +1265,28 @@ status_prompt_key(struct client *c, key_code key)
process_key: process_key:
switch (key) { switch (key) {
case KEYC_LEFT: case KEYC_LEFT:
case '\002': /* C-b */ case 'b'|KEYC_CTRL:
if (c->prompt_index > 0) { if (c->prompt_index > 0) {
c->prompt_index--; c->prompt_index--;
break; break;
} }
break; break;
case KEYC_RIGHT: case KEYC_RIGHT:
case '\006': /* C-f */ case 'f'|KEYC_CTRL:
if (c->prompt_index < size) { if (c->prompt_index < size) {
c->prompt_index++; c->prompt_index++;
break; break;
} }
break; break;
case KEYC_HOME: case KEYC_HOME:
case '\001': /* C-a */ case 'a'|KEYC_CTRL:
if (c->prompt_index != 0) { if (c->prompt_index != 0) {
c->prompt_index = 0; c->prompt_index = 0;
break; break;
} }
break; break;
case KEYC_END: case KEYC_END:
case '\005': /* C-e */ case 'e'|KEYC_CTRL:
if (c->prompt_index != size) { if (c->prompt_index != size) {
c->prompt_index = size; c->prompt_index = size;
break; break;
@@ -1297,7 +1297,7 @@ process_key:
goto changed; goto changed;
break; break;
case KEYC_BSPACE: case KEYC_BSPACE:
case '\010': /* C-h */ case 'h'|KEYC_CTRL:
if (c->prompt_index != 0) { if (c->prompt_index != 0) {
if (c->prompt_index == size) if (c->prompt_index == size)
c->prompt_buffer[--c->prompt_index].size = 0; c->prompt_buffer[--c->prompt_index].size = 0;
@@ -1312,7 +1312,7 @@ process_key:
} }
break; break;
case KEYC_DC: case KEYC_DC:
case '\004': /* C-d */ case 'd'|KEYC_CTRL:
if (c->prompt_index != size) { if (c->prompt_index != size) {
memmove(c->prompt_buffer + c->prompt_index, memmove(c->prompt_buffer + c->prompt_index,
c->prompt_buffer + c->prompt_index + 1, c->prompt_buffer + c->prompt_index + 1,
@@ -1321,17 +1321,17 @@ process_key:
goto changed; goto changed;
} }
break; break;
case '\025': /* C-u */ case 'u'|KEYC_CTRL:
c->prompt_buffer[0].size = 0; c->prompt_buffer[0].size = 0;
c->prompt_index = 0; c->prompt_index = 0;
goto changed; goto changed;
case '\013': /* C-k */ case 'k'|KEYC_CTRL:
if (c->prompt_index < size) { if (c->prompt_index < size) {
c->prompt_buffer[c->prompt_index].size = 0; c->prompt_buffer[c->prompt_index].size = 0;
goto changed; goto changed;
} }
break; break;
case '\027': /* C-w */ case 'w'|KEYC_CTRL:
separators = options_get_string(oo, "word-separators"); separators = options_get_string(oo, "word-separators");
idx = c->prompt_index; idx = c->prompt_index;
@@ -1399,7 +1399,7 @@ process_key:
status_prompt_backward_word(c, separators); status_prompt_backward_word(c, separators);
goto changed; goto changed;
case KEYC_UP: case KEYC_UP:
case '\020': /* C-p */ case 'p'|KEYC_CTRL:
histstr = status_prompt_up_history(c->prompt_hindex, histstr = status_prompt_up_history(c->prompt_hindex,
c->prompt_type); c->prompt_type);
if (histstr == NULL) if (histstr == NULL)
@@ -1409,7 +1409,7 @@ process_key:
c->prompt_index = utf8_strlen(c->prompt_buffer); c->prompt_index = utf8_strlen(c->prompt_buffer);
goto changed; goto changed;
case KEYC_DOWN: case KEYC_DOWN:
case '\016': /* C-n */ case 'n'|KEYC_CTRL:
histstr = status_prompt_down_history(c->prompt_hindex, histstr = status_prompt_down_history(c->prompt_hindex,
c->prompt_type); c->prompt_type);
if (histstr == NULL) if (histstr == NULL)
@@ -1418,11 +1418,11 @@ process_key:
c->prompt_buffer = utf8_fromcstr(histstr); c->prompt_buffer = utf8_fromcstr(histstr);
c->prompt_index = utf8_strlen(c->prompt_buffer); c->prompt_index = utf8_strlen(c->prompt_buffer);
goto changed; goto changed;
case '\031': /* C-y */ case 'y'|KEYC_CTRL:
if (status_prompt_paste(c)) if (status_prompt_paste(c))
goto changed; goto changed;
break; break;
case '\024': /* C-t */ case 't'|KEYC_CTRL:
idx = c->prompt_index; idx = c->prompt_index;
if (idx < size) if (idx < size)
idx++; idx++;
@@ -1445,12 +1445,12 @@ process_key:
free(s); free(s);
break; break;
case '\033': /* Escape */ case '\033': /* Escape */
case '\003': /* C-c */ case 'c'|KEYC_CTRL:
case '\007': /* C-g */ case 'g'|KEYC_CTRL:
if (c->prompt_inputcb(c, c->prompt_data, NULL, 1) == 0) if (c->prompt_inputcb(c, c->prompt_data, NULL, 1) == 0)
status_prompt_clear(c); status_prompt_clear(c);
break; break;
case '\022': /* C-r */ case 'r'|KEYC_CTRL:
if (~c->prompt_flags & PROMPT_INCREMENTAL) if (~c->prompt_flags & PROMPT_INCREMENTAL)
break; break;
if (c->prompt_buffer[0].size == 0) { if (c->prompt_buffer[0].size == 0) {
@@ -1461,7 +1461,7 @@ process_key:
} else } else
prefix = '-'; prefix = '-';
goto changed; goto changed;
case '\023': /* C-s */ case 's'|KEYC_CTRL:
if (~c->prompt_flags & PROMPT_INCREMENTAL) if (~c->prompt_flags & PROMPT_INCREMENTAL)
break; break;
if (c->prompt_buffer[0].size == 0) { if (c->prompt_buffer[0].size == 0) {
@@ -1628,8 +1628,9 @@ status_prompt_complete_list(u_int *size, const char *s, int at_start)
struct options_entry *o; struct options_entry *o;
struct options_array_item *a; struct options_array_item *a;
const char *layouts[] = { const char *layouts[] = {
"even-horizontal", "even-vertical", "main-horizontal", "even-horizontal", "even-vertical",
"main-vertical", "tiled", NULL "main-horizontal", "main-horizontal-mirrored",
"main-vertical", "main-vertical-mirrored", "tiled", NULL
}; };
*size = 0; *size = 0;
@@ -1839,6 +1840,7 @@ status_prompt_complete_window_menu(struct client *c, struct session *s,
} }
if (size == 0) { if (size == 0) {
menu_free(menu); menu_free(menu);
free(spm);
return (NULL); return (NULL);
} }
if (size == 1) { if (size == 1) {
@@ -1849,6 +1851,7 @@ status_prompt_complete_window_menu(struct client *c, struct session *s,
} else } else
tmp = list[0]; tmp = list[0];
free(list); free(list);
free(spm);
return (tmp); return (tmp);
} }
if (height > size) if (height > size)

30
style.c
View File

@@ -58,10 +58,11 @@ int
style_parse(struct style *sy, const struct grid_cell *base, const char *in) style_parse(struct style *sy, const struct grid_cell *base, const char *in)
{ {
struct style saved; struct style saved;
const char delimiters[] = " ,\n", *cp; const char delimiters[] = " ,\n", *errstr;
char tmp[256], *found; char tmp[256], *found;
int value; int value;
size_t end; size_t end;
u_int n;
if (*in == '\0') if (*in == '\0')
return (0); return (0);
@@ -137,34 +138,31 @@ style_parse(struct style *sy, const struct grid_cell *base, const char *in)
goto error; goto error;
if (*found != '%' || found[1] == '\0') if (*found != '%' || found[1] == '\0')
goto error; goto error;
for (cp = found + 1; *cp != '\0'; cp++) { n = strtonum(found + 1, 0, UINT_MAX, &errstr);
if (!isdigit((u_char)*cp)) if (errstr != NULL)
goto error; goto error;
}
sy->range_type = STYLE_RANGE_PANE; sy->range_type = STYLE_RANGE_PANE;
sy->range_argument = atoi(found + 1); sy->range_argument = n;
style_set_range_string(sy, ""); style_set_range_string(sy, "");
} else if (strcasecmp(tmp + 6, "window") == 0) { } else if (strcasecmp(tmp + 6, "window") == 0) {
if (found == NULL) if (found == NULL)
goto error; goto error;
for (cp = found; *cp != '\0'; cp++) { n = strtonum(found, 0, UINT_MAX, &errstr);
if (!isdigit((u_char)*cp)) if (errstr != NULL)
goto error; goto error;
}
sy->range_type = STYLE_RANGE_WINDOW; sy->range_type = STYLE_RANGE_WINDOW;
sy->range_argument = atoi(found); sy->range_argument = n;
style_set_range_string(sy, ""); style_set_range_string(sy, "");
} else if (strcasecmp(tmp + 6, "session") == 0) { } else if (strcasecmp(tmp + 6, "session") == 0) {
if (found == NULL) if (found == NULL)
goto error; goto error;
if (*found != '$' || found[1] == '\0') if (*found != '$' || found[1] == '\0')
goto error; goto error;
for (cp = found + 1; *cp != '\0'; cp++) { n = strtonum(found + 1, 0, UINT_MAX, &errstr);
if (!isdigit((u_char)*cp)) if (errstr != NULL)
goto error; goto error;
}
sy->range_type = STYLE_RANGE_SESSION; sy->range_type = STYLE_RANGE_SESSION;
sy->range_argument = atoi(found + 1); sy->range_argument = n;
style_set_range_string(sy, ""); style_set_range_string(sy, "");
} else if (strcasecmp(tmp + 6, "user") == 0) { } else if (strcasecmp(tmp + 6, "user") == 0) {
if (found == NULL) if (found == NULL)

472
tmux.1
View File

@@ -140,10 +140,9 @@ By default,
loads the system configuration file from loads the system configuration file from
.Pa @SYSCONFDIR@/tmux.conf , .Pa @SYSCONFDIR@/tmux.conf ,
if present, then looks for a user configuration file at if present, then looks for a user configuration file at
.Pa \[ti]/.tmux.conf, .Pa \[ti]/.tmux.conf
.Pa $XDG_CONFIG_HOME/tmux/tmux.conf
or or
.Pa \[ti]/.tmux.conf . .Pa $XDG_CONFIG_HOME/tmux/tmux.conf .
.Pp .Pp
The configuration file is a set of The configuration file is a set of
.Nm .Nm
@@ -373,8 +372,10 @@ Enter copy mode and scroll one page up.
Change to the pane above, below, to the left, or to the right of the current Change to the pane above, below, to the left, or to the right of the current
pane. pane.
.It M-1 to M-5 .It M-1 to M-5
Arrange panes in one of the five preset layouts: even-horizontal, Arrange panes in one of the seven preset layouts:
even-vertical, main-horizontal, main-vertical, or tiled. even-horizontal, even-vertical,
main-horizontal, main-horizontal-mirrored,
main-vertical, main-vertical, or tiled.
.It Space .It Space
Arrange the current window in the next preset layout. Arrange the current window in the next preset layout.
.It M-n .It M-n
@@ -1039,9 +1040,17 @@ The following commands are available to manage clients and sessions:
.D1 Pq alias: Ic attach .D1 Pq alias: Ic attach
If run from outside If run from outside
.Nm , .Nm ,
create a new client in the current terminal and attach it to attach to
.Ar target-session
in the current terminal.
.Ar target-session
must already exist - to create a new session, see the
.Ic new-session
command (with
.Fl A
to create or attach).
If used from inside, switch the currently attached session to
.Ar target-session . .Ar target-session .
If used from inside, switch the current client.
If If
.Fl d .Fl d
is specified, any other clients attached to the session are detached. is specified, any other clients attached to the session are detached.
@@ -1353,6 +1362,7 @@ specified multiple times.
.Op Fl C Ar size .Op Fl C Ar size
.Op Fl f Ar flags .Op Fl f Ar flags
.Op Fl l Op Ar target-pane .Op Fl l Op Ar target-pane
.Op Fl r Ar pane:report
.Op Fl t Ar target-client .Op Fl t Ar target-client
.Op Ar adjustment .Op Ar adjustment
.Xc .Xc
@@ -1462,6 +1472,12 @@ for all windows in the attached session.
.Fl f .Fl f
sets a comma-separated list of client flags, see sets a comma-separated list of client flags, see
.Ic attach-session . .Ic attach-session .
.Fl r
allows a control mode client to provide information about a pane via a report
(such as the response to OSC 10).
The argument is a pane ID (with a leading
.Ql % ) ,
a colon, then a report escape sequence.
.Pp .Pp
.Fl l .Fl l
requests the clipboard from the client using the requests the clipboard from the client using the
@@ -1798,6 +1814,23 @@ is used to name the new paste buffer.
.Xc .Xc
Copy from the cursor position and exit copy mode. Copy from the cursor position and exit copy mode.
.It Xo .It Xo
.Ic copy-pipe-end-of-line
.Op Ar command
.Op Ar prefix
.Xc
Copy from the cursor position to the end of the line and pipe the text to
.Ar command .
.Ar prefix
is used to name the new paste buffer.
.It Xo
.Ic copy-pipe-end-of-line-and-cancel
.Op Ar command
.Op Ar prefix
.Xc
Same as
.Ic copy-pipe-end-of-line
but also exit copy mode.
.It Xo
.Ic copy-line .Ic copy-line
.Op Ar prefix .Op Ar prefix
.Xc .Xc
@@ -1808,11 +1841,60 @@ Copy the entire line.
.Xc .Xc
Copy the entire line and exit copy mode. Copy the entire line and exit copy mode.
.It Xo .It Xo
.Ic copy-pipe-line
.Op Ar command
.Op Ar prefix
.Xc
Copy the entire line and pipe the text to
.Ar command .
.Ar prefix
is used to name the new paste buffer.
.It Xo
.Ic copy-pipe-line-and-cancel
.Op Ar command
.Op Ar prefix
.Xc
Same as
.Ic copy-pipe-line
but also exit copy mode.
.It Xo
.Ic copy-pipe
.Op Ar command
.Op Ar prefix
.Xc
Copy the selection, clear it and pipe its text to
.Ar command .
.Ar prefix
is used to name the new paste buffer.
.It Xo
.Ic copy-pipe-no-clear
.Op Ar command
.Op Ar prefix
.Xc
Same as
.Ic copy-pipe
but do not clear the selection.
.It Xo
.Ic copy-pipe-and-cancel
.Op Ar command
.Op Ar prefix
.Xc
Same as
.Ic copy-pipe
but also exit copy mode.
.It Xo
.Ic copy-selection .Ic copy-selection
.Op Ar prefix .Op Ar prefix
.Xc .Xc
Copies the current selection. Copies the current selection.
.It Xo .It Xo
.Ic copy-selection-no-clear
.Op Ar prefix
.Xc
Same as
.Ic copy-selection
but do not clear the selection.
.It Xo
.Ic copy-selection-and-cancel .Ic copy-selection-and-cancel
.Op Ar prefix .Op Ar prefix
(vi: Enter) (vi: Enter)
@@ -1826,6 +1908,12 @@ Copy the current selection and exit copy mode.
.Xc .Xc
Move the cursor down. Move the cursor down.
.It Xo .It Xo
.Ic cursor-down-and-cancel
.Xc
Same as
.Ic cursor-down
but also exit copy mode if reaching the bottom.
.It Xo
.Ic cursor-left .Ic cursor-left
(vi: h) (vi: h)
(emacs: Left) (emacs: Left)
@@ -1857,6 +1945,24 @@ Move the cursor to the end of the line.
.Xc .Xc
Move the cursor to a specific line. Move the cursor to a specific line.
.It Xo .It Xo
.Ic halfpage-down
(vi: C-d)
(emacs: M-Down)
.Xc
Scroll down by half a page.
.It Xo
.Ic halfpage-down-and-cancel
.Xc
Same as
.Ic halfpage-down
but also exit copy mode if reaching the bottom.
.It Xo
.Ic halfpage-up
(vi: C-u)
(emacs: M-Up)
.Xc
Scroll up by half a page.
.It Xo
.Ic history-bottom .Ic history-bottom
(vi: G) (vi: G)
(emacs: M->) (emacs: M->)
@@ -1889,6 +1995,27 @@ Jump backwards to the specified text.
.Xc .Xc
Jump forward to the specified text. Jump forward to the specified text.
.It Xo .It Xo
.Ic jump-reverse
(vi: ,)
(emacs: ,)
.Xc
Repeat the last jump in the reverse direction (forward becomes backward and
backward becomes forward).
.It Xo
.Ic jump-to-backward
.Ar to
(vi: T)
.Xc
Jump backwards, but one character less, placing the cursor on the character
after the target.
.It Xo
.Ic jump-to-forward
.Ar to
(vi: t)
.Xc
Jump forward, but one character less, placing the cursor on the character
before the target.
.It Xo
.Ic jump-to-mark .Ic jump-to-mark
(vi: M-x) (vi: M-x)
(emacs: M-x) (emacs: M-x)
@@ -1923,18 +2050,71 @@ Move to the next prompt.
.Xc .Xc
Move to the next word. Move to the next word.
.It Xo .It Xo
.Ic next-word-end
(vi: e)
(emacs: M-f)
.Xc
Move to the end of the next word.
.It Xo
.Ic next-space
(vi: W)
.Xc
Same as
.Ic next-word
but use a space alone as the word separator.
.It Xo
.Ic next-space-end
(vi: E)
.Xc
Same as
.Ic next-word-end
but use a space alone as the word separator.
.It Xo
.Ic other-end
(vi: o)
.Xc
Switch at which end of the selection the cursor sits.
.It Xo
.Ic page-down .Ic page-down
(vi: C-f) (vi: C-f)
(emacs: PageDown) (emacs: PageDown)
.Xc .Xc
Scroll down by one page. Scroll down by one page.
.It Xo .It Xo
.Ic page-down-and-cancel
.Xc
Same as
.Ic page-down
but also exit copy mode if reaching the bottom.
.It Xo
.Ic page-up .Ic page-up
(vi: C-b) (vi: C-b)
(emacs: PageUp) (emacs: PageUp)
.Xc .Xc
Scroll up by one page. Scroll up by one page.
.It Xo .It Xo
.Ic pipe
.Op Ar command
.Xc
Pipe the selected text to
.Ar command
and clear the selection.
.It Xo
.Ic pipe-no-clear
.Op Ar command
.Xc
Same as
.Ic pipe
but do not clear the selection.
.It Xo
.Ic pipe-and-cancel
.Op Ar command
.Op Ar prefix
.Xc
Same as
.Ic pipe
but also exit copy mode.
.It Xo
.Ic previous-matching-bracket .Ic previous-matching-bracket
(emacs: M-C-b) (emacs: M-C-b)
.Xc .Xc
@@ -1957,6 +2137,21 @@ Move to the previous prompt.
.Xc .Xc
Move to the previous word. Move to the previous word.
.It Xo .It Xo
.Ic previous-space
(vi: B)
.Xc
Same as
.Ic previous-word
but use a space alone as the word separator.
.It Xo
.Ic rectangle-on
.Xc
Turn on rectangle selection mode.
.It Xo
.Ic rectangle-off
.Xc
Turn off rectangle selection mode.
.It Xo
.Ic rectangle-toggle .Ic rectangle-toggle
(vi: v) (vi: v)
(emacs: R) (emacs: R)
@@ -1969,6 +2164,40 @@ Toggle rectangle selection mode.
.Xc .Xc
Refresh the content from the pane. Refresh the content from the pane.
.It Xo .It Xo
.Ic scroll-bottom
.Xc
Scroll up until the current line is at the bottom while keeping the cursor on
that line.
.It Xo
.Ic scroll-down
(vi: C-e)
(emacs: C-Down)
.Xc
Scroll down.
.It Xo
.Ic scroll-down-and-cancel
.Xc
Same as
.Ic scroll-down
but also exit copy mode if the cursor reaches the bottom.
.It Xo
.Ic scroll-middle
(vi: z)
.Xc
Scroll so that the current line becomes the middle one while keeping the
cursor on that line.
.It Xo
.Ic scroll-top
.Xc
Scroll down until the current line is at the top while keeping the cursor on
that line.
.It Xo
.Ic scroll-up
(vi: C-y)
(emacs: C-Up)
.Xc
Scroll up.
.It Xo
.Ic search-again .Ic search-again
(vi: n) (vi: n)
(emacs: n) (emacs: n)
@@ -1981,12 +2210,51 @@ Repeat the last search.
.Xc .Xc
Search backwards for the specified text. Search backwards for the specified text.
.It Xo .It Xo
.Ic search-backward-incremental
.Ar text
(emacs: C-r)
.Xc
Search backwards incrementally for the specified text.
Is expected to be used with the
.Fl i
flag to the
.Ic command-prompt
command.
.It Xo
.Ic search-backward-text
.Ar text
.Xc
Search backwards for the specified plain text.
.It Xo
.Ic search-forward .Ic search-forward
.Ar text .Ar text
(vi: /) (vi: /)
.Xc .Xc
Search forward for the specified text. Search forward for the specified text.
.It Xo .It Xo
.Ic search-forward-incremental
.Ar text
(emacs: C-s)
.Xc
Search forward incrementally for the specified text.
Is expected to be used with the
.Fl i
flag to the
.Ic command-prompt
command.
.It Xo
.Ic search-forward-text
.Ar text
.Xc
Search forward for the specified plain text.
.It Xo
.Ic search-reverse
(vi: N)
(emacs: N)
.Xc
Repeat the last search in the reverse direction (forward becomes backward and
backward becomes forward).
.It Xo
.Ic select-line .Ic select-line
(vi: V) (vi: V)
.Xc .Xc
@@ -1996,12 +2264,28 @@ Select the current line.
.Xc .Xc
Select the current word. Select the current word.
.It Xo .It Xo
.Ic set-mark
(vi: X)
(emacs: X)
.Xc
Mark the current line.
.It Xo
.Ic start-of-line .Ic start-of-line
(vi: 0) (vi: 0)
(emacs: C-a) (emacs: C-a)
.Xc .Xc
Move the cursor to the start of the line. Move the cursor to the start of the line.
.It Xo .It Xo
.Ic stop-selection
.Xc
Stop selecting without clearing the current selection.
.It Xo
.Ic toggle-position
(vi: P)
(emacs: P)
.Xc
Toggle the visibility of the position indicator in the top right.
.It Xo
.Ic top-line .Ic top-line
(vi: H) (vi: H)
(emacs: M-R) (emacs: M-R)
@@ -2094,14 +2378,15 @@ The synopsis for the
command is: command is:
.Bl -tag -width Ds .Bl -tag -width Ds
.It Xo Ic copy-mode .It Xo Ic copy-mode
.Op Fl eHMqu .Op Fl deHMqu
.Op Fl s Ar src-pane .Op Fl s Ar src-pane
.Op Fl t Ar target-pane .Op Fl t Ar target-pane
.Xc .Xc
Enter copy mode. Enter copy mode.
The
.Fl u .Fl u
option scrolls one page up. also scrolls one page up after entering and
.Fl d
one page down if already in copy mode.
.Fl M .Fl M
begins a mouse drag (only valid if bound to a mouse key binding, see begins a mouse drag (only valid if bound to a mouse key binding, see
.Sx MOUSE SUPPORT ) . .Sx MOUSE SUPPORT ) .
@@ -2124,6 +2409,7 @@ This is intended to allow fast scrolling through a pane's history, for
example with: example with:
.Bd -literal -offset indent .Bd -literal -offset indent
bind PageUp copy-mode -eu bind PageUp copy-mode -eu
bind PageDown copy-mode -ed
.Ed .Ed
.El .El
.Pp .Pp
@@ -2150,14 +2436,20 @@ are spread from left to right in the leftover space at the bottom.
Use the Use the
.Em main-pane-height .Em main-pane-height
window option to specify the height of the top pane. window option to specify the height of the top pane.
.It Ic main-vertical .It Ic main-horizontal-mirrored
Similar to The same as
.Ic main-horizontal .Ic main-horizontal
but the large pane is placed on the left and the others spread from top to but mirrored so the main pane is at the bottom of the window.
bottom along the right. .It Ic main-vertical
See the A large (main) pane is shown on the left of the window and the remaining panes
are spread from top to bottom in the leftover space on the right.
Use the
.Em main-pane-width .Em main-pane-width
window option. window option to specify the width of the left pane.
.It Ic main-vertical-mirrored
The same as
.Ic main-vertical
but mirrored so the main pane is on the right of the window.
.It Ic tiled .It Ic tiled
Panes are spread out as evenly as possible over the window in both rows and Panes are spread out as evenly as possible over the window in both rows and
columns. columns.
@@ -2290,7 +2582,8 @@ The following keys may be used in client mode:
.It Li "Up" Ta "Select previous client" .It Li "Up" Ta "Select previous client"
.It Li "Down" Ta "Select next client" .It Li "Down" Ta "Select next client"
.It Li "C-s" Ta "Search by name" .It Li "C-s" Ta "Search by name"
.It Li "n" Ta "Repeat last search" .It Li "n" Ta "Repeat last search forwards"
.It Li "N" Ta "Repeat last search backwards"
.It Li "t" Ta "Toggle if client is tagged" .It Li "t" Ta "Toggle if client is tagged"
.It Li "T" Ta "Tag no clients" .It Li "T" Ta "Tag no clients"
.It Li "C-t" Ta "Tag all clients" .It Li "C-t" Ta "Tag all clients"
@@ -2377,7 +2670,8 @@ The following keys may be used in tree mode:
.It Li "C-s" Ta "Search by name" .It Li "C-s" Ta "Search by name"
.It Li "m" Ta "Set the marked pane" .It Li "m" Ta "Set the marked pane"
.It Li "M" Ta "Clear the marked pane" .It Li "M" Ta "Clear the marked pane"
.It Li "n" Ta "Repeat last search" .It Li "n" Ta "Repeat last search forwards"
.It Li "N" Ta "Repeat last search backwards"
.It Li "t" Ta "Toggle if item is tagged" .It Li "t" Ta "Toggle if item is tagged"
.It Li "T" Ta "Tag no items" .It Li "T" Ta "Tag no items"
.It Li "C-t" Ta "Tag all items" .It Li "C-t" Ta "Tag all items"
@@ -2455,7 +2749,8 @@ The following keys may be used in customize mode:
.It Li "u" Ta "Unset an option (set to default value if global) or unbind a key" .It Li "u" Ta "Unset an option (set to default value if global) or unbind a key"
.It Li "U" Ta "Unset tagged options and unbind tagged keys" .It Li "U" Ta "Unset tagged options and unbind tagged keys"
.It Li "C-s" Ta "Search by name" .It Li "C-s" Ta "Search by name"
.It Li "n" Ta "Repeat last search" .It Li "n" Ta "Repeat last search forwards"
.It Li "N" Ta "Repeat last search backwards"
.It Li "t" Ta "Toggle if item is tagged" .It Li "t" Ta "Toggle if item is tagged"
.It Li "T" Ta "Tag no items" .It Li "T" Ta "Tag no items"
.It Li "C-t" Ta "Tag all items" .It Li "C-t" Ta "Tag all items"
@@ -3718,6 +4013,10 @@ Note that aliases are expanded when a command is parsed rather than when it is
executed, so binding an alias with executed, so binding an alias with
.Ic bind-key .Ic bind-key
will bind the expanded form. will bind the expanded form.
.It Ic copy-command Ar shell-command
Give the command to pipe to if the
.Ic copy-pipe
copy mode command is used without arguments.
.It Ic default-terminal Ar terminal .It Ic default-terminal Ar terminal
Set the default terminal for new windows created in this session - the Set the default terminal for new windows created in this session - the
default value of the default value of the
@@ -3731,16 +4030,11 @@ be set to
.Ql screen , .Ql screen ,
.Ql tmux .Ql tmux
or a derivative of them. or a derivative of them.
.It Ic copy-command Ar shell-command
Give the command to pipe to if the
.Ic copy-pipe
copy mode command is used without arguments.
.It Ic escape-time Ar time .It Ic escape-time Ar time
Set the time in milliseconds for which Set the time in milliseconds for which
.Nm .Nm
waits after an escape is input to determine if it is part of a function or meta waits after an escape is input to determine if it is part of a function or meta
key sequences. key sequences.
The default is 500 milliseconds.
.It Ic editor Ar shell-command .It Ic editor Ar shell-command
Set the command used when Set the command used when
.Nm .Nm
@@ -3757,22 +4051,54 @@ If enabled, the server will exit when there are no attached clients.
.It Xo Ic extended-keys .It Xo Ic extended-keys
.Op Ic on | off | always .Op Ic on | off | always
.Xc .Xc
When Controls how modified keys (keys pressed together with Control, Meta, or Shift)
.Ic on are reported.
or This is the equivalent of the
.Ic always , .Ic modifyOtherKeys
the escape sequence to enable extended keys is sent to the terminal, if .Xr xterm 1
.Nm resource.
knows that it is supported. .Pp
.Nm When set to
always recognises extended keys itself.
If this option is
.Ic on , .Ic on ,
.Nm the program inside the pane can request one of two modes: mode 1 which changes
will only forward extended keys to applications when they request them; if the sequence for only keys which lack an existing well-known representation; or
mode 2 which changes the sequence for all keys.
When set to
.Ic always , .Ic always ,
modes 1 and 2 can still be requested by applications, but mode 1 will be forced
instead of the standard mode.
When set to
.Ic off ,
this feature is disabled and only standard keys are reported.
.Pp
.Nm .Nm
will always forward the keys. will always request extended keys itself if the terminal supports them.
See also the
.Ic extkeys
feature for the
.Ic terminal-features
option, the
.Ic extended-keys-format
option and the
.Ic pane_key_mode
variable.
.It Xo Ic extended-keys-format
.Op Ic csi-u | xterm
.Xc
Selects one of the two possible formats for reporting modified keys to
applications.
This is the equivalent of the
.Ic formatOtherKeys
.Xr xterm 1
resource.
For example, C-S-a will be reported as
.Ql ^[[27;6;65~
when set to
.Ic xterm ,
and as
.Ql ^[[65;6u
when set to
.Ic csi-u .
.It Xo Ic focus-events .It Xo Ic focus-events
.Op Ic on | off .Op Ic on | off
.Xc .Xc
@@ -4036,10 +4362,12 @@ If
(the default), leave the session orphaned. (the default), leave the session orphaned.
If If
.Ic keep-last , .Ic keep-last ,
destroy the session only if it is in a group and has other sessions in that group. destroy the session only if it is in a group and has other sessions in that
group.
If If
.Ic keep-group , .Ic keep-group ,
destroy the session unless it is in a group and is the only session in that group. destroy the session unless it is in a group and is the only session in that
group.
.It Xo Ic detach-on-destroy .It Xo Ic detach-on-destroy
.Op Ic off | on | no-detached | previous | next .Op Ic off | on | no-detached | previous | next
.Xc .Xc
@@ -4173,6 +4501,13 @@ Like
.Ic prefix2 .Ic prefix2
can be set to can be set to
.Ql None . .Ql None .
.It Ic prefix-timeout Ar time
Set the time in milliseconds for which
.Nm
waits after
.Ic prefix
is input before dismissing it.
Can be set to zero to disable any timeout.
.It Xo Ic renumber-windows .It Xo Ic renumber-windows
.Op Ic on | off .Op Ic on | off
.Xc .Xc
@@ -4438,9 +4773,11 @@ Set the character used to fill areas of the terminal unused by a window.
.It Ic main-pane-height Ar height .It Ic main-pane-height Ar height
.It Ic main-pane-width Ar width .It Ic main-pane-width Ar width
Set the width or height of the main (left or top) pane in the Set the width or height of the main (left or top) pane in the
.Ic main-horizontal .Ic main-horizontal ,
.Ic main-horizontal-mirrored ,
.Ic main-vertical ,
or or
.Ic main-vertical .Ic main-vertical-mirrored
layouts. layouts.
If suffixed by If suffixed by
.Ql % , .Ql % ,
@@ -4514,7 +4851,9 @@ An interval of zero disables the monitoring.
.It Ic other-pane-height Ar height .It Ic other-pane-height Ar height
Set the height of the other panes (not the main pane) in the Set the height of the other panes (not the main pane) in the
.Ic main-horizontal .Ic main-horizontal
layout. and
.Ic main-horizontal-mirrored
layouts.
If this option is set to 0 (the default), it will have no effect. If this option is set to 0 (the default), it will have no effect.
If both the If both the
.Ic main-pane-height .Ic main-pane-height
@@ -4531,7 +4870,9 @@ Like
.Ic other-pane-height , .Ic other-pane-height ,
but set the width of other panes in the but set the width of other panes in the
.Ic main-vertical .Ic main-vertical
layout. and
.Ic main-vertical-mirrored
layouts.
.Pp .Pp
.It Ic pane-active-border-style Ar style .It Ic pane-active-border-style Ar style
Set the pane border style for the currently active pane. Set the pane border style for the currently active pane.
@@ -4746,6 +5087,12 @@ they will be allowed even if the pane is invisible.
Allow programs in the pane to change the window name using a terminal escape Allow programs in the pane to change the window name using a terminal escape
sequence (\eek...\ee\e\e). sequence (\eek...\ee\e\e).
.Pp .Pp
.It Xo Ic allow-set-title
.Op Ic on | off
.Xc
Allow programs in the pane to change the title using the terminal escape
sequences (\ee]2;...\ee\e\e or \ee]0;...\ee\e\e).
.Pp
.It Xo Ic alternate-screen .It Xo Ic alternate-screen
.Op Ic on | off .Op Ic on | off
.Xc .Xc
@@ -4871,6 +5218,14 @@ layout after every
set-hook -g after-split-window "selectl even-vertical" set-hook -g after-split-window "selectl even-vertical"
.Ed .Ed
.Pp .Pp
If a command fails, the
.Ql command-error
hook will be fired.
For example, this could be used to write to a log file:
.Bd -literal -offset indent
set-hook -g command-error "run-shell \\"echo 'a tmux command failed' >>/tmp/log\\""
.Ed
.Pp
All the notifications listed in the All the notifications listed in the
.Sx CONTROL MODE .Sx CONTROL MODE
section are hooks (without any arguments), except section are hooks (without any arguments), except
@@ -4903,6 +5258,8 @@ Run when focus exits a client
Run when a client is resized. Run when a client is resized.
.It client-session-changed .It client-session-changed
Run when a client's attached session is changed. Run when a client's attached session is changed.
.It command-error
Run when a command fails.
.It pane-died .It pane-died
Run when the program running in a pane exits, but Run when the program running in a pane exits, but
.Ic remain-on-exit .Ic remain-on-exit
@@ -5421,6 +5778,7 @@ The following variables are available, where appropriate:
.It Li "command_list_name" Ta "" Ta "Command name if listing commands" .It Li "command_list_name" Ta "" Ta "Command name if listing commands"
.It Li "command_list_usage" Ta "" Ta "Command usage if listing commands" .It Li "command_list_usage" Ta "" Ta "Command usage if listing commands"
.It Li "config_files" Ta "" Ta "List of configuration files loaded" .It Li "config_files" Ta "" Ta "List of configuration files loaded"
.It Li "copy_cursor_hyperlink" Ta "" Ta "Hyperlink under cursor in copy mode"
.It Li "copy_cursor_line" Ta "" Ta "Line the cursor is on in copy mode" .It Li "copy_cursor_line" Ta "" Ta "Line the cursor is on in copy mode"
.It Li "copy_cursor_word" Ta "" Ta "Word under cursor in copy mode" .It Li "copy_cursor_word" Ta "" Ta "Word under cursor in copy mode"
.It Li "copy_cursor_x" Ta "" Ta "Cursor X position in copy mode" .It Li "copy_cursor_x" Ta "" Ta "Cursor X position in copy mode"
@@ -5482,6 +5840,7 @@ The following variables are available, where appropriate:
.It Li "pane_in_mode" Ta "" Ta "1 if pane is in a mode" .It Li "pane_in_mode" Ta "" Ta "1 if pane is in a mode"
.It Li "pane_index" Ta "#P" Ta "Index of pane" .It Li "pane_index" Ta "#P" Ta "Index of pane"
.It Li "pane_input_off" Ta "" Ta "1 if input to pane is disabled" .It Li "pane_input_off" Ta "" Ta "1 if input to pane is disabled"
.It Li "pane_key_mode" Ta "" Ta "Extended key reporting mode in this pane"
.It Li "pane_last" Ta "" Ta "1 if last pane" .It Li "pane_last" Ta "" Ta "1 if last pane"
.It Li "pane_left" Ta "" Ta "Left of pane" .It Li "pane_left" Ta "" Ta "Left of pane"
.It Li "pane_marked" Ta "" Ta "1 if this is the marked pane" .It Li "pane_marked" Ta "" Ta "1 if this is the marked pane"
@@ -5506,6 +5865,8 @@ The following variables are available, where appropriate:
.It Li "scroll_position" Ta "" Ta "Scroll position in copy mode" .It Li "scroll_position" Ta "" Ta "Scroll position in copy mode"
.It Li "scroll_region_lower" Ta "" Ta "Bottom of scroll region in pane" .It Li "scroll_region_lower" Ta "" Ta "Bottom of scroll region in pane"
.It Li "scroll_region_upper" Ta "" Ta "Top of scroll region in pane" .It Li "scroll_region_upper" Ta "" Ta "Top of scroll region in pane"
.It Li "search_count" Ta "" Ta "Count of search results"
.It Li "search_count_partial" Ta "" Ta "1 if search count is partial count"
.It Li "search_match" Ta "" Ta "Search match if any" .It Li "search_match" Ta "" Ta "Search match if any"
.It Li "search_present" Ta "" Ta "1 if search started in copy mode" .It Li "search_present" Ta "" Ta "1 if search started in copy mode"
.It Li "selection_active" Ta "" Ta "1 if selection started and changes with the cursor in copy mode" .It Li "selection_active" Ta "" Ta "1 if selection started and changes with the cursor in copy mode"
@@ -6111,7 +6472,7 @@ the default is
.Ql y . .Ql y .
.Tg menu .Tg menu
.It Xo Ic display-menu .It Xo Ic display-menu
.Op Fl O .Op Fl OM
.Op Fl b Ar border-lines .Op Fl b Ar border-lines
.Op Fl c Ar target-client .Op Fl c Ar target-client
.Op Fl C Ar starting-choice .Op Fl C Ar starting-choice
@@ -6218,7 +6579,13 @@ changes this behaviour so that the menu does not close when the mouse button is
released without an item selected the menu is not closed and a mouse button released without an item selected the menu is not closed and a mouse button
must be clicked to choose an item. must be clicked to choose an item.
.Pp .Pp
The following keys are also available: .Fl M
tells
.Nm
the menu should handle mouse events; by default only menus opened from mouse
key bindings do so.
.Pp
The following keys are available in menus:
.Bl -column "Key" "Function" -offset indent .Bl -column "Key" "Function" -offset indent
.It Sy "Key" Ta Sy "Function" .It Sy "Key" Ta Sy "Function"
.It Li "Enter" Ta "Choose selected item" .It Li "Enter" Ta "Choose selected item"
@@ -6441,7 +6808,8 @@ The following keys may be used in buffer mode:
.It Li "Up" Ta "Select previous buffer" .It Li "Up" Ta "Select previous buffer"
.It Li "Down" Ta "Select next buffer" .It Li "Down" Ta "Select next buffer"
.It Li "C-s" Ta "Search by name or content" .It Li "C-s" Ta "Search by name or content"
.It Li "n" Ta "Repeat last search" .It Li "n" Ta "Repeat last search forwards"
.It Li "N" Ta "Repeat last search backwards"
.It Li "t" Ta "Toggle if buffer is tagged" .It Li "t" Ta "Toggle if buffer is tagged"
.It Li "T" Ta "Tag no buffers" .It Li "T" Ta "Tag no buffers"
.It Li "C-t" Ta "Tag all buffers" .It Li "C-t" Ta "Tag all buffers"
@@ -6464,7 +6832,7 @@ is replaced by the buffer name in
and the result executed as a command. and the result executed as a command.
If If
.Ar template .Ar template
is not given, "paste-buffer -b \[aq]%%\[aq]" is used. is not given, "paste-buffer -p -b \[aq]%%\[aq]" is used.
.Pp .Pp
.Fl O .Fl O
specifies the initial sort field: one of specifies the initial sort field: one of
@@ -6533,6 +6901,11 @@ is given, the buffer is also sent to the clipboard for
using the using the
.Xr xterm 1 .Xr xterm 1
escape sequence, if possible. escape sequence, if possible.
If
.Ar path
is
.Ql - ,
the contents are read from stdin.
.Tg pasteb .Tg pasteb
.It Xo Ic paste-buffer .It Xo Ic paste-buffer
.Op Fl dpr .Op Fl dpr
@@ -6570,6 +6943,11 @@ Save the contents of the specified paste buffer to
The The
.Fl a .Fl a
option appends to rather than overwriting the file. option appends to rather than overwriting the file.
If
.Ar path
is
.Ql - ,
the contents are read from stdin.
.It Xo Ic set-buffer .It Xo Ic set-buffer
.Op Fl aw .Op Fl aw
.Op Fl b Ar buffer-name .Op Fl b Ar buffer-name

18
tmux.c
View File

@@ -235,6 +235,24 @@ fail:
return (NULL); return (NULL);
} }
char *
shell_argv0(const char *shell, int is_login)
{
const char *slash, *name;
char *argv0;
slash = strrchr(shell, '/');
if (slash != NULL && slash[1] != '\0')
name = slash + 1;
else
name = shell;
if (is_login)
xasprintf(&argv0, "-%s", name);
else
xasprintf(&argv0, "%s", name);
return (argv0);
}
void void
setblocking(int fd, int state) setblocking(int fd, int state)
{ {

81
tmux.h
View File

@@ -134,6 +134,7 @@ struct winlink;
*/ */
#define KEYC_BASE 0x0000000010e000ULL #define KEYC_BASE 0x0000000010e000ULL
#define KEYC_USER 0x0000000010f000ULL #define KEYC_USER 0x0000000010f000ULL
#define KEYC_USER_END (KEYC_USER + KEYC_NUSER)
/* Key modifier bits. */ /* Key modifier bits. */
#define KEYC_META 0x00100000000000ULL #define KEYC_META 0x00100000000000ULL
@@ -147,8 +148,7 @@ struct winlink;
#define KEYC_IMPLIED_META 0x08000000000000ULL #define KEYC_IMPLIED_META 0x08000000000000ULL
#define KEYC_BUILD_MODIFIERS 0x10000000000000ULL #define KEYC_BUILD_MODIFIERS 0x10000000000000ULL
#define KEYC_VI 0x20000000000000ULL #define KEYC_VI 0x20000000000000ULL
#define KEYC_EXTENDED 0x40000000000000ULL #define KEYC_SENT 0x40000000000000ULL
#define KEYC_SENT 0x80000000000000ULL
/* Masks for key bits. */ /* Masks for key bits. */
#define KEYC_MASK_MODIFIERS 0x00f00000000000ULL #define KEYC_MASK_MODIFIERS 0x00f00000000000ULL
@@ -169,7 +169,7 @@ struct winlink;
(((key) & KEYC_MASK_KEY) < KEYC_BASE || \ (((key) & KEYC_MASK_KEY) < KEYC_BASE || \
((key) & KEYC_MASK_KEY) >= KEYC_BASE_END) && \ ((key) & KEYC_MASK_KEY) >= KEYC_BASE_END) && \
(((key) & KEYC_MASK_KEY) < KEYC_USER || \ (((key) & KEYC_MASK_KEY) < KEYC_USER || \
((key) & KEYC_MASK_KEY) >= KEYC_USER + KEYC_NUSER)) ((key) & KEYC_MASK_KEY) >= KEYC_USER_END))
/* Multiple click timeout. */ /* Multiple click timeout. */
#define KEYC_CLICK_TIMEOUT 300 #define KEYC_CLICK_TIMEOUT 300
@@ -196,6 +196,42 @@ struct winlink;
*/ */
typedef unsigned long long key_code; typedef unsigned long long key_code;
/* C0 control characters */
enum {
C0_NUL,
C0_SOH,
C0_STX,
C0_ETX,
C0_EOT,
C0_ENQ,
C0_ASC,
C0_BEL,
C0_BS,
C0_HT,
C0_LF,
C0_VT,
C0_FF,
C0_CR,
C0_SO,
C0_SI,
C0_DLE,
C0_DC1,
C0_DC2,
C0_DC3,
C0_DC4,
C0_NAK,
C0_SYN,
C0_ETB,
C0_CAN,
C0_EM,
C0_SUB,
C0_ESC,
C0_FS,
C0_GS,
C0_RS,
C0_US
};
/* Special key codes. */ /* Special key codes. */
enum { enum {
/* Focus events. */ /* Focus events. */
@@ -591,14 +627,16 @@ enum tty_code_code {
#define MODE_MOUSE_ALL 0x1000 #define MODE_MOUSE_ALL 0x1000
#define MODE_ORIGIN 0x2000 #define MODE_ORIGIN 0x2000
#define MODE_CRLF 0x4000 #define MODE_CRLF 0x4000
#define MODE_KEXTENDED 0x8000 #define MODE_KEYS_EXTENDED 0x8000
#define MODE_CURSOR_VERY_VISIBLE 0x10000 #define MODE_CURSOR_VERY_VISIBLE 0x10000
#define MODE_CURSOR_BLINKING_SET 0x20000 #define MODE_CURSOR_BLINKING_SET 0x20000
#define MODE_KEYS_EXTENDED_2 0x40000
#define ALL_MODES 0xffffff #define ALL_MODES 0xffffff
#define ALL_MOUSE_MODES (MODE_MOUSE_STANDARD|MODE_MOUSE_BUTTON|MODE_MOUSE_ALL) #define ALL_MOUSE_MODES (MODE_MOUSE_STANDARD|MODE_MOUSE_BUTTON|MODE_MOUSE_ALL)
#define MOTION_MOUSE_MODES (MODE_MOUSE_BUTTON|MODE_MOUSE_ALL) #define MOTION_MOUSE_MODES (MODE_MOUSE_BUTTON|MODE_MOUSE_ALL)
#define CURSOR_MODES (MODE_CURSOR|MODE_CURSOR_BLINKING|MODE_CURSOR_VERY_VISIBLE) #define CURSOR_MODES (MODE_CURSOR|MODE_CURSOR_BLINKING|MODE_CURSOR_VERY_VISIBLE)
#define EXTENDED_KEY_MODES (MODE_KEYS_EXTENDED|MODE_KEYS_EXTENDED_2)
/* Mouse protocol constants. */ /* Mouse protocol constants. */
#define MOUSE_PARAM_MAX 0xff #define MOUSE_PARAM_MAX 0xff
@@ -877,7 +915,7 @@ struct screen_sel;
struct screen_titles; struct screen_titles;
struct screen { struct screen {
char *title; char *title;
char *path; char *path;
struct screen_titles *titles; struct screen_titles *titles;
struct grid *grid; /* grid data */ struct grid *grid; /* grid data */
@@ -959,6 +997,11 @@ enum pane_lines {
#define PANE_BORDER_ARROWS 2 #define PANE_BORDER_ARROWS 2
#define PANE_BORDER_BOTH 3 #define PANE_BORDER_BOTH 3
/* Mode returned by window_pane_mode function. */
#define WINDOW_PANE_NO_MODE 0
#define WINDOW_PANE_COPY_MODE 1
#define WINDOW_PANE_VIEW_MODE 2
/* Screen redraw context. */ /* Screen redraw context. */
struct screen_redraw_ctx { struct screen_redraw_ctx {
struct client *c; struct client *c;
@@ -1131,6 +1174,9 @@ struct window_pane {
int border_gc_set; int border_gc_set;
struct grid_cell border_gc; struct grid_cell border_gc;
int control_bg;
int control_fg;
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 */
RB_ENTRY(window_pane) tree_entry; RB_ENTRY(window_pane) tree_entry;
@@ -1970,6 +2016,7 @@ RB_HEAD(key_bindings, key_binding);
struct key_table { struct key_table {
const char *name; const char *name;
struct timeval activity_time;
struct key_bindings key_bindings; struct key_bindings key_bindings;
struct key_bindings default_key_bindings; struct key_bindings default_key_bindings;
@@ -2096,6 +2143,7 @@ extern int ptm_fd;
extern const char *shell_command; extern const char *shell_command;
int checkshell(const char *); int checkshell(const char *);
void setblocking(int, int); void setblocking(int, int);
char *shell_argv0(const char *, int);
uint64_t get_timer(void); uint64_t get_timer(void);
const char *sig2name(int); const char *sig2name(int);
const char *find_cwd(void); const char *find_cwd(void);
@@ -2390,7 +2438,6 @@ void tty_cmd_clearstartofscreen(struct tty *, const struct tty_ctx *);
void tty_cmd_deletecharacter(struct tty *, const struct tty_ctx *); void tty_cmd_deletecharacter(struct tty *, const struct tty_ctx *);
void tty_cmd_clearcharacter(struct tty *, const struct tty_ctx *); void tty_cmd_clearcharacter(struct tty *, const struct tty_ctx *);
void tty_cmd_deleteline(struct tty *, const struct tty_ctx *); void tty_cmd_deleteline(struct tty *, const struct tty_ctx *);
void tty_cmd_erasecharacter(struct tty *, const struct tty_ctx *);
void tty_cmd_insertcharacter(struct tty *, const struct tty_ctx *); void tty_cmd_insertcharacter(struct tty *, const struct tty_ctx *);
void tty_cmd_insertline(struct tty *, const struct tty_ctx *); void tty_cmd_insertline(struct tty *, const struct tty_ctx *);
void tty_cmd_linefeed(struct tty *, const struct tty_ctx *); void tty_cmd_linefeed(struct tty *, const struct tty_ctx *);
@@ -2451,6 +2498,8 @@ const struct utf8_data *tty_acs_rounded_borders(int);
void tty_keys_build(struct tty *); void tty_keys_build(struct tty *);
void tty_keys_free(struct tty *); void tty_keys_free(struct tty *);
int tty_keys_next(struct tty *); int tty_keys_next(struct tty *);
int tty_keys_colours(struct tty *, const char *, size_t, size_t *,
int *, int *);
/* arguments.c */ /* arguments.c */
void args_set(struct args *, u_char, struct args_value *, int); void args_set(struct args *, u_char, struct args_value *, int);
@@ -2567,7 +2616,6 @@ enum cmd_retval cmd_attach_session(struct cmdq_item *, const char *, int, int,
int, const char *, int, const char *); int, const char *, int, const char *);
/* cmd-parse.c */ /* cmd-parse.c */
void cmd_parse_empty(struct cmd_parse_input *);
struct cmd_parse_result *cmd_parse_from_file(FILE *, struct cmd_parse_input *); struct cmd_parse_result *cmd_parse_from_file(FILE *, struct cmd_parse_input *);
struct cmd_parse_result *cmd_parse_from_string(const char *, struct cmd_parse_result *cmd_parse_from_string(const char *,
struct cmd_parse_input *); struct cmd_parse_input *);
@@ -2700,11 +2748,12 @@ void server_clear_marked(void);
int server_is_marked(struct session *, struct winlink *, int server_is_marked(struct session *, struct winlink *,
struct window_pane *); struct window_pane *);
int server_check_marked(void); int server_check_marked(void);
int server_start(struct tmuxproc *, int, struct event_base *, int, char *); int server_start(struct tmuxproc *, uint64_t, struct event_base *, int,
char *);
void server_update_socket(void); void server_update_socket(void);
void server_add_accept(int); void server_add_accept(int);
void printflike(1, 2) server_add_message(const char *, ...); void printflike(1, 2) server_add_message(const char *, ...);
int server_create_socket(int, char **); int server_create_socket(uint64_t, char **);
/* server-client.c */ /* server-client.c */
RB_PROTOTYPE(client_windows, client_window, entry, server_client_window_cmp); RB_PROTOTYPE(client_windows, client_window, entry, server_client_window_cmp);
@@ -2728,8 +2777,6 @@ void server_client_suspend(struct client *);
void server_client_detach(struct client *, enum msgtype); void server_client_detach(struct client *, enum msgtype);
void server_client_exec(struct client *, const char *); void server_client_exec(struct client *, const char *);
void server_client_loop(void); void server_client_loop(void);
void server_client_push_stdout(struct client *);
void server_client_push_stderr(struct client *);
const char *server_client_get_cwd(struct client *, struct session *); const char *server_client_get_cwd(struct client *, struct session *);
void server_client_set_flags(struct client *, const char *); void server_client_set_flags(struct client *, const char *);
const char *server_client_get_flags(struct client *); const char *server_client_get_flags(struct client *);
@@ -3070,7 +3117,7 @@ struct window_pane *window_add_pane(struct window *, struct window_pane *,
void window_resize(struct window *, u_int, u_int, int, int); void window_resize(struct window *, u_int, u_int, int, int);
void window_pane_send_resize(struct window_pane *, u_int, u_int); void window_pane_send_resize(struct window_pane *, u_int, u_int);
int window_zoom(struct window_pane *); int window_zoom(struct window_pane *);
int window_unzoom(struct window *); int window_unzoom(struct window *, int);
int window_push_zoom(struct window *, int, int); int window_push_zoom(struct window *, int, int);
int window_pop_zoom(struct window *); int window_pop_zoom(struct window *);
void window_lost_pane(struct window *, struct window_pane *); void window_lost_pane(struct window *, struct window_pane *);
@@ -3121,6 +3168,7 @@ void window_pane_update_used_data(struct window_pane *,
struct window_pane_offset *, size_t); struct window_pane_offset *, size_t);
void window_set_fill_character(struct window *); void window_set_fill_character(struct window *);
void window_pane_default_cursor(struct window_pane *); void window_pane_default_cursor(struct window_pane *);
int window_pane_mode(struct window_pane *);
/* layout.c */ /* layout.c */
u_int layout_count_cells(struct layout_cell *); u_int layout_count_cells(struct layout_cell *);
@@ -3185,7 +3233,7 @@ int mode_tree_set_current(struct mode_tree_data *, uint64_t);
void mode_tree_each_tagged(struct mode_tree_data *, mode_tree_each_cb, void mode_tree_each_tagged(struct mode_tree_data *, mode_tree_each_cb,
struct client *, key_code, int); struct client *, key_code, int);
void mode_tree_up(struct mode_tree_data *, int); void mode_tree_up(struct mode_tree_data *, int);
void mode_tree_down(struct mode_tree_data *, int); int mode_tree_down(struct mode_tree_data *, int);
struct mode_tree_data *mode_tree_start(struct window_pane *, struct args *, struct mode_tree_data *mode_tree_start(struct window_pane *, struct args *,
mode_tree_build_cb, mode_tree_draw_cb, mode_tree_search_cb, mode_tree_build_cb, mode_tree_draw_cb, mode_tree_search_cb,
mode_tree_menu_cb, mode_tree_height_cb, mode_tree_key_cb, void *, mode_tree_menu_cb, mode_tree_height_cb, mode_tree_key_cb, void *,
@@ -3227,6 +3275,7 @@ void printflike(3, 4) window_copy_add(struct window_pane *, int, const char *,
void printflike(3, 0) window_copy_vadd(struct window_pane *, int, const char *, void printflike(3, 0) window_copy_vadd(struct window_pane *, int, const char *,
va_list); va_list);
void window_copy_pageup(struct window_pane *, int); void window_copy_pageup(struct window_pane *, int);
void window_copy_pagedown(struct window_pane *, int, int);
void window_copy_start_drag(struct client *, struct mouse_event *); void window_copy_start_drag(struct client *, struct mouse_event *);
char *window_copy_get_word(struct window_pane *, u_int, u_int); char *window_copy_get_word(struct window_pane *, u_int, u_int);
char *window_copy_get_line(struct window_pane *, u_int); char *window_copy_get_line(struct window_pane *, u_int);
@@ -3259,8 +3308,6 @@ void control_add_sub(struct client *, const char *, enum control_sub_type,
void control_remove_sub(struct client *, const char *); void control_remove_sub(struct client *, const char *);
/* control-notify.c */ /* control-notify.c */
void control_notify_input(struct client *, struct window_pane *,
const u_char *, size_t);
void control_notify_pane_mode_changed(int); void control_notify_pane_mode_changed(int);
void control_notify_window_layout_changed(struct window *); void control_notify_window_layout_changed(struct window *);
void control_notify_window_pane_changed(struct window *); void control_notify_window_pane_changed(struct window *);
@@ -3294,8 +3341,6 @@ char *session_check_name(const char *);
void session_update_activity(struct session *, struct timeval *); void session_update_activity(struct session *, struct timeval *);
struct session *session_next_session(struct session *); struct session *session_next_session(struct session *);
struct session *session_previous_session(struct session *); struct session *session_previous_session(struct session *);
struct winlink *session_new(struct session *, const char *, int, char **,
const char *, const char *, int, char **);
struct winlink *session_attach(struct session *, struct window *, int, struct winlink *session_attach(struct session *, struct window *, int,
char **); char **);
int session_detach(struct session *, struct winlink *); int session_detach(struct session *, struct winlink *);
@@ -3318,6 +3363,7 @@ void session_renumber_windows(struct session *);
/* utf8.c */ /* utf8.c */
enum utf8_state utf8_towc (const struct utf8_data *, wchar_t *); enum utf8_state utf8_towc (const struct utf8_data *, wchar_t *);
enum utf8_state utf8_fromwc(wchar_t wc, struct utf8_data *);
int utf8_in_table(wchar_t, const wchar_t *, u_int); int utf8_in_table(wchar_t, const wchar_t *, u_int);
utf8_char utf8_build_one(u_char); utf8_char utf8_build_one(u_char);
enum utf8_state utf8_from_data(const struct utf8_data *, utf8_char *); enum utf8_state utf8_from_data(const struct utf8_data *, utf8_char *);
@@ -3463,6 +3509,7 @@ u_int hyperlinks_put(struct hyperlinks *, const char *,
int hyperlinks_get(struct hyperlinks *, u_int, int hyperlinks_get(struct hyperlinks *, u_int,
const char **, const char **, const char **); const char **, const char **, const char **);
struct hyperlinks *hyperlinks_init(void); struct hyperlinks *hyperlinks_init(void);
struct hyperlinks *hyperlinks_copy(struct hyperlinks *);
void hyperlinks_reset(struct hyperlinks *); void hyperlinks_reset(struct hyperlinks *);
void hyperlinks_free(struct hyperlinks *); void hyperlinks_free(struct hyperlinks *);

View File

@@ -237,7 +237,7 @@ static const struct tty_feature tty_feature_sync = {
/* Terminal supports extended keys. */ /* Terminal supports extended keys. */
static const char *const tty_feature_extkeys_capabilities[] = { static const char *const tty_feature_extkeys_capabilities[] = {
"Eneks=\\E[>4;1m", "Eneks=\\E[>4;2m",
"Dseks=\\E[>4m", "Dseks=\\E[>4m",
NULL NULL
}; };

View File

@@ -59,7 +59,6 @@ static int tty_keys_device_attributes2(struct tty *, const char *, size_t,
size_t *); size_t *);
static int tty_keys_extended_device_attributes(struct tty *, const char *, static int tty_keys_extended_device_attributes(struct tty *, const char *,
size_t, size_t *); size_t, size_t *);
static int tty_keys_colours(struct tty *, const char *, size_t, size_t *);
/* A key tree entry. */ /* A key tree entry. */
struct tty_key { struct tty_key {
@@ -665,7 +664,7 @@ tty_keys_next(struct tty *tty)
size_t len, size; size_t len, size;
cc_t bspace; cc_t bspace;
int delay, expired = 0, n; int delay, expired = 0, n;
key_code key; key_code key, onlykey;
struct mouse_event m = { 0 }; struct mouse_event m = { 0 };
struct key_event *event; struct key_event *event;
@@ -721,7 +720,7 @@ tty_keys_next(struct tty *tty)
} }
/* Is this a colours response? */ /* Is this a colours response? */
switch (tty_keys_colours(tty, buf, len, &size)) { switch (tty_keys_colours(tty, buf, len, &size, &tty->fg, &tty->bg)) {
case 0: /* yes */ case 0: /* yes */
key = KEYC_UNKNOWN; key = KEYC_UNKNOWN;
goto complete_key; goto complete_key;
@@ -802,6 +801,27 @@ first_key:
key = (u_char)buf[0]; key = (u_char)buf[0];
size = 1; size = 1;
} }
/* C-Space is special. */
if ((key & KEYC_MASK_KEY) == C0_NUL)
key = ' ' | KEYC_CTRL | (key & KEYC_META);
/*
* Fix up all C0 control codes that don't have a dedicated key into
* corresponding Ctrl keys. Convert characters in the A-Z range into
* lowercase, so ^A becomes a|CTRL.
*/
onlykey = key & KEYC_MASK_KEY;
if (onlykey < 0x20 &&
onlykey != C0_HT &&
onlykey != C0_CR &&
onlykey != C0_ESC) {
onlykey |= 0x40;
if (onlykey >= 'A' && onlykey <= 'Z')
onlykey |= 0x20;
key = onlykey | KEYC_CTRL | (key & KEYC_META);
}
goto complete_key; goto complete_key;
partial_key: partial_key:
@@ -911,7 +931,8 @@ tty_keys_extended_key(struct tty *tty, const char *buf, size_t len,
char tmp[64]; char tmp[64];
cc_t bspace; cc_t bspace;
key_code nkey; key_code nkey;
key_code onlykey; struct utf8_data ud;
utf8_char uc;
*size = 0; *size = 0;
@@ -961,10 +982,25 @@ tty_keys_extended_key(struct tty *tty, const char *buf, size_t len,
else else
nkey = number; nkey = number;
/* Convert UTF-32 codepoint into internal representation. */
if (nkey & ~0x7f) {
if (utf8_fromwc(nkey, &ud) == UTF8_DONE &&
utf8_from_data(&ud, &uc) == UTF8_DONE)
nkey = uc;
else
return (-1);
}
/* Update the modifiers. */ /* Update the modifiers. */
if (modifiers > 0) { if (modifiers > 0) {
modifiers--; modifiers--;
if (modifiers & 1) /*
* The Shift modifier may not be reported in some input modes,
* which is unfortunate, as in general case determining if a
* character is shifted or not requires knowing the input
* keyboard layout. So we only fix up the trivial case.
*/
if (modifiers & 1 || (nkey >= 'A' && nkey <= 'Z'))
nkey |= KEYC_SHIFT; nkey |= KEYC_SHIFT;
if (modifiers & 2) if (modifiers & 2)
nkey |= (KEYC_META|KEYC_IMPLIED_META); /* Alt */ nkey |= (KEYC_META|KEYC_IMPLIED_META); /* Alt */
@@ -974,34 +1010,15 @@ tty_keys_extended_key(struct tty *tty, const char *buf, size_t len,
nkey |= (KEYC_META|KEYC_IMPLIED_META); /* Meta */ nkey |= (KEYC_META|KEYC_IMPLIED_META); /* Meta */
} }
/* /* Convert S-Tab into Backtab. */
* Don't allow both KEYC_CTRL and as an implied modifier. Also convert if ((nkey & KEYC_MASK_KEY) == '\011' && (nkey & KEYC_SHIFT))
* C-X into C-x and so on. nkey = KEYC_BTAB | (nkey & ~KEYC_MASK_KEY & ~KEYC_SHIFT);
*/
if (nkey & KEYC_CTRL) {
onlykey = (nkey & KEYC_MASK_KEY);
if (onlykey < 32 &&
onlykey != 9 &&
onlykey != 13 &&
onlykey != 27)
/* nothing */;
else if (onlykey >= 97 && onlykey <= 122)
onlykey -= 96;
else if (onlykey >= 64 && onlykey <= 95)
onlykey -= 64;
else if (onlykey == 32)
onlykey = 0;
else if (onlykey == 63)
onlykey = 127;
else
onlykey |= KEYC_CTRL;
nkey = onlykey|((nkey & KEYC_MASK_MODIFIERS) & ~KEYC_CTRL);
}
if (log_get_level() != 0) { if (log_get_level() != 0) {
log_debug("%s: extended key %.*s is %llx (%s)", c->name, log_debug("%s: extended key %.*s is %llx (%s)", c->name,
(int)*size, buf, nkey, key_string_lookup_key(nkey, 1)); (int)*size, buf, nkey, key_string_lookup_key(nkey, 1));
} }
*key = nkey; *key = nkey;
return (0); return (0);
} }
@@ -1202,7 +1219,7 @@ tty_keys_clipboard(struct tty *tty, const char *buf, size_t len, size_t *size)
} }
if (end == len) if (end == len)
return (1); return (1);
*size = end + terminator; *size = end + 1;
/* Skip the initial part. */ /* Skip the initial part. */
buf += 5; buf += 5;
@@ -1314,26 +1331,21 @@ tty_keys_device_attributes(struct tty *tty, const char *buf, size_t len,
break; break;
} }
/* /* Add terminal features. */
* Add terminal features. Hardware level 5 does not offer SIXEL but
* some terminal emulators report it anyway and it does not harm
* to check it here.
*
* DECSLRM and DECFRA should be supported by level 5 as well as level
* 4, but VTE has rather ruined it by advertising level 5 despite not
* supporting them.
*/
switch (p[0]) { switch (p[0]) {
case 64: /* level 4 */ case 61: /* level 1 */
tty_add_features(features, "margins,rectfill", ",");
/* FALLTHROUGH */
case 62: /* level 2 */ case 62: /* level 2 */
case 63: /* level 3 */ case 63: /* level 3 */
case 64: /* level 4 */
case 65: /* level 5 */ case 65: /* level 5 */
for (i = 1; i < n; i++) { for (i = 1; i < n; i++) {
log_debug("%s: DA feature: %d", c->name, p[i]); log_debug("%s: DA feature: %d", c->name, p[i]);
if (p[i] == 4) if (p[i] == 4)
tty_add_features(features, "sixel", ","); tty_add_features(features, "sixel", ",");
if (p[i] == 21)
tty_add_features(features, "margins", ",");
if (p[i] == 28)
tty_add_features(features, "rectfill", ",");
} }
break; break;
} }
@@ -1405,11 +1417,6 @@ tty_keys_device_attributes2(struct tty *tty, const char *buf, size_t len,
* we can't use level 5 from DA because of VTE. * we can't use level 5 from DA because of VTE.
*/ */
switch (p[0]) { switch (p[0]) {
case 41: /* VT420 */
case 61: /* VT510 */
case 64: /* VT520 */
tty_add_features(features, "margins,rectfill", ",");
break;
case 'M': /* mintty */ case 'M': /* mintty */
tty_default_features(features, "mintty", 0); tty_default_features(features, "mintty", 0);
break; break;
@@ -1500,8 +1507,9 @@ tty_keys_extended_device_attributes(struct tty *tty, const char *buf,
* Handle foreground or background input. Returns 0 for success, -1 for * Handle foreground or background input. Returns 0 for success, -1 for
* failure, 1 for partial. * failure, 1 for partial.
*/ */
static int int
tty_keys_colours(struct tty *tty, const char *buf, size_t len, size_t *size) tty_keys_colours(struct tty *tty, const char *buf, size_t len, size_t *size,
int *fg, int *bg)
{ {
struct client *c = tty->client; struct client *c = tty->client;
u_int i; u_int i;
@@ -1552,11 +1560,17 @@ tty_keys_colours(struct tty *tty, const char *buf, size_t len, size_t *size)
n = colour_parseX11(tmp); n = colour_parseX11(tmp);
if (n != -1 && buf[3] == '0') { if (n != -1 && buf[3] == '0') {
log_debug("%s: foreground is %s", c->name, colour_tostring(n)); if (c != NULL)
tty->fg = n; log_debug("%s fg is %s", c->name, colour_tostring(n));
else
log_debug("fg is %s", colour_tostring(n));
*fg = n;
} else if (n != -1) { } else if (n != -1) {
log_debug("%s: background is %s", c->name, colour_tostring(n)); if (c != NULL)
tty->bg = n; log_debug("%s bg is %s", c->name, colour_tostring(n));
else
log_debug("bg is %s", colour_tostring(n));
*bg = n;
} }
return (0); return (0);

View File

@@ -531,9 +531,10 @@ tty_term_create(struct tty *tty, char *name, char **caps, u_int ncaps,
struct options_array_item *a; struct options_array_item *a;
union options_value *ov; union options_value *ov;
u_int i, j; u_int i, j;
const char *s, *value; const char *s, *value, *errstr;
size_t offset, namelen; size_t offset, namelen;
char *first; char *first;
int n;
log_debug("adding term %s", name); log_debug("adding term %s", name);
@@ -567,8 +568,13 @@ tty_term_create(struct tty *tty, char *name, char **caps, u_int ncaps,
code->value.string = tty_term_strip(value); code->value.string = tty_term_strip(value);
break; break;
case TTYCODE_NUMBER: case TTYCODE_NUMBER:
code->type = TTYCODE_NUMBER; n = strtonum(value, 0, INT_MAX, &errstr);
code->value.number = atoi(value); if (errstr != NULL)
log_debug("%s: %s", ent->name, errstr);
else {
code->type = TTYCODE_NUMBER;
code->value.number = n;
}
break; break;
case TTYCODE_FLAG: case TTYCODE_FLAG:
code->type = TTYCODE_FLAG; code->type = TTYCODE_FLAG;

35
tty.c
View File

@@ -28,6 +28,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <termios.h> #include <termios.h>
#include <time.h>
#include <unistd.h> #include <unistd.h>
#include "tmux.h" #include "tmux.h"
@@ -379,13 +380,13 @@ tty_send_requests(struct tty *tty)
tty_puts(tty, "\033]11;?\033\\"); tty_puts(tty, "\033]11;?\033\\");
} else } else
tty->flags |= TTY_ALL_REQUEST_FLAGS; tty->flags |= TTY_ALL_REQUEST_FLAGS;
tty->last_requests = time (NULL); tty->last_requests = time(NULL);
} }
void void
tty_repeat_requests(struct tty *tty) tty_repeat_requests(struct tty *tty)
{ {
time_t t = time (NULL); time_t t = time(NULL);
if (~tty->flags & TTY_STARTED) if (~tty->flags & TTY_STARTED)
return; return;
@@ -2777,7 +2778,6 @@ static void
tty_colours(struct tty *tty, const struct grid_cell *gc) tty_colours(struct tty *tty, const struct grid_cell *gc)
{ {
struct grid_cell *tc = &tty->cell; struct grid_cell *tc = &tty->cell;
int have_ax;
/* No changes? Nothing is necessary. */ /* No changes? Nothing is necessary. */
if (gc->fg == tc->fg && gc->bg == tc->bg && gc->us == tc->us) if (gc->fg == tc->fg && gc->bg == tc->bg && gc->us == tc->us)
@@ -2791,28 +2791,18 @@ tty_colours(struct tty *tty, const struct grid_cell *gc)
*/ */
if (COLOUR_DEFAULT(gc->fg) || COLOUR_DEFAULT(gc->bg)) { if (COLOUR_DEFAULT(gc->fg) || COLOUR_DEFAULT(gc->bg)) {
/* /*
* If don't have AX but do have op, send sgr0 (op can't * If don't have AX, send sgr0. This resets both colours to default.
* actually be used because it is sometimes the same as sgr0
* and sometimes isn't). This resets both colours to default.
*
* Otherwise, try to set the default colour only as needed. * Otherwise, try to set the default colour only as needed.
*/ */
have_ax = tty_term_flag(tty->term, TTYC_AX); if (!tty_term_flag(tty->term, TTYC_AX))
if (!have_ax && tty_term_has(tty->term, TTYC_OP))
tty_reset(tty); tty_reset(tty);
else { else {
if (COLOUR_DEFAULT(gc->fg) && !COLOUR_DEFAULT(tc->fg)) { if (COLOUR_DEFAULT(gc->fg) && !COLOUR_DEFAULT(tc->fg)) {
if (have_ax) tty_puts(tty, "\033[39m");
tty_puts(tty, "\033[39m");
else if (tc->fg != 7)
tty_putcode_i(tty, TTYC_SETAF, 7);
tc->fg = gc->fg; tc->fg = gc->fg;
} }
if (COLOUR_DEFAULT(gc->bg) && !COLOUR_DEFAULT(tc->bg)) { if (COLOUR_DEFAULT(gc->bg) && !COLOUR_DEFAULT(tc->bg)) {
if (have_ax) tty_puts(tty, "\033[49m");
tty_puts(tty, "\033[49m");
else if (tc->bg != 0)
tty_putcode_i(tty, TTYC_SETAB, 0);
tc->bg = gc->bg; tc->bg = gc->bg;
} }
} }
@@ -2824,7 +2814,7 @@ tty_colours(struct tty *tty, const struct grid_cell *gc)
/* /*
* Set the background colour. This must come after the foreground as * Set the background colour. This must come after the foreground as
* tty_colour_fg() can call tty_reset(). * tty_colours_fg() can call tty_reset().
*/ */
if (!COLOUR_DEFAULT(gc->bg) && gc->bg != tc->bg) if (!COLOUR_DEFAULT(gc->bg) && gc->bg != tc->bg)
tty_colours_bg(tty, gc); tty_colours_bg(tty, gc);
@@ -2972,6 +2962,15 @@ tty_colours_fg(struct tty *tty, const struct grid_cell *gc)
struct grid_cell *tc = &tty->cell; struct grid_cell *tc = &tty->cell;
char s[32]; char s[32];
/*
* If the current colour is an aixterm bright colour and the new is not,
* reset because some terminals do not clear bright correctly.
*/
if (tty->cell.fg >= 90 &&
tty->cell.bg <= 97 &&
(gc->fg < 90 || gc->fg > 97))
tty_reset(tty);
/* Is this a 24-bit or 256-colour colour? */ /* Is this a 24-bit or 256-colour colour? */
if (gc->fg & COLOUR_FLAG_RGB || gc->fg & COLOUR_FLAG_256) { if (gc->fg & COLOUR_FLAG_RGB || gc->fg & COLOUR_FLAG_256) {
if (tty_try_colour(tty, gc->fg, "38") == 0) if (tty_try_colour(tty, gc->fg, "38") == 0)

29
utf8.c
View File

@@ -24,6 +24,7 @@
#include <string.h> #include <string.h>
#include <wchar.h> #include <wchar.h>
#include "compat.h"
#include "tmux.h" #include "tmux.h"
static const wchar_t utf8_force_wide[] = { static const wchar_t utf8_force_wide[] = {
@@ -449,6 +450,32 @@ utf8_towc(const struct utf8_data *ud, wchar_t *wc)
return (UTF8_DONE); return (UTF8_DONE);
} }
/* Convert wide character to UTF-8 character. */
enum utf8_state
utf8_fromwc(wchar_t wc, struct utf8_data *ud)
{
int size, width;
#ifdef HAVE_UTF8PROC
size = utf8proc_wctomb(ud->data, wc);
#else
size = wctomb(ud->data, wc);
#endif
if (size < 0) {
log_debug("UTF-8 %d, wctomb() %d", wc, errno);
wctomb(NULL, 0);
return (UTF8_ERROR);
}
if (size == 0)
return (UTF8_ERROR);
ud->size = ud->have = size;
if (utf8_width(ud, &width) == UTF8_DONE) {
ud->width = width;
return (UTF8_DONE);
}
return (UTF8_ERROR);
}
/* /*
* Open UTF-8 sequence. * Open UTF-8 sequence.
* *
@@ -525,7 +552,7 @@ utf8_strvis(char *dst, const char *src, size_t len, int flag)
/* Not a complete, valid UTF-8 character. */ /* Not a complete, valid UTF-8 character. */
src -= ud.have; src -= ud.have;
} }
if (src[0] == '$' && src < end - 1) { if ((flag & VIS_DQ) && src[0] == '$' && src < end - 1) {
if (isalpha((u_char)src[1]) || if (isalpha((u_char)src[1]) ||
src[1] == '_' || src[1] == '_' ||
src[1] == '{') src[1] == '{')

View File

@@ -36,7 +36,7 @@ static void window_buffer_key(struct window_mode_entry *,
struct client *, struct session *, struct client *, struct session *,
struct winlink *, key_code, struct mouse_event *); struct winlink *, key_code, struct mouse_event *);
#define WINDOW_BUFFER_DEFAULT_COMMAND "paste-buffer -b '%%'" #define WINDOW_BUFFER_DEFAULT_COMMAND "paste-buffer -p -b '%%'"
#define WINDOW_BUFFER_DEFAULT_FORMAT \ #define WINDOW_BUFFER_DEFAULT_FORMAT \
"#{t/p:buffer_created}: #{buffer_sample}" "#{t/p:buffer_created}: #{buffer_sample}"
@@ -408,8 +408,17 @@ window_buffer_do_delete(void *modedata, void *itemdata,
struct window_buffer_itemdata *item = itemdata; struct window_buffer_itemdata *item = itemdata;
struct paste_buffer *pb; struct paste_buffer *pb;
if (item == mode_tree_get_current(data->data)) if (item == mode_tree_get_current(data->data) &&
mode_tree_down(data->data, 0); !mode_tree_down(data->data, 0)) {
/*
*If we were unable to select the item further down we are at
* the end of the list. Move one element up instead, to make
* sure that we preserve a valid selection or we risk having
* the tree build logic reset it to the first item.
*/
mode_tree_up(data->data, 0);
}
if ((pb = paste_get_name(item->name)) != NULL) if ((pb = paste_get_name(item->name)) != NULL)
paste_free(pb); paste_free(pb);
} }
@@ -508,7 +517,7 @@ window_buffer_key(struct window_mode_entry *wme, struct client *c,
struct window_buffer_itemdata *item; struct window_buffer_itemdata *item;
int finished; int finished;
if (paste_get_top(NULL) == NULL) { if (paste_is_empty()) {
finished = 1; finished = 1;
goto out; goto out;
} }
@@ -541,7 +550,7 @@ window_buffer_key(struct window_mode_entry *wme, struct client *c,
} }
out: out:
if (finished || paste_get_top(NULL) == NULL) if (finished || paste_is_empty())
window_pane_reset_mode(wp); window_pane_reset_mode(wp);
else { else {
mode_tree_draw(mtd); mode_tree_draw(mtd);

View File

@@ -41,7 +41,7 @@ static void window_copy_resize(struct window_mode_entry *, u_int, u_int);
static void window_copy_formats(struct window_mode_entry *, static void window_copy_formats(struct window_mode_entry *,
struct format_tree *); struct format_tree *);
static void window_copy_pageup1(struct window_mode_entry *, int); static void window_copy_pageup1(struct window_mode_entry *, int);
static int window_copy_pagedown(struct window_mode_entry *, int, int); static int window_copy_pagedown1(struct window_mode_entry *, int, int);
static void window_copy_next_paragraph(struct window_mode_entry *); static void window_copy_next_paragraph(struct window_mode_entry *);
static void window_copy_previous_paragraph(struct window_mode_entry *); static void window_copy_previous_paragraph(struct window_mode_entry *);
static void window_copy_redraw_selection(struct window_mode_entry *, u_int); static void window_copy_redraw_selection(struct window_mode_entry *, u_int);
@@ -450,6 +450,8 @@ window_copy_init(struct window_mode_entry *wme,
data->scroll_exit = args_has(args, 'e'); data->scroll_exit = args_has(args, 'e');
data->hide_position = args_has(args, 'H'); data->hide_position = args_has(args, 'H');
if (base->hyperlinks != NULL)
data->screen.hyperlinks = hyperlinks_copy(base->hyperlinks);
data->screen.cx = data->cx; data->screen.cx = data->cx;
data->screen.cy = data->cy; data->screen.cy = data->cy;
data->mx = data->cx; data->mx = data->cx;
@@ -646,8 +648,18 @@ window_copy_pageup1(struct window_mode_entry *wme, int half_page)
window_copy_redraw_screen(wme); window_copy_redraw_screen(wme);
} }
void
window_copy_pagedown(struct window_pane *wp, int half_page, int scroll_exit)
{
if (window_copy_pagedown1(TAILQ_FIRST(&wp->modes), half_page,
scroll_exit)) {
window_pane_reset_mode(wp);
return;
}
}
static int static int
window_copy_pagedown(struct window_mode_entry *wme, int half_page, window_copy_pagedown1(struct window_mode_entry *wme, int half_page,
int scroll_exit) int scroll_exit)
{ {
struct window_copy_mode_data *data = wme->data; struct window_copy_mode_data *data = wme->data;
@@ -754,6 +766,18 @@ window_copy_get_line(struct window_pane *wp, u_int y)
return (format_grid_line(gd, gd->hsize + y)); return (format_grid_line(gd, gd->hsize + y));
} }
static void *
window_copy_cursor_hyperlink_cb(struct format_tree *ft)
{
struct window_pane *wp = format_get_pane(ft);
struct window_mode_entry *wme = TAILQ_FIRST(&wp->modes);
struct window_copy_mode_data *data = wme->data;
struct grid *gd = data->screen.grid;
return (format_grid_hyperlink(gd, data->cx, gd->hsize + data->cy,
&data->screen));
}
static void * static void *
window_copy_cursor_word_cb(struct format_tree *ft) window_copy_cursor_word_cb(struct format_tree *ft)
{ {
@@ -795,22 +819,36 @@ window_copy_formats(struct window_mode_entry *wme, struct format_tree *ft)
format_add(ft, "copy_cursor_x", "%d", data->cx); format_add(ft, "copy_cursor_x", "%d", data->cx);
format_add(ft, "copy_cursor_y", "%d", data->cy); format_add(ft, "copy_cursor_y", "%d", data->cy);
format_add(ft, "selection_present", "%d", data->screen.sel != NULL);
if (data->screen.sel != NULL) { if (data->screen.sel != NULL) {
format_add(ft, "selection_start_x", "%d", data->selx); format_add(ft, "selection_start_x", "%d", data->selx);
format_add(ft, "selection_start_y", "%d", data->sely); format_add(ft, "selection_start_y", "%d", data->sely);
format_add(ft, "selection_end_x", "%d", data->endselx); format_add(ft, "selection_end_x", "%d", data->endselx);
format_add(ft, "selection_end_y", "%d", data->endsely); format_add(ft, "selection_end_y", "%d", data->endsely);
format_add(ft, "selection_active", "%d",
data->cursordrag != CURSORDRAG_NONE); if (data->cursordrag != CURSORDRAG_NONE)
} else format_add(ft, "selection_active", "1");
format_add(ft, "selection_active", "%d", 0); else
format_add(ft, "selection_active", "0");
if (data->endselx != data->selx || data->endsely != data->sely)
format_add(ft, "selection_present", "1");
else
format_add(ft, "selection_present", "0");
} else {
format_add(ft, "selection_active", "0");
format_add(ft, "selection_present", "0");
}
format_add(ft, "search_present", "%d", data->searchmark != NULL); format_add(ft, "search_present", "%d", data->searchmark != NULL);
if (data->searchcount != -1) {
format_add(ft, "search_count", "%d", data->searchcount);
format_add(ft, "search_count_partial", "%d", data->searchmore);
}
format_add_cb(ft, "search_match", window_copy_search_match_cb); format_add_cb(ft, "search_match", window_copy_search_match_cb);
format_add_cb(ft, "copy_cursor_word", window_copy_cursor_word_cb); format_add_cb(ft, "copy_cursor_word", window_copy_cursor_word_cb);
format_add_cb(ft, "copy_cursor_line", window_copy_cursor_line_cb); format_add_cb(ft, "copy_cursor_line", window_copy_cursor_line_cb);
format_add_cb(ft, "copy_cursor_hyperlink",
window_copy_cursor_hyperlink_cb);
} }
static void static void
@@ -1339,7 +1377,7 @@ window_copy_cmd_halfpage_down(struct window_copy_cmd_state *cs)
u_int np = wme->prefix; u_int np = wme->prefix;
for (; np != 0; np--) { for (; np != 0; np--) {
if (window_copy_pagedown(wme, 1, data->scroll_exit)) if (window_copy_pagedown1(wme, 1, data->scroll_exit))
return (WINDOW_COPY_CMD_CANCEL); return (WINDOW_COPY_CMD_CANCEL);
} }
return (WINDOW_COPY_CMD_NOTHING); return (WINDOW_COPY_CMD_NOTHING);
@@ -1353,7 +1391,7 @@ window_copy_cmd_halfpage_down_and_cancel(struct window_copy_cmd_state *cs)
u_int np = wme->prefix; u_int np = wme->prefix;
for (; np != 0; np--) { for (; np != 0; np--) {
if (window_copy_pagedown(wme, 1, 1)) if (window_copy_pagedown1(wme, 1, 1))
return (WINDOW_COPY_CMD_CANCEL); return (WINDOW_COPY_CMD_CANCEL);
} }
return (WINDOW_COPY_CMD_NOTHING); return (WINDOW_COPY_CMD_NOTHING);
@@ -1781,7 +1819,7 @@ window_copy_cmd_page_down(struct window_copy_cmd_state *cs)
u_int np = wme->prefix; u_int np = wme->prefix;
for (; np != 0; np--) { for (; np != 0; np--) {
if (window_copy_pagedown(wme, 0, data->scroll_exit)) if (window_copy_pagedown1(wme, 0, data->scroll_exit))
return (WINDOW_COPY_CMD_CANCEL); return (WINDOW_COPY_CMD_CANCEL);
} }
return (WINDOW_COPY_CMD_NOTHING); return (WINDOW_COPY_CMD_NOTHING);
@@ -1794,7 +1832,7 @@ window_copy_cmd_page_down_and_cancel(struct window_copy_cmd_state *cs)
u_int np = wme->prefix; u_int np = wme->prefix;
for (; np != 0; np--) { for (; np != 0; np--) {
if (window_copy_pagedown(wme, 0, 1)) if (window_copy_pagedown1(wme, 0, 1))
return (WINDOW_COPY_CMD_CANCEL); return (WINDOW_COPY_CMD_CANCEL);
} }
return (WINDOW_COPY_CMD_NOTHING); return (WINDOW_COPY_CMD_NOTHING);
@@ -2464,7 +2502,8 @@ window_copy_cmd_refresh_from_pane(struct window_copy_cmd_state *cs)
screen_free(data->backing); screen_free(data->backing);
free(data->backing); free(data->backing);
data->backing = window_copy_clone_screen(&wp->base, &data->screen, NULL, NULL, wme->swp != wme->wp); data->backing = window_copy_clone_screen(&wp->base, &data->screen, NULL,
NULL, wme->swp != wme->wp);
window_copy_size_changed(wme); window_copy_size_changed(wme);
return (WINDOW_COPY_CMD_REDRAW); return (WINDOW_COPY_CMD_REDRAW);
@@ -3606,11 +3645,10 @@ window_copy_search_jump(struct window_mode_entry *wme, struct grid *gd,
struct grid *sgd, u_int fx, u_int fy, u_int endline, int cis, int wrap, struct grid *sgd, u_int fx, u_int fy, u_int endline, int cis, int wrap,
int direction, int regex) int direction, int regex)
{ {
u_int i, px, sx, ssize = 1; u_int i, px, sx, ssize = 1;
int found = 0, cflags = REG_EXTENDED; int found = 0, cflags = REG_EXTENDED;
char *sbuf; char *sbuf;
regex_t reg; regex_t reg;
struct grid_line *gl;
if (regex) { if (regex) {
sbuf = xmalloc(ssize); sbuf = xmalloc(ssize);
@@ -3627,9 +3665,6 @@ window_copy_search_jump(struct window_mode_entry *wme, struct grid *gd,
if (direction) { if (direction) {
for (i = fy; i <= endline; i++) { for (i = fy; i <= endline; i++) {
gl = grid_get_line(gd, i);
if (i != endline && gl->flags & GRID_LINE_WRAPPED)
continue;
if (regex) { if (regex) {
found = window_copy_search_lr_regex(gd, found = window_copy_search_lr_regex(gd,
&px, &sx, i, fx, gd->sx, &reg); &px, &sx, i, fx, gd->sx, &reg);
@@ -3643,9 +3678,6 @@ window_copy_search_jump(struct window_mode_entry *wme, struct grid *gd,
} }
} else { } else {
for (i = fy + 1; endline < i; i--) { for (i = fy + 1; endline < i; i--) {
gl = grid_get_line(gd, i - 1);
if (i != endline && gl->flags & GRID_LINE_WRAPPED)
continue;
if (regex) { if (regex) {
found = window_copy_search_rl_regex(gd, found = window_copy_search_rl_regex(gd,
&px, &sx, i - 1, 0, fx + 1, &reg); &px, &sx, i - 1, 0, fx + 1, &reg);
@@ -4686,7 +4718,7 @@ window_copy_get_selection(struct window_mode_entry *wme, size_t *len)
if (keys == MODEKEY_EMACS || lastex <= ey_last) { if (keys == MODEKEY_EMACS || lastex <= ey_last) {
if (~grid_get_line(data->backing->grid, ey)->flags & if (~grid_get_line(data->backing->grid, ey)->flags &
GRID_LINE_WRAPPED || lastex != ey_last) GRID_LINE_WRAPPED || lastex != ey_last)
off -= 1; off -= 1;
} }
*len = off; *len = off;
return (buf); return (buf);

View File

@@ -338,7 +338,7 @@ window_destroy(struct window *w)
{ {
log_debug("window @%u destroyed (%d references)", w->id, w->references); log_debug("window @%u destroyed (%d references)", w->id, w->references);
window_unzoom(w); window_unzoom(w, 0);
RB_REMOVE(windows, &windows, w); RB_REMOVE(windows, &windows, w);
if (w->layout_root != NULL) if (w->layout_root != NULL)
@@ -481,7 +481,7 @@ window_pane_update_focus(struct window_pane *wp)
struct client *c; struct client *c;
int focused = 0; int focused = 0;
if (wp != NULL) { if (wp != NULL && (~wp->flags & PANE_EXITED)) {
if (wp != wp->window->active) if (wp != wp->window->active)
focused = 0; focused = 0;
else { else {
@@ -673,7 +673,7 @@ window_zoom(struct window_pane *wp)
} }
int int
window_unzoom(struct window *w) window_unzoom(struct window *w, int notify)
{ {
struct window_pane *wp; struct window_pane *wp;
@@ -690,7 +690,9 @@ window_unzoom(struct window *w)
wp->saved_layout_cell = NULL; wp->saved_layout_cell = NULL;
} }
layout_fix_panes(w, NULL); layout_fix_panes(w, NULL);
notify_window("window-layout-changed", w);
if (notify)
notify_window("window-layout-changed", w);
return (0); return (0);
} }
@@ -704,7 +706,7 @@ window_push_zoom(struct window *w, int always, int flag)
w->flags |= WINDOW_WASZOOMED; w->flags |= WINDOW_WASZOOMED;
else else
w->flags &= ~WINDOW_WASZOOMED; w->flags &= ~WINDOW_WASZOOMED;
return (window_unzoom(w) == 0); return (window_unzoom(w, 1) == 0);
} }
int int
@@ -942,6 +944,9 @@ window_pane_create(struct window *w, u_int sx, u_int sy, u_int hlimit)
wp->pipe_fd = -1; wp->pipe_fd = -1;
wp->control_bg = -1;
wp->control_fg = -1;
colour_palette_init(&wp->palette); colour_palette_init(&wp->palette);
colour_palette_from_option(&wp->palette, wp->options); colour_palette_from_option(&wp->palette, wp->options);
@@ -1667,3 +1672,15 @@ window_pane_default_cursor(struct window_pane *wp)
s->default_mode = 0; s->default_mode = 0;
screen_set_cursor_style(c, &s->default_cstyle, &s->default_mode); screen_set_cursor_style(c, &s->default_cstyle, &s->default_mode);
} }
int
window_pane_mode(struct window_pane *wp)
{
if (TAILQ_FIRST(&wp->modes) != NULL) {
if (TAILQ_FIRST(&wp->modes)->mode == &window_copy_mode)
return (WINDOW_PANE_COPY_MODE);
if (TAILQ_FIRST(&wp->modes)->mode == &window_view_mode)
return (WINDOW_PANE_VIEW_MODE);
}
return (WINDOW_PANE_NO_MODE);
}