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:
schedule:
- cron: '0 0 * * *'
workflow_dispatch:
permissions:
contents: read
issues: write
pull-requests: write
discussions: write
concurrency:
group: lock-threads
jobs:
lock:
permissions:
issues: write # for dessant/lock-threads to lock issues
pull-requests: write # for dessant/lock-threads to lock PRs
action:
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@v2
- uses: dessant/lock-threads@v5
with:
github-token: ${{ github.token }}
issue-lock-inactive-days: '30'
pr-lock-inactive-days: '60'
issue-lock-comment: >
issue-inactive-days: '30'
issue-comment: >
This issue has been automatically locked since there
has not been any recent activity after it was closed.
Please open a new issue for related bugs.
pr-lock-comment: >
pr-inactive-days: '60'
pr-comment: >
This pull request has been automatically locked since there
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
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.
* 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
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];
if (argument->type != ARGS_STRING) {
xasprintf(cause, "-%c argument must be a string", flag);
args_free_value(new);
free(new);
return (-1);
}
}
if (argument == NULL) {
args_free_value(new);
free(new);
if (optional_argument) {
log_debug("%s: -%c (optional)", __func__, flag);
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++;
if (value != NULL && value->type != ARGS_NONE)
TAILQ_INSERT_TAIL(&entry->values, value, entry);
else
free(value);
}
/* 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;
size_t sslen;
int fd, flags = client_flags;
int fd;
uint64_t flags = client_flags;
pid_t pid;
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,
sizeof client_flags);
@@ -497,20 +498,10 @@ client_send_identify(const char *ttynam, const char *termname, char **caps,
static __dead void
client_exec(const char *shell, const char *shellcmd)
{
const char *name, *ptr;
char *argv0;
char *argv0;
log_debug("shell %s, command %s", shell, shellcmd);
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);
argv0 = shell_argv0(shell, !!(client_flags & CLIENT_LOGIN));
setenv("SHELL", shell, 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);
if (cdata->prompt_type == PROMPT_TYPE_INVALID) {
cmdq_error(item, "unknown type: %s", type);
cmd_command_prompt_free(cdata);
return (CMD_RETURN_ERROR);
}
} else

View File

@@ -76,8 +76,10 @@ cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item)
cdata = xcalloc(1, sizeof *cdata);
cdata->cmdlist = args_make_commands_now(self, item, 0, 1);
if (cdata->cmdlist == NULL)
if (cdata->cmdlist == NULL) {
free(cdata);
return (CMD_RETURN_ERROR);
}
if (wait)
cdata->item = item;
@@ -90,6 +92,7 @@ cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item)
cdata->confirm_key = confirm_key[0];
else {
cmdq_error(item, "invalid confirm key");
free(cdata);
return (CMD_RETURN_ERROR);
}
}
@@ -100,8 +103,8 @@ cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item)
xasprintf(&new_prompt, "%s ", prompt);
else {
cmd = cmd_get_entry(cmd_list_first(cdata->cmdlist))->name;
xasprintf(&new_prompt, "Confirm '%s'? (%c/n) ",
cmd, cdata->confirm_key);
xasprintf(&new_prompt, "Confirm '%s'? (%c/n) ", cmd,
cdata->confirm_key);
}
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",
.alias = NULL,
.args = { "eHMs:t:uq", 0, 0, NULL },
.usage = "[-eHMuq] [-s src-pane] " CMD_TARGET_PANE_USAGE,
.args = { "deHMs:t:uq", 0, 0, NULL },
.usage = "[-deHMuq] [-s src-pane] " CMD_TARGET_PANE_USAGE,
.source = { 's', 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'))
window_copy_pageup(wp, 0);
if (args_has(args, 'd'))
window_copy_pagedown(wp, 0, args_has(args, 'e'));
return (CMD_RETURN_NORMAL);
}

View File

@@ -38,8 +38,8 @@ const struct cmd_entry cmd_display_menu_entry = {
.name = "display-menu",
.alias = "menu",
.args = { "b:c:C:H:s:S:Ot:T:x:y:", 1, -1, cmd_display_menu_args_parse },
.usage = "[-O] [-b border-lines] [-c target-client] "
.args = { "b:c:C:H:s:S:MOt:T:x:y:", 1, -1, cmd_display_menu_args_parse },
.usage = "[-MO] [-b border-lines] [-c target-client] "
"[-C starting-choice] [-H selected-style] [-s style] "
"[-S border-style] " CMD_TARGET_PANE_USAGE "[-T title] "
"[-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'))
flags |= MENU_STAYOPEN;
if (!event->m.valid)
if (!event->m.valid && !args_has(args, 'M'))
flags |= MENU_NOMOUSE;
if (menu_display(menu, flags, starting_choice, item, px, py, tc, lines,
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);
if (wp == NULL)
return (1);
window_unzoom(w);
window_unzoom(w, 1);
xasprintf(&expanded, "%%%u", wp->id);

View File

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

View File

@@ -664,9 +664,18 @@ cmdq_fire_command(struct cmdq_item *item)
out:
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);
else
} else
cmdq_guard(item, "end", flags);
return (retval);
}
@@ -805,10 +814,10 @@ cmdq_running(struct client *c)
struct cmdq_list *queue = cmdq_get(c);
if (queue->item == NULL)
return (NULL);
if (queue->item->flags & CMDQ_WAITING)
return (NULL);
return (queue->item);
return (NULL);
if (queue->item->flags & CMDQ_WAITING)
return (NULL);
return (queue->item);
}
/* Print a guard line. */

View File

@@ -34,9 +34,10 @@ const struct cmd_entry cmd_refresh_client_entry = {
.name = "refresh-client",
.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] "
"[-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,
.exec = cmd_refresh_client_exec
@@ -193,6 +194,34 @@ cmd_refresh_client_clipboard(struct cmd *self, struct cmdq_item *item)
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
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'));
if (args_has(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 (~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 (w->flags & WINDOW_ZOOMED)
window_unzoom(w);
window_unzoom(w, 1);
else
window_zoom(wp);
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)
wp = window_pane_find_by_id(cdata->wp_id);
if (wp == NULL && 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;
if (wp == NULL) {
if (cdata->item != NULL) {
cmdq_print(cdata->item, "%s", msg);
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);
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;
if (args_has(args, 'l')) {
size = args_percentage_and_expand(args, 'l', 0, INT_MAX, curval,
item, &cause);
item, &cause);
} else if (args_has(args, 'p')) {
size = args_strtonum_and_expand(args, 'l', 0, 100, item,
&cause);
size = args_strtonum_and_expand(args, 'p', 0, 100, item,
&cause);
if (cause == NULL)
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_popup_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_has_session_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_unbind_key_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;
const struct cmd_entry *cmd_table[] = {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -24,7 +24,9 @@
#include <systemd/sd-login.h>
#include <systemd/sd-id128.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "tmux.h"
@@ -142,6 +144,17 @@ systemd_move_pid_to_new_cgroup(pid_t pid, char **cause)
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
* "app-tmux.slice" if that fails.

View File

@@ -1,6 +1,6 @@
# configure.ac
AC_INIT([tmux], 3.4)
AC_INIT([tmux], 3.5)
AC_PREREQ([2.60])
AC_CONFIG_AUX_DIR(etc)
@@ -56,10 +56,11 @@ AC_USE_SYSTEM_EXTENSIONS
test "$sysconfdir" = '${prefix}/etc' && sysconfdir=/etc
# Is this --enable-debug?
case "x$VERSION" in xnext*) enable_debug=yes;; esac
AC_ARG_ENABLE(
debug,
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)
@@ -548,6 +549,24 @@ if test "x$found_malloc_trim" = xyes; then
AC_DEFINE(HAVE_MALLOC_TRIM)
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
# (_XOPEN_SOURCE and _XOPEN_SOURCE_EXTENDED) (see xopen_networking(7)). On
# others, UNIX 03 (_XOPEN_SOURCE 600, see standards(7) on Solaris).
@@ -926,8 +945,13 @@ case "$host_os" in
MANFORMAT=mdoc
;;
*)
# Solaris 2.0 to 11.3 use AT&T nroff.
MANFORMAT=man
if test `uname -o 2>/dev/null` = illumos; then
# Illumos uses mandoc.
MANFORMAT=mdoc
else
# Solaris 2.0 to 11.3 use AT&T nroff.
MANFORMAT=man
fi
;;
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());
}
#ifdef HAVE_SYSTEMD
environ_clear(env, "LISTEN_PID");
environ_clear(env, "LISTEN_FDS");
environ_clear(env, "LISTEN_FDNAMES");
#endif
if (s != NULL)
idx = s->id;
else

View File

@@ -14,7 +14,7 @@ set -g status-bg red
%endif
# 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
set -g default-terminal "tmux-256color"

View File

@@ -1136,8 +1136,7 @@ format_cb_mouse_word(struct format_tree *ft)
return (NULL);
if (!TAILQ_EMPTY(&wp->modes)) {
if (TAILQ_FIRST(&wp->modes)->mode == &window_copy_mode ||
TAILQ_FIRST(&wp->modes)->mode == &window_view_mode)
if (window_pane_mode(wp) != WINDOW_PANE_NO_MODE)
return (window_copy_get_word(wp, x, y));
return (NULL);
}
@@ -1181,8 +1180,7 @@ format_cb_mouse_line(struct format_tree *ft)
return (NULL);
if (!TAILQ_EMPTY(&wp->modes)) {
if (TAILQ_FIRST(&wp->modes)->mode == &window_copy_mode ||
TAILQ_FIRST(&wp->modes)->mode == &window_view_mode)
if (window_pane_mode(wp) != WINDOW_PANE_NO_MODE)
return (window_copy_get_line(wp, y));
return (NULL);
}
@@ -1962,6 +1960,23 @@ format_cb_pane_unseen_changes(struct format_tree *ft)
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. */
static void *
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,
format_cb_pane_input_off
},
{ "pane_key_mode", FORMAT_TABLE_STRING,
format_cb_pane_key_mode
},
{ "pane_last", FORMAT_TABLE_STRING,
format_cb_pane_last
},

View File

@@ -35,7 +35,7 @@ LLVMFuzzerTestOneInput(const u_char *data, size_t size)
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.
*/
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);
if ((gc->fg & COLOUR_FLAG_RGB) || (gc->bg & COLOUR_FLAG_RGB))
return (1);
if (gc->us != 0) /* only supports 256 or RGB */
if (gc->us != 8) /* only supports 256 or RGB */
return (1);
if (gc->link != 0)
return (1);

View File

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

View File

@@ -307,20 +307,6 @@ static struct input_key_entry input_key_defaults[] = {
{ .key = KEYC_DC|KEYC_BUILD_MODIFIERS,
.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[] = {
0,
@@ -426,126 +412,18 @@ input_key_write(const char *from, struct bufferevent *bev, const char *data,
bufferevent_write(bev, data, size);
}
/* Translate a key code into an output key sequence. */
int
input_key(struct screen *s, struct bufferevent *bev, key_code key)
/*
* Encode and write an extended key escape sequence in one of the two
* 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;
key_code justkey, newkey, outkey, modifiers;
struct utf8_data ud;
char tmp[64], modifier;
char tmp[64], modifier;
struct utf8_data ud;
wchar_t wc;
/* 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));
}
/*
* 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) {
switch (key & KEYC_MASK_MODIFIERS) {
case KEYC_SHIFT:
modifier = '2';
break;
@@ -568,17 +446,247 @@ input_key(struct screen *s, struct bufferevent *bev, key_code key)
modifier = '8';
break;
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));
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);
}
/* 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. */
int
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 ch;
int last;
struct utf8_data last;
int flags;
#define INPUT_DISCARD 0x1
#define INPUT_LAST 0x2
const struct input_state *state;
@@ -867,8 +868,6 @@ input_reset(struct input_ctx *ictx, int clear)
input_clear(ictx);
ictx->last = -1;
ictx->state = &input_state_ground;
ictx->flags = 0;
}
@@ -1149,7 +1148,9 @@ input_print(struct input_ctx *ictx)
utf8_set(&ictx->cell.cell.data, ictx->ch);
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;
@@ -1261,7 +1262,7 @@ input_c0_dispatch(struct input_ctx *ictx)
break;
}
ictx->last = -1;
ictx->flags &= ~INPUT_LAST;
return (0);
}
@@ -1337,7 +1338,7 @@ input_esc_dispatch(struct input_ctx *ictx)
break;
}
ictx->last = -1;
ictx->flags &= ~INPUT_LAST;
return (0);
}
@@ -1348,7 +1349,7 @@ input_csi_dispatch(struct input_ctx *ictx)
struct screen_write_ctx *sctx = &ictx->ctx;
struct screen *s = sctx->s;
struct input_table_entry *entry;
int i, n, m;
int i, n, m, ek;
u_int cx, bg = ictx->cell.cell.bg;
if (ictx->flags & INPUT_DISCARD)
@@ -1406,18 +1407,36 @@ input_csi_dispatch(struct input_ctx *ictx)
break;
case INPUT_CSI_MODSET:
n = input_get(ictx, 0, 0, 0);
m = input_get(ictx, 1, 0, 0);
if (options_get_number(global_options, "extended-keys") == 2)
if (n != 4)
break;
if (n == 0 || (n == 4 && m == 0))
screen_write_mode_clear(sctx, MODE_KEXTENDED);
else if (n == 4 && (m == 1 || m == 2))
screen_write_mode_set(sctx, MODE_KEXTENDED);
m = input_get(ictx, 1, 0, 0);
/*
* 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;
case INPUT_CSI_MODOFF:
n = input_get(ictx, 0, 0, 0);
if (n == 4)
screen_write_mode_clear(sctx, MODE_KEXTENDED);
if (n != 4)
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;
case INPUT_CSI_WINOPS:
input_csi_dispatch_winops(ictx);
@@ -1574,12 +1593,12 @@ input_csi_dispatch(struct input_ctx *ictx)
if (n > m)
n = m;
if (ictx->last == -1)
if (~ictx->flags & INPUT_LAST)
break;
ictx->ch = ictx->last;
utf8_copy(&ictx->cell.cell.data, &ictx->last);
for (i = 0; i < n; i++)
input_print(ictx);
screen_write_collect_add(sctx, &ictx->cell.cell);
break;
case INPUT_CSI_RCP:
input_restore_state(ictx);
@@ -1649,7 +1668,7 @@ input_csi_dispatch(struct input_ctx *ictx)
}
ictx->last = -1;
ictx->flags &= ~INPUT_LAST;
return (0);
}
@@ -1839,7 +1858,7 @@ input_csi_dispatch_sm_private(struct input_ctx *ictx)
/* Handle CSI graphics SM. */
static void
input_csi_dispatch_sm_graphics(struct input_ctx *ictx)
input_csi_dispatch_sm_graphics(__unused struct input_ctx *ictx)
{
#ifdef ENABLE_SIXEL
int n, m, o;
@@ -2284,7 +2303,7 @@ input_enter_dcs(struct input_ctx *ictx)
input_clear(ictx);
input_start_timer(ictx);
ictx->last = -1;
ictx->flags &= ~INPUT_LAST;
}
/* DCS terminator (ST) received. */
@@ -2341,7 +2360,7 @@ input_enter_osc(struct input_ctx *ictx)
input_clear(ictx);
input_start_timer(ictx);
ictx->last = -1;
ictx->flags &= ~INPUT_LAST;
}
/* OSC terminator (ST) received. */
@@ -2372,7 +2391,9 @@ input_exit_osc(struct input_ctx *ictx)
switch (option) {
case 0:
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);
server_redraw_window_borders(wp->window);
server_status_window(wp->window);
@@ -2434,7 +2455,7 @@ input_enter_apc(struct input_ctx *ictx)
input_clear(ictx);
input_start_timer(ictx);
ictx->last = -1;
ictx->flags &= ~INPUT_LAST;
}
/* APC terminator (ST) received. */
@@ -2463,7 +2484,7 @@ input_enter_rename(struct input_ctx *ictx)
input_clear(ictx);
input_start_timer(ictx);
ictx->last = -1;
ictx->flags &= ~INPUT_LAST;
}
/* Rename terminator (ST) received. */
@@ -2507,7 +2528,7 @@ input_top_bit_set(struct input_ctx *ictx)
struct screen_write_ctx *sctx = &ictx->ctx;
struct utf8_data *ud = &ictx->utf8data;
ictx->last = -1;
ictx->flags &= ~INPUT_LAST;
if (!ictx->utf8started) {
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);
screen_write_collect_add(sctx, &ictx->cell.cell);
utf8_copy(&ictx->last, &ictx->cell.cell.data);
ictx->flags |= INPUT_LAST;
return (0);
}
@@ -2681,6 +2705,44 @@ input_get_bg_client(struct window_pane *wp)
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. */
static void
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 (wp == NULL)
return;
tty_default_colours(&defaults, wp);
if (COLOUR_DEFAULT(defaults.fg))
c = input_get_fg_client(wp);
else
c = defaults.fg;
c = input_get_fg_control_client(wp);
if (c == -1) {
tty_default_colours(&defaults, wp);
if (COLOUR_DEFAULT(defaults.fg))
c = input_get_fg_client(wp);
else
c = defaults.fg;
}
input_osc_colour_reply(ictx, 10, c);
return;
}
@@ -2740,11 +2805,14 @@ input_osc_11(struct input_ctx *ictx, const char *p)
if (strcmp(p, "?") == 0) {
if (wp == NULL)
return;
tty_default_colours(&defaults, wp);
if (COLOUR_DEFAULT(defaults.bg))
c = input_get_bg_client(wp);
else
c = defaults.bg;
c = input_get_bg_control_client(wp);
if (c == -1) {
tty_default_colours(&defaults, wp);
if (COLOUR_DEFAULT(defaults.bg))
c = input_get_bg_client(wp);
else
c = defaults.bg;
}
input_osc_colour_reply(ictx, 11, c);
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;
pid_t pid;
int nullfd, out[2], master;
const char *home;
const char *home, *shell;
sigset_t set, oldset;
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
* if-shell to decide on default-terminal based on outside TERM.
* Do not set TERM during .tmux.conf (second argument here), it is nice
* to be able to use if-shell to decide on default-terminal based on
* outside TERM.
*/
env = environ_for_session(s, !cfg_finished);
if (e != NULL)
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);
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) {
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 {
log_debug("%s: cmd=%s, cwd=%s", __func__, cmd,
cwd == NULL ? "" : cwd);
log_debug("%s: cmd=%s, cwd=%s, shell=%s", __func__, cmd,
cwd == NULL ? "" : cwd, shell);
}
switch (pid) {
@@ -150,7 +160,8 @@ job_run(const char *cmd, int argc, char **argv, struct environ *e, struct sessio
closefrom(STDERR_FILENO + 1);
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");
} else {
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);
environ_free(env);
free(argv0);
job = xmalloc(sizeof *job);
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");
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);
fail:
sigprocmask(SIG_SETMASK, &oldset, NULL);
environ_free(env);
free(argv0);
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-vertical layout' M-4 { select-layout main-vertical }",
"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 '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 }",

View File

@@ -18,6 +18,7 @@
#include <sys/types.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
@@ -56,12 +57,47 @@ static const struct {
{ "PPage", KEYC_PPAGE|KEYC_IMPLIED_META },
{ "PageUp", KEYC_PPAGE|KEYC_IMPLIED_META },
{ "PgUp", KEYC_PPAGE|KEYC_IMPLIED_META },
{ "Tab", '\011' },
{ "BTab", KEYC_BTAB },
{ "Space", ' ' },
{ "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. */
{ "Up", KEYC_UP|KEYC_CURSOR|KEYC_IMPLIED_META },
@@ -206,8 +242,7 @@ key_string_get_modifiers(const char **string)
key_code
key_string_lookup_string(const char *string)
{
static const char *other = "!#()+,-.0123456789:;<=>'\r\t\177`/";
key_code key, modifiers;
key_code key, modifiers = 0;
u_int u, i;
struct utf8_data ud, *udp;
enum utf8_state more;
@@ -244,12 +279,15 @@ key_string_lookup_string(const char *string)
return (uc);
}
/* Check for modifiers. */
modifiers = 0;
/* Check for short Ctrl key. */
if (string[0] == '^' && string[1] != '\0') {
if (string[2] == '\0')
return (tolower((u_char)string[1])|KEYC_CTRL);
modifiers |= KEYC_CTRL;
string++;
}
/* Check for modifiers. */
modifiers |= key_string_get_modifiers(&string);
if (string == NULL || string[0] == '\0')
return (KEYC_UNKNOWN);
@@ -281,26 +319,6 @@ key_string_lookup_string(const char *string)
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);
}
@@ -324,10 +342,6 @@ key_string_lookup_key(key_code key, int with_flags)
goto out;
}
/* Display C-@ as C-Space. */
if ((key & (KEYC_MASK_KEY|KEYC_MASK_MODIFIERS)) == 0)
key = ' '|KEYC_CTRL;
/* Fill in the modifiers. */
if (key & KEYC_CTRL)
strlcat(out, "C-", sizeof out);
@@ -396,7 +410,7 @@ key_string_lookup_key(key_code key, int with_flags)
s = "MouseMoveBorder";
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));
strlcat(out, tmp, sizeof out);
goto out;
@@ -427,13 +441,8 @@ key_string_lookup_key(key_code key, int with_flags)
goto out;
}
/* Check for standard or control key. */
if (key <= 32) {
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) {
/* Printable ASCII keys. */
if (key > 32 && key <= 126) {
tmp[0] = key;
tmp[1] = '\0';
} else if (key == 127)
@@ -460,8 +469,6 @@ out:
strlcat(out, "I", sizeof out);
if (saved & KEYC_BUILD_MODIFIERS)
strlcat(out, "B", sizeof out);
if (saved & KEYC_EXTENDED)
strlcat(out, "E", sizeof out);
if (saved & KEYC_SENT)
strlcat(out, "S", 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. */
if (!layout_check(lc)) {
*cause = xstrdup("size mismatch after applying layout");
return (-1);
goto fail;
}
/* Resize to the layout size. */

View File

@@ -31,7 +31,9 @@
static void layout_set_even_h(struct window *);
static void layout_set_even_v(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_mirrored(struct window *);
static void layout_set_tiled(struct window *);
static const struct {
@@ -41,7 +43,9 @@ static const struct {
{ "even-horizontal", layout_set_even_h },
{ "even-vertical", layout_set_even_v },
{ "main-horizontal", layout_set_main_h },
{ "main-horizontal-mirrored", layout_set_main_h_mirrored },
{ "main-vertical", layout_set_main_v },
{ "main-vertical-mirrored", layout_set_main_v_mirrored },
{ "tiled", layout_set_tiled },
};
@@ -51,6 +55,10 @@ layout_set_lookup(const char *name)
u_int i;
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++) {
if (strncmp(layout_sets[i].name, name, strlen(name)) == 0) {
if (matched != -1) /* ambiguous */
@@ -279,6 +287,104 @@ layout_set_main_h(struct 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
layout_set_main_v(struct window *w)
{
@@ -377,6 +483,104 @@ layout_set_main_v(struct 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
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;
return (0);
case KEYC_PPAGE:
case '\002': /* C-b */
case 'b'|KEYC_CTRL:
if (md->choice < 6)
md->choice = 0;
else {
@@ -394,13 +394,13 @@ menu_key_cb(struct client *c, void *data, struct key_event *event)
}
c->flags |= CLIENT_REDRAWOVERLAY;
break;
case '\006': /* C-f */
case 'f'|KEYC_CTRL:
break;
case '\r':
goto chosen;
case '\033': /* Escape */
case '\003': /* C-c */
case '\007': /* C-g */
case 'c'|KEYC_CTRL:
case 'g'|KEYC_CTRL:
case 'q':
return (1);
}

View File

@@ -25,6 +25,11 @@
#include "tmux.h"
enum mode_tree_search_dir {
MODE_TREE_SEARCH_FORWARD,
MODE_TREE_SEARCH_BACKWARD
};
struct mode_tree_item;
TAILQ_HEAD(mode_tree_list, mode_tree_item);
@@ -68,6 +73,7 @@ struct mode_tree_data {
char *search;
char *filter;
int no_matches;
enum mode_tree_search_dir search_dir;
};
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)
{
if (mtd->current == mtd->line_size - 1) {
if (wrap) {
mtd->current = 0;
mtd->offset = 0;
}
} else
return (0);
} else {
mtd->current++;
if (mtd->current > mtd->offset + mtd->height - 1)
mtd->offset++;
}
return (1);
}
void *
@@ -786,7 +794,49 @@ done:
}
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;
@@ -832,7 +882,10 @@ mode_tree_search_set(struct mode_tree_data *mtd)
struct mode_tree_item *mti, *loop;
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)
return;
tag = mti->tag;
@@ -1035,22 +1088,22 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
switch (*key) {
case 'q':
case '\033': /* Escape */
case '\007': /* C-g */
case 'g'|KEYC_CTRL:
return (1);
case KEYC_UP:
case 'k':
case KEYC_WHEELUP_PANE:
case '\020': /* C-p */
case 'p'|KEYC_CTRL:
mode_tree_up(mtd, 1);
break;
case KEYC_DOWN:
case 'j':
case KEYC_WHEELDOWN_PANE:
case '\016': /* C-n */
case 'n'|KEYC_CTRL:
mode_tree_down(mtd, 1);
break;
case KEYC_PPAGE:
case '\002': /* C-b */
case 'b'|KEYC_CTRL:
for (i = 0; i < mtd->height; i++) {
if (mtd->current == 0)
break;
@@ -1058,7 +1111,7 @@ mode_tree_key(struct mode_tree_data *mtd, struct client *c, key_code *key,
}
break;
case KEYC_NPAGE:
case '\006': /* C-f */
case 'f'|KEYC_CTRL:
for (i = 0; i < mtd->height; i++) {
if (mtd->current == mtd->line_size - 1)
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++)
mtd->line_list[i].item->tagged = 0;
break;
case '\024': /* C-t */
case 't'|KEYC_CTRL:
for (i = 0; i < mtd->line_size; i++) {
if ((mtd->line_list[i].item->parent == NULL &&
!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;
case '?':
case '/':
case '\023': /* C-s */
case 's'|KEYC_CTRL:
mtd->references++;
status_prompt_set(c, NULL, "(search) ", "",
mode_tree_search_callback, mode_tree_search_free, mtd,
PROMPT_NOFORMAT, PROMPT_TYPE_SEARCH);
break;
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);
break;
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[] = {
"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[] = {
"off", "on", "all", NULL
};
@@ -285,7 +288,7 @@ const struct options_table_entry options_table[] = {
.scope = OPTIONS_TABLE_SERVER,
.minimum = 0,
.maximum = INT_MAX,
.default_num = 500,
.default_num = 10,
.unit = "milliseconds",
.text = "Time to wait before assuming a key is Escape."
},
@@ -314,6 +317,14 @@ const struct options_table_entry options_table[] = {
"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",
.type = OPTIONS_TABLE_FLAG,
.scope = OPTIONS_TABLE_SERVER,
@@ -374,6 +385,17 @@ const struct options_table_entry options_table[] = {
.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",
.type = OPTIONS_TABLE_NUMBER,
.scope = OPTIONS_TABLE_SERVER,
@@ -397,7 +419,7 @@ const struct options_table_entry options_table[] = {
.type = OPTIONS_TABLE_STRING,
.scope = OPTIONS_TABLE_SERVER,
.flags = OPTIONS_TABLE_IS_ARRAY,
.default_str = "",
.default_str = "linux*:AX@",
.separator = ",",
.text = "List of terminal capabilities overrides."
},
@@ -613,7 +635,7 @@ const struct options_table_entry options_table[] = {
{ .name = "prefix",
.type = OPTIONS_TABLE_KEY,
.scope = OPTIONS_TABLE_SESSION,
.default_num = '\002',
.default_num = 'b'|KEYC_CTRL,
.text = "The prefix key."
},
@@ -875,6 +897,14 @@ const struct options_table_entry options_table[] = {
"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",
.type = OPTIONS_TABLE_FLAG,
.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-resized", ""),
OPTIONS_TABLE_HOOK("client-session-changed", ""),
OPTIONS_TABLE_HOOK("command-error", ""),
OPTIONS_TABLE_PANE_HOOK("pane-died", ""),
OPTIONS_TABLE_PANE_HOOK("pane-exited", ""),
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)
{
struct options_array_item *a;
char *result = NULL;
char *last = NULL;
char *next;
if (OPTIONS_IS_ARRAY(o)) {
if (idx == -1)
return (xstrdup(""));
if (idx == -1) {
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);
if (a == NULL)
return (xstrdup(""));

View File

@@ -345,7 +345,7 @@ popup_make_pane(struct popup_data *pd, enum layout_type type)
u_int hlimit;
const char *shell;
window_unzoom(w);
window_unzoom(w, 1);
lc = layout_split_pane(wp, type, -1, 0);
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) ||
pd->job == NULL) &&
(event->key == '\033' || event->key == '\003'))
(event->key == '\033' || event->key == ('c'|KEYC_CTRL)))
return (1);
if (pd->job != NULL) {
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 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.
$TMUX send-keys -X next-word
$TMUX send-keys -X begin-selection
$TMUX send-keys -X next-word
$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.
$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 next-word
$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.
$TMUX send-keys -X previous-space
$TMUX send-keys -X begin-selection
$TMUX send-keys -X next-space
$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.
$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 next-word
$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
$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 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.
$TMUX send-keys -X next-word
$TMUX send-keys -X begin-selection
$TMUX send-keys -X next-word
$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.
$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 next-space
$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.
$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 next-space
$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
$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. */
zoomed = w->flags & WINDOW_ZOOMED;
if (zoomed)
window_unzoom(w);
window_unzoom(w, 1);
/* Resize the layout first. */
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. */
static enum screen_redraw_border_type
screen_redraw_pane_border(struct window_pane *wp, u_int px, u_int py,
int pane_status)
screen_redraw_pane_border(struct screen_redraw_ctx *ctx, struct window_pane *wp,
u_int px, u_int py)
{
struct options *oo = wp->window->options;
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. */
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. */
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_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) {
if (!window_pane_visible(wp))
continue;
switch (screen_redraw_pane_border(wp, px, py, pane_status)) {
switch (screen_redraw_pane_border(ctx, wp, px, py)) {
case SCREEN_REDRAW_INSIDE:
return (0);
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. */
static int
screen_redraw_type_of_cell(struct client *c, u_int px, u_int py,
int pane_status)
screen_redraw_type_of_cell(struct screen_redraw_ctx *ctx, u_int px, u_int py)
{
struct client *c = ctx->c;
int pane_status = ctx->pane_status;
struct window *w = c->session->curw->window;
u_int sx = w->sx, sy = w->sy;
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,
* 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;
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;
if (pane_status == PANE_STATUS_TOP) {
if (py != 0 &&
screen_redraw_cell_border(c, px, py - 1, pane_status))
screen_redraw_cell_border(ctx, px, py - 1))
borders |= 2;
if (screen_redraw_cell_border(c, px, py + 1, pane_status))
if (screen_redraw_cell_border(ctx, px, py + 1))
borders |= 1;
} else if (pane_status == PANE_STATUS_BOTTOM) {
if (py == 0 ||
screen_redraw_cell_border(c, px, py - 1, pane_status))
screen_redraw_cell_border(ctx, px, py - 1))
borders |= 2;
if (py != sy - 1 &&
screen_redraw_cell_border(c, px, py + 1, pane_status))
screen_redraw_cell_border(ctx, px, py + 1))
borders |= 1;
} else {
if (py == 0 ||
screen_redraw_cell_border(c, px, py - 1, pane_status))
screen_redraw_cell_border(ctx, px, py - 1))
borders |= 2;
if (screen_redraw_cell_border(c, px, py + 1, pane_status))
if (screen_redraw_cell_border(ctx, px, py + 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. */
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 client *c = ctx->c;
struct window *w = c->session->curw->window;
struct window_pane *wp, *active;
int pane_status = ctx->pane_status;
int border;
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)
return (CELL_OUTSIDE);
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) {
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.
* 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)
return (CELL_INSIDE);
if (border == SCREEN_REDRAW_OUTSIDE)
goto next2;
return (screen_redraw_type_of_cell(c, px, py, pane_status));
return (screen_redraw_type_of_cell(ctx, px, py));
next2:
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. */
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)
{
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)
return (1);
return (0);
@@ -409,11 +414,11 @@ screen_redraw_make_pane_status(struct client *c, struct window_pane *wp,
for (i = 0; i < width; i++) {
px = wp->xoff + 2 + i;
if (rctx->pane_status == PANE_STATUS_TOP)
if (pane_status == PANE_STATUS_TOP)
py = wp->yoff - 1;
else
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_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. */
static int
screen_redraw_update(struct client *c, int flags)
static uint64_t
screen_redraw_update(struct client *c, uint64_t flags)
{
struct window *w = c->session->curw->window;
struct window_pane *wp;
@@ -567,7 +572,7 @@ void
screen_redraw_screen(struct client *c)
{
struct screen_redraw_ctx ctx;
int flags;
uint64_t flags;
if (c->flags & CLIENT_SUSPENDED)
return;
@@ -638,7 +643,7 @@ screen_redraw_draw_borders_style(struct screen_redraw_ctx *ctx, u_int x,
wp->border_gc_set = 1;
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);
else
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;
u_int cell_type, x = ctx->ox + i, y = ctx->oy + j;
int arrows = 0, border;
int pane_status = ctx->pane_status, isolates;
int isolates;
if (c->overlay_check != NULL) {
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;
}
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)
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);
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;
}
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) {
border = screen_redraw_pane_border(active, x, y, pane_status);
border = screen_redraw_pane_border(ctx, active, x, y);
if (((i == wp->xoff + 1 &&
(cell_type == CELL_LEFTRIGHT ||
(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) ||
(cell_type == CELL_RIGHTJOIN &&
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;
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 window *w = s->curw->window;
struct window_pane *wp;
u_int i, j;
u_int i, j;
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);
s->mode = MODE_CURSOR|MODE_WRAP;
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_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. */
grid_view_set_cell(gd, cx - n, cy, &last);
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
@@ -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);
sixel_free(si);
si = new;
/* Bail out if the image cannot be scaled. */
if (si == NULL)
return;
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->mode = MODE_CURSOR|MODE_WRAP|(s->mode & MODE_CRLF);
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)
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))
screen_resize_y(s, sy, eat_empty, &cy);
if (reflow) {
#ifdef ENABLE_SIXEL
image_free_all(s);
image_free_all(s);
#endif
if (reflow)
screen_reflow(s, sx, &cx, &cy, cursor);
}
if (cy >= s->grid->hsize) {
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
* is is enabled.
* it is enabled.
*/
available = gd->hscrolled;
if (gd->flags & GRID_HISTORY && available > 0) {
@@ -730,8 +731,10 @@ screen_mode_to_string(int mode)
strlcat(tmp, "ORIGIN,", sizeof tmp);
if (mode & MODE_CRLF)
strlcat(tmp, "CRLF,", sizeof tmp);
if (mode & MODE_KEXTENDED)
strlcat(tmp, "KEXTENDED,", sizeof tmp);
if (mode & MODE_KEYS_EXTENDED)
strlcat(tmp, "KEYS_EXTENDED,", sizeof tmp);
if (mode & MODE_KEYS_EXTENDED_2)
strlcat(tmp, "KEYS_EXTENDED_2,", sizeof tmp);
tmp[strlen(tmp) - 1] = '\0';
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);
c->keytable = key_bindings_get_table(name, 1);
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. */
@@ -622,6 +633,8 @@ server_client_check_mouse(struct client *c, struct key_event *event)
} else if (MOUSE_RELEASE(m->b)) {
type = UP;
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);
} else {
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);
goto have_event;
}
} else {
}
/* DOWN is the only remaining event type. */
if (type == NOTYPE) {
type = DOWN;
x = m->x, y = m->y, b = m->b;
log_debug("down at %u,%u", x, y);
@@ -774,8 +790,7 @@ have_event:
log_debug("mouse on pane %%%u border", wp->id);
m->wp = wp->id;
m->w = wp->window->id;
} else
m->wp = -1;
}
/* Stop dragging if needed. */
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 key_table *table, *first;
struct key_binding *bd;
int xtimeout, flags;
int xtimeout;
uint64_t flags, prefix_delay;
struct cmd_find_state fs;
key_code key0, prefix, prefix2;
@@ -1956,8 +1972,34 @@ try_again:
if (c->flags & CLIENT_REPEAT)
log_debug("currently repeating");
/* Try to see if there is a key binding in the current table. */
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) {
/*
* 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.
*/
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 window *w = c->session->curw->window;
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;
u_int bit = 0;
struct timeval tv = { .tv_usec = 1000 };
@@ -2594,7 +2649,7 @@ server_client_check_redraw(struct client *c)
}
}
if (needed)
new_flags |= CLIENT_REDRAWPANES;
client_flags |= CLIENT_REDRAWPANES;
}
if (needed && (left = EVBUFFER_LENGTH(tty->out)) != 0) {
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
* just redraw the window.
*/
new_flags &= CLIENT_REDRAWPANES;
new_flags |= CLIENT_REDRAWWINDOW;
client_flags &= CLIENT_REDRAWPANES;
client_flags |= CLIENT_REDRAWWINDOW;
break;
}
}
if (c->redraw_panes != 0)
c->flags |= CLIENT_REDRAWPANES;
}
c->flags |= new_flags;
c->flags |= client_flags;
return;
} else if (needed)
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;
if (~c->flags & CLIENT_REDRAWWINDOW) {
@@ -2662,9 +2717,10 @@ server_client_check_redraw(struct client *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->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);

View File

@@ -411,7 +411,7 @@ server_find_session(struct session *s,
static int
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
@@ -488,6 +488,6 @@ server_check_unattached(void)
void
server_unzoom_window(struct window *w)
{
if (window_unzoom(w) == 0)
if (window_unzoom(w, 1) == 0)
server_redraw_window(w);
}

View File

@@ -103,7 +103,7 @@ server_check_marked(void)
/* Create server socket. */
int
server_create_socket(int flags, char **cause)
server_create_socket(uint64_t flags, char **cause)
{
struct sockaddr_un sa;
size_t size;
@@ -172,7 +172,7 @@ server_tidy_event(__unused int fd, __unused short events, __unused void *data)
/* Fork new server. */
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 fd;
@@ -264,7 +264,7 @@ server_loop(void)
struct client *c;
u_int items;
current_time = time (NULL);
current_time = time(NULL);
do {
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;
char *tmp;
server_client_clear_overlay(c);
if (fs != NULL)
ft = format_create_from_state(NULL, c, fs);
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) {
switch (key) {
case '\001': /* C-a */
case '\003': /* C-c */
case '\005': /* C-e */
case '\007': /* C-g */
case '\010': /* C-h */
case 'a'|KEYC_CTRL:
case 'c'|KEYC_CTRL:
case 'e'|KEYC_CTRL:
case 'g'|KEYC_CTRL:
case 'h'|KEYC_CTRL:
case '\011': /* Tab */
case '\013': /* C-k */
case '\016': /* C-n */
case '\020': /* C-p */
case '\024': /* C-t */
case '\025': /* C-u */
case '\027': /* C-w */
case '\031': /* C-y */
case 'k'|KEYC_CTRL:
case 'n'|KEYC_CTRL:
case 'p'|KEYC_CTRL:
case 't'|KEYC_CTRL:
case 'u'|KEYC_CTRL:
case 'w'|KEYC_CTRL:
case 'y'|KEYC_CTRL:
case '\n':
case '\r':
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':
c->prompt_mode = PROMPT_ENTRY;
c->flags |= CLIENT_REDRAWSTATUS;
*new_key = '\025'; /* C-u */
*new_key = 'u'|KEYC_CTRL;
return (1);
case 'i':
case '\033': /* Escape */
@@ -911,7 +913,7 @@ status_prompt_translate_key(struct client *c, key_code key, key_code *new_key)
return (1);
case 'C':
case 'D':
*new_key = '\013'; /* C-k */
*new_key = 'k'|KEYC_CTRL;
return (1);
case KEYC_BSPACE:
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;
return (1);
case 'd':
*new_key = '\025'; /* C-u */
*new_key = 'u'|KEYC_CTRL;
return (1);
case 'e':
*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;
return (1);
case 'p':
*new_key = '\031'; /* C-y */
*new_key = 'y'|KEYC_CTRL;
return (1);
case 'q':
*new_key = '\003'; /* C-c */
*new_key = 'c'|KEYC_CTRL;
return (1);
case 's':
case KEYC_DC:
@@ -966,8 +968,8 @@ status_prompt_translate_key(struct client *c, key_code key, key_code *new_key)
case 'k':
*new_key = KEYC_UP;
return (1);
case '\010' /* C-h */:
case '\003' /* C-c */:
case 'h'|KEYC_CTRL:
case 'c'|KEYC_CTRL:
case '\n':
case '\r':
return (1);
@@ -994,8 +996,7 @@ status_prompt_paste(struct client *c)
if ((pb = paste_get_top(NULL)) == NULL)
return (0);
bufdata = paste_buffer_data(pb, &bufsize);
ud = xreallocarray(NULL, bufsize + 1, sizeof *ud);
udp = ud;
ud = udp = xreallocarray(NULL, bufsize + 1, sizeof *ud);
for (i = 0; i != bufsize; /* nothing */) {
more = utf8_open(udp, bufdata[i]);
if (more == UTF8_MORE) {
@@ -1016,25 +1017,24 @@ status_prompt_paste(struct client *c)
udp->size = 0;
n = udp - ud;
}
if (n == 0)
return (0);
c->prompt_buffer = xreallocarray(c->prompt_buffer, size + n + 1,
sizeof *c->prompt_buffer);
if (c->prompt_index == size) {
memcpy(c->prompt_buffer + c->prompt_index, ud,
n * sizeof *c->prompt_buffer);
c->prompt_index += n;
c->prompt_buffer[c->prompt_index].size = 0;
} else {
memmove(c->prompt_buffer + c->prompt_index + n,
c->prompt_buffer + c->prompt_index,
(size + 1 - c->prompt_index) * sizeof *c->prompt_buffer);
memcpy(c->prompt_buffer + c->prompt_index, ud,
n * sizeof *c->prompt_buffer);
c->prompt_index += n;
if (n != 0) {
c->prompt_buffer = xreallocarray(c->prompt_buffer, size + n + 1,
sizeof *c->prompt_buffer);
if (c->prompt_index == size) {
memcpy(c->prompt_buffer + c->prompt_index, ud,
n * sizeof *c->prompt_buffer);
c->prompt_index += n;
c->prompt_buffer[c->prompt_index].size = 0;
} else {
memmove(c->prompt_buffer + c->prompt_index + n,
c->prompt_buffer + c->prompt_index,
(size + 1 - c->prompt_index) *
sizeof *c->prompt_buffer);
memcpy(c->prompt_buffer + c->prompt_index, ud,
n * sizeof *c->prompt_buffer);
c->prompt_index += n;
}
}
if (ud != c->prompt_saved)
free(ud);
return (1);
@@ -1265,28 +1265,28 @@ status_prompt_key(struct client *c, key_code key)
process_key:
switch (key) {
case KEYC_LEFT:
case '\002': /* C-b */
case 'b'|KEYC_CTRL:
if (c->prompt_index > 0) {
c->prompt_index--;
break;
}
break;
case KEYC_RIGHT:
case '\006': /* C-f */
case 'f'|KEYC_CTRL:
if (c->prompt_index < size) {
c->prompt_index++;
break;
}
break;
case KEYC_HOME:
case '\001': /* C-a */
case 'a'|KEYC_CTRL:
if (c->prompt_index != 0) {
c->prompt_index = 0;
break;
}
break;
case KEYC_END:
case '\005': /* C-e */
case 'e'|KEYC_CTRL:
if (c->prompt_index != size) {
c->prompt_index = size;
break;
@@ -1297,7 +1297,7 @@ process_key:
goto changed;
break;
case KEYC_BSPACE:
case '\010': /* C-h */
case 'h'|KEYC_CTRL:
if (c->prompt_index != 0) {
if (c->prompt_index == size)
c->prompt_buffer[--c->prompt_index].size = 0;
@@ -1312,7 +1312,7 @@ process_key:
}
break;
case KEYC_DC:
case '\004': /* C-d */
case 'd'|KEYC_CTRL:
if (c->prompt_index != size) {
memmove(c->prompt_buffer + c->prompt_index,
c->prompt_buffer + c->prompt_index + 1,
@@ -1321,17 +1321,17 @@ process_key:
goto changed;
}
break;
case '\025': /* C-u */
case 'u'|KEYC_CTRL:
c->prompt_buffer[0].size = 0;
c->prompt_index = 0;
goto changed;
case '\013': /* C-k */
case 'k'|KEYC_CTRL:
if (c->prompt_index < size) {
c->prompt_buffer[c->prompt_index].size = 0;
goto changed;
}
break;
case '\027': /* C-w */
case 'w'|KEYC_CTRL:
separators = options_get_string(oo, "word-separators");
idx = c->prompt_index;
@@ -1399,7 +1399,7 @@ process_key:
status_prompt_backward_word(c, separators);
goto changed;
case KEYC_UP:
case '\020': /* C-p */
case 'p'|KEYC_CTRL:
histstr = status_prompt_up_history(c->prompt_hindex,
c->prompt_type);
if (histstr == NULL)
@@ -1409,7 +1409,7 @@ process_key:
c->prompt_index = utf8_strlen(c->prompt_buffer);
goto changed;
case KEYC_DOWN:
case '\016': /* C-n */
case 'n'|KEYC_CTRL:
histstr = status_prompt_down_history(c->prompt_hindex,
c->prompt_type);
if (histstr == NULL)
@@ -1418,11 +1418,11 @@ process_key:
c->prompt_buffer = utf8_fromcstr(histstr);
c->prompt_index = utf8_strlen(c->prompt_buffer);
goto changed;
case '\031': /* C-y */
case 'y'|KEYC_CTRL:
if (status_prompt_paste(c))
goto changed;
break;
case '\024': /* C-t */
case 't'|KEYC_CTRL:
idx = c->prompt_index;
if (idx < size)
idx++;
@@ -1445,12 +1445,12 @@ process_key:
free(s);
break;
case '\033': /* Escape */
case '\003': /* C-c */
case '\007': /* C-g */
case 'c'|KEYC_CTRL:
case 'g'|KEYC_CTRL:
if (c->prompt_inputcb(c, c->prompt_data, NULL, 1) == 0)
status_prompt_clear(c);
break;
case '\022': /* C-r */
case 'r'|KEYC_CTRL:
if (~c->prompt_flags & PROMPT_INCREMENTAL)
break;
if (c->prompt_buffer[0].size == 0) {
@@ -1461,7 +1461,7 @@ process_key:
} else
prefix = '-';
goto changed;
case '\023': /* C-s */
case 's'|KEYC_CTRL:
if (~c->prompt_flags & PROMPT_INCREMENTAL)
break;
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_array_item *a;
const char *layouts[] = {
"even-horizontal", "even-vertical", "main-horizontal",
"main-vertical", "tiled", NULL
"even-horizontal", "even-vertical",
"main-horizontal", "main-horizontal-mirrored",
"main-vertical", "main-vertical-mirrored", "tiled", NULL
};
*size = 0;
@@ -1839,6 +1840,7 @@ status_prompt_complete_window_menu(struct client *c, struct session *s,
}
if (size == 0) {
menu_free(menu);
free(spm);
return (NULL);
}
if (size == 1) {
@@ -1849,6 +1851,7 @@ status_prompt_complete_window_menu(struct client *c, struct session *s,
} else
tmp = list[0];
free(list);
free(spm);
return (tmp);
}
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)
{
struct style saved;
const char delimiters[] = " ,\n", *cp;
const char delimiters[] = " ,\n", *errstr;
char tmp[256], *found;
int value;
size_t end;
u_int n;
if (*in == '\0')
return (0);
@@ -137,34 +138,31 @@ style_parse(struct style *sy, const struct grid_cell *base, const char *in)
goto error;
if (*found != '%' || found[1] == '\0')
goto error;
for (cp = found + 1; *cp != '\0'; cp++) {
if (!isdigit((u_char)*cp))
goto error;
}
n = strtonum(found + 1, 0, UINT_MAX, &errstr);
if (errstr != NULL)
goto error;
sy->range_type = STYLE_RANGE_PANE;
sy->range_argument = atoi(found + 1);
sy->range_argument = n;
style_set_range_string(sy, "");
} else if (strcasecmp(tmp + 6, "window") == 0) {
if (found == NULL)
goto error;
for (cp = found; *cp != '\0'; cp++) {
if (!isdigit((u_char)*cp))
goto error;
}
n = strtonum(found, 0, UINT_MAX, &errstr);
if (errstr != NULL)
goto error;
sy->range_type = STYLE_RANGE_WINDOW;
sy->range_argument = atoi(found);
sy->range_argument = n;
style_set_range_string(sy, "");
} else if (strcasecmp(tmp + 6, "session") == 0) {
if (found == NULL)
goto error;
if (*found != '$' || found[1] == '\0')
goto error;
for (cp = found + 1; *cp != '\0'; cp++) {
if (!isdigit((u_char)*cp))
goto error;
}
n = strtonum(found + 1, 0, UINT_MAX, &errstr);
if (errstr != NULL)
goto error;
sy->range_type = STYLE_RANGE_SESSION;
sy->range_argument = atoi(found + 1);
sy->range_argument = n;
style_set_range_string(sy, "");
} else if (strcasecmp(tmp + 6, "user") == 0) {
if (found == NULL)

472
tmux.1
View File

@@ -140,10 +140,9 @@ By default,
loads the system configuration file from
.Pa @SYSCONFDIR@/tmux.conf ,
if present, then looks for a user configuration file at
.Pa \[ti]/.tmux.conf,
.Pa $XDG_CONFIG_HOME/tmux/tmux.conf
.Pa \[ti]/.tmux.conf
or
.Pa \[ti]/.tmux.conf .
.Pa $XDG_CONFIG_HOME/tmux/tmux.conf .
.Pp
The configuration file is a set of
.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
pane.
.It M-1 to M-5
Arrange panes in one of the five preset layouts: even-horizontal,
even-vertical, main-horizontal, main-vertical, or tiled.
Arrange panes in one of the seven preset layouts:
even-horizontal, even-vertical,
main-horizontal, main-horizontal-mirrored,
main-vertical, main-vertical, or tiled.
.It Space
Arrange the current window in the next preset layout.
.It M-n
@@ -1039,9 +1040,17 @@ The following commands are available to manage clients and sessions:
.D1 Pq alias: Ic attach
If run from outside
.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 .
If used from inside, switch the current client.
If
.Fl d
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 f Ar flags
.Op Fl l Op Ar target-pane
.Op Fl r Ar pane:report
.Op Fl t Ar target-client
.Op Ar adjustment
.Xc
@@ -1462,6 +1472,12 @@ for all windows in the attached session.
.Fl f
sets a comma-separated list of client flags, see
.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
.Fl l
requests the clipboard from the client using the
@@ -1798,6 +1814,23 @@ is used to name the new paste buffer.
.Xc
Copy from the cursor position and exit copy mode.
.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
.Op Ar prefix
.Xc
@@ -1808,11 +1841,60 @@ Copy the entire line.
.Xc
Copy the entire line and exit copy mode.
.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
.Op Ar prefix
.Xc
Copies the current selection.
.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
.Op Ar prefix
(vi: Enter)
@@ -1826,6 +1908,12 @@ Copy the current selection and exit copy mode.
.Xc
Move the cursor down.
.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
(vi: h)
(emacs: Left)
@@ -1857,6 +1945,24 @@ Move the cursor to the end of the line.
.Xc
Move the cursor to a specific line.
.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
(vi: G)
(emacs: M->)
@@ -1889,6 +1995,27 @@ Jump backwards to the specified text.
.Xc
Jump forward to the specified text.
.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
(vi: M-x)
(emacs: M-x)
@@ -1923,18 +2050,71 @@ Move to the next prompt.
.Xc
Move to the next word.
.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
(vi: C-f)
(emacs: PageDown)
.Xc
Scroll down by one page.
.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
(vi: C-b)
(emacs: PageUp)
.Xc
Scroll up by one page.
.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
(emacs: M-C-b)
.Xc
@@ -1957,6 +2137,21 @@ Move to the previous prompt.
.Xc
Move to the previous word.
.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
(vi: v)
(emacs: R)
@@ -1969,6 +2164,40 @@ Toggle rectangle selection mode.
.Xc
Refresh the content from the pane.
.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
(vi: n)
(emacs: n)
@@ -1981,12 +2210,51 @@ Repeat the last search.
.Xc
Search backwards for the specified text.
.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
.Ar text
(vi: /)
.Xc
Search forward for the specified text.
.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
(vi: V)
.Xc
@@ -1996,12 +2264,28 @@ Select the current line.
.Xc
Select the current word.
.It Xo
.Ic set-mark
(vi: X)
(emacs: X)
.Xc
Mark the current line.
.It Xo
.Ic start-of-line
(vi: 0)
(emacs: C-a)
.Xc
Move the cursor to the start of the line.
.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
(vi: H)
(emacs: M-R)
@@ -2094,14 +2378,15 @@ The synopsis for the
command is:
.Bl -tag -width Ds
.It Xo Ic copy-mode
.Op Fl eHMqu
.Op Fl deHMqu
.Op Fl s Ar src-pane
.Op Fl t Ar target-pane
.Xc
Enter copy mode.
The
.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
begins a mouse drag (only valid if bound to a mouse key binding, see
.Sx MOUSE SUPPORT ) .
@@ -2124,6 +2409,7 @@ This is intended to allow fast scrolling through a pane's history, for
example with:
.Bd -literal -offset indent
bind PageUp copy-mode -eu
bind PageDown copy-mode -ed
.Ed
.El
.Pp
@@ -2150,14 +2436,20 @@ are spread from left to right in the leftover space at the bottom.
Use the
.Em main-pane-height
window option to specify the height of the top pane.
.It Ic main-vertical
Similar to
.It Ic main-horizontal-mirrored
The same as
.Ic main-horizontal
but the large pane is placed on the left and the others spread from top to
bottom along the right.
See the
but mirrored so the main pane is at the bottom of the window.
.It Ic main-vertical
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
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
Panes are spread out as evenly as possible over the window in both rows and
columns.
@@ -2290,7 +2582,8 @@ The following keys may be used in client mode:
.It Li "Up" Ta "Select previous client"
.It Li "Down" Ta "Select next client"
.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 "Tag no 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 "m" Ta "Set 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 "Tag no 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 tagged options and unbind tagged keys"
.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 "Tag no 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
.Ic bind-key
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
Set the default terminal for new windows created in this session - the
default value of the
@@ -3731,16 +4030,11 @@ be set to
.Ql screen ,
.Ql tmux
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
Set the time in milliseconds for which
.Nm
waits after an escape is input to determine if it is part of a function or meta
key sequences.
The default is 500 milliseconds.
.It Ic editor Ar shell-command
Set the command used when
.Nm
@@ -3757,22 +4051,54 @@ If enabled, the server will exit when there are no attached clients.
.It Xo Ic extended-keys
.Op Ic on | off | always
.Xc
When
.Ic on
or
.Ic always ,
the escape sequence to enable extended keys is sent to the terminal, if
.Nm
knows that it is supported.
.Nm
always recognises extended keys itself.
If this option is
Controls how modified keys (keys pressed together with Control, Meta, or Shift)
are reported.
This is the equivalent of the
.Ic modifyOtherKeys
.Xr xterm 1
resource.
.Pp
When set to
.Ic on ,
.Nm
will only forward extended keys to applications when they request them; if
the program inside the pane can request one of two modes: mode 1 which changes
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 ,
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
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
.Op Ic on | off
.Xc
@@ -4036,10 +4362,12 @@ If
(the default), leave the session orphaned.
If
.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
.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
.Op Ic off | on | no-detached | previous | next
.Xc
@@ -4173,6 +4501,13 @@ Like
.Ic prefix2
can be set to
.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
.Op Ic on | off
.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-width Ar width
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
.Ic main-vertical
.Ic main-vertical-mirrored
layouts.
If suffixed by
.Ql % ,
@@ -4514,7 +4851,9 @@ An interval of zero disables the monitoring.
.It Ic other-pane-height Ar height
Set the height of the other panes (not the main pane) in the
.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 both the
.Ic main-pane-height
@@ -4531,7 +4870,9 @@ Like
.Ic other-pane-height ,
but set the width of other panes in the
.Ic main-vertical
layout.
and
.Ic main-vertical-mirrored
layouts.
.Pp
.It Ic pane-active-border-style Ar style
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
sequence (\eek...\ee\e\e).
.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
.Op Ic on | off
.Xc
@@ -4871,6 +5218,14 @@ layout after every
set-hook -g after-split-window "selectl even-vertical"
.Ed
.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
.Sx CONTROL MODE
section are hooks (without any arguments), except
@@ -4903,6 +5258,8 @@ Run when focus exits a client
Run when a client is resized.
.It client-session-changed
Run when a client's attached session is changed.
.It command-error
Run when a command fails.
.It pane-died
Run when the program running in a pane exits, but
.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_usage" Ta "" Ta "Command usage if listing commands"
.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_word" Ta "" Ta "Word under cursor 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_index" Ta "#P" Ta "Index of pane"
.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_left" Ta "" Ta "Left of 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_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 "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_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"
@@ -6111,7 +6472,7 @@ the default is
.Ql y .
.Tg menu
.It Xo Ic display-menu
.Op Fl O
.Op Fl OM
.Op Fl b Ar border-lines
.Op Fl c Ar target-client
.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
must be clicked to choose an item.
.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
.It Sy "Key" Ta Sy "Function"
.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 "Down" Ta "Select next buffer"
.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 "Tag no 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.
If
.Ar template
is not given, "paste-buffer -b \[aq]%%\[aq]" is used.
is not given, "paste-buffer -p -b \[aq]%%\[aq]" is used.
.Pp
.Fl O
specifies the initial sort field: one of
@@ -6533,6 +6901,11 @@ is given, the buffer is also sent to the clipboard for
using the
.Xr xterm 1
escape sequence, if possible.
If
.Ar path
is
.Ql - ,
the contents are read from stdin.
.Tg pasteb
.It Xo Ic paste-buffer
.Op Fl dpr
@@ -6570,6 +6943,11 @@ Save the contents of the specified paste buffer to
The
.Fl a
option appends to rather than overwriting the file.
If
.Ar path
is
.Ql - ,
the contents are read from stdin.
.It Xo Ic set-buffer
.Op Fl aw
.Op Fl b Ar buffer-name

18
tmux.c
View File

@@ -235,6 +235,24 @@ fail:
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
setblocking(int fd, int state)
{

81
tmux.h
View File

@@ -134,6 +134,7 @@ struct winlink;
*/
#define KEYC_BASE 0x0000000010e000ULL
#define KEYC_USER 0x0000000010f000ULL
#define KEYC_USER_END (KEYC_USER + KEYC_NUSER)
/* Key modifier bits. */
#define KEYC_META 0x00100000000000ULL
@@ -147,8 +148,7 @@ struct winlink;
#define KEYC_IMPLIED_META 0x08000000000000ULL
#define KEYC_BUILD_MODIFIERS 0x10000000000000ULL
#define KEYC_VI 0x20000000000000ULL
#define KEYC_EXTENDED 0x40000000000000ULL
#define KEYC_SENT 0x80000000000000ULL
#define KEYC_SENT 0x40000000000000ULL
/* Masks for key bits. */
#define KEYC_MASK_MODIFIERS 0x00f00000000000ULL
@@ -169,7 +169,7 @@ struct winlink;
(((key) & KEYC_MASK_KEY) < KEYC_BASE || \
((key) & KEYC_MASK_KEY) >= KEYC_BASE_END) && \
(((key) & KEYC_MASK_KEY) < KEYC_USER || \
((key) & KEYC_MASK_KEY) >= KEYC_USER + KEYC_NUSER))
((key) & KEYC_MASK_KEY) >= KEYC_USER_END))
/* Multiple click timeout. */
#define KEYC_CLICK_TIMEOUT 300
@@ -196,6 +196,42 @@ struct winlink;
*/
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. */
enum {
/* Focus events. */
@@ -591,14 +627,16 @@ enum tty_code_code {
#define MODE_MOUSE_ALL 0x1000
#define MODE_ORIGIN 0x2000
#define MODE_CRLF 0x4000
#define MODE_KEXTENDED 0x8000
#define MODE_KEYS_EXTENDED 0x8000
#define MODE_CURSOR_VERY_VISIBLE 0x10000
#define MODE_CURSOR_BLINKING_SET 0x20000
#define MODE_KEYS_EXTENDED_2 0x40000
#define ALL_MODES 0xffffff
#define ALL_MOUSE_MODES (MODE_MOUSE_STANDARD|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 EXTENDED_KEY_MODES (MODE_KEYS_EXTENDED|MODE_KEYS_EXTENDED_2)
/* Mouse protocol constants. */
#define MOUSE_PARAM_MAX 0xff
@@ -877,7 +915,7 @@ struct screen_sel;
struct screen_titles;
struct screen {
char *title;
char *path;
char *path;
struct screen_titles *titles;
struct grid *grid; /* grid data */
@@ -959,6 +997,11 @@ enum pane_lines {
#define PANE_BORDER_ARROWS 2
#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. */
struct screen_redraw_ctx {
struct client *c;
@@ -1131,6 +1174,9 @@ struct window_pane {
int border_gc_set;
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) sentry; /* link in list of last visited */
RB_ENTRY(window_pane) tree_entry;
@@ -1970,6 +2016,7 @@ RB_HEAD(key_bindings, key_binding);
struct key_table {
const char *name;
struct timeval activity_time;
struct key_bindings key_bindings;
struct key_bindings default_key_bindings;
@@ -2096,6 +2143,7 @@ extern int ptm_fd;
extern const char *shell_command;
int checkshell(const char *);
void setblocking(int, int);
char *shell_argv0(const char *, int);
uint64_t get_timer(void);
const char *sig2name(int);
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_clearcharacter(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_insertline(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_free(struct tty *);
int tty_keys_next(struct tty *);
int tty_keys_colours(struct tty *, const char *, size_t, size_t *,
int *, int *);
/* arguments.c */
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 *);
/* 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_string(const char *,
struct cmd_parse_input *);
@@ -2700,11 +2748,12 @@ void server_clear_marked(void);
int server_is_marked(struct session *, struct winlink *,
struct window_pane *);
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_add_accept(int);
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 */
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_exec(struct client *, const char *);
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 *);
void server_client_set_flags(struct client *, const char *);
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_pane_send_resize(struct window_pane *, u_int, u_int);
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_pop_zoom(struct window *);
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);
void window_set_fill_character(struct window *);
void window_pane_default_cursor(struct window_pane *);
int window_pane_mode(struct window_pane *);
/* layout.c */
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,
struct client *, key_code, 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 *,
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 *,
@@ -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 *,
va_list);
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 *);
char *window_copy_get_word(struct window_pane *, u_int, 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 *);
/* 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_window_layout_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 *);
struct session *session_next_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,
char **);
int session_detach(struct session *, struct winlink *);
@@ -3318,6 +3363,7 @@ void session_renumber_windows(struct session *);
/* utf8.c */
enum utf8_state utf8_towc (const struct utf8_data *, wchar_t *);
enum utf8_state utf8_fromwc(wchar_t wc, struct utf8_data *);
int utf8_in_table(wchar_t, const wchar_t *, u_int);
utf8_char utf8_build_one(u_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,
const char **, const char **, const char **);
struct hyperlinks *hyperlinks_init(void);
struct hyperlinks *hyperlinks_copy(struct hyperlinks *);
void hyperlinks_reset(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. */
static const char *const tty_feature_extkeys_capabilities[] = {
"Eneks=\\E[>4;1m",
"Eneks=\\E[>4;2m",
"Dseks=\\E[>4m",
NULL
};

View File

@@ -59,7 +59,6 @@ static int tty_keys_device_attributes2(struct tty *, const char *, size_t,
size_t *);
static int tty_keys_extended_device_attributes(struct tty *, const char *,
size_t, size_t *);
static int tty_keys_colours(struct tty *, const char *, size_t, size_t *);
/* A key tree entry. */
struct tty_key {
@@ -665,7 +664,7 @@ tty_keys_next(struct tty *tty)
size_t len, size;
cc_t bspace;
int delay, expired = 0, n;
key_code key;
key_code key, onlykey;
struct mouse_event m = { 0 };
struct key_event *event;
@@ -721,7 +720,7 @@ tty_keys_next(struct tty *tty)
}
/* 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 */
key = KEYC_UNKNOWN;
goto complete_key;
@@ -802,6 +801,27 @@ first_key:
key = (u_char)buf[0];
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;
partial_key:
@@ -911,7 +931,8 @@ tty_keys_extended_key(struct tty *tty, const char *buf, size_t len,
char tmp[64];
cc_t bspace;
key_code nkey;
key_code onlykey;
struct utf8_data ud;
utf8_char uc;
*size = 0;
@@ -961,10 +982,25 @@ tty_keys_extended_key(struct tty *tty, const char *buf, size_t len,
else
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. */
if (modifiers > 0) {
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;
if (modifiers & 2)
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 */
}
/*
* Don't allow both KEYC_CTRL and as an implied modifier. Also convert
* C-X into C-x and so on.
*/
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);
}
/* Convert S-Tab into Backtab. */
if ((nkey & KEYC_MASK_KEY) == '\011' && (nkey & KEYC_SHIFT))
nkey = KEYC_BTAB | (nkey & ~KEYC_MASK_KEY & ~KEYC_SHIFT);
if (log_get_level() != 0) {
log_debug("%s: extended key %.*s is %llx (%s)", c->name,
(int)*size, buf, nkey, key_string_lookup_key(nkey, 1));
}
*key = nkey;
return (0);
}
@@ -1202,7 +1219,7 @@ tty_keys_clipboard(struct tty *tty, const char *buf, size_t len, size_t *size)
}
if (end == len)
return (1);
*size = end + terminator;
*size = end + 1;
/* Skip the initial part. */
buf += 5;
@@ -1314,26 +1331,21 @@ tty_keys_device_attributes(struct tty *tty, const char *buf, size_t len,
break;
}
/*
* 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.
*/
/* Add terminal features. */
switch (p[0]) {
case 64: /* level 4 */
tty_add_features(features, "margins,rectfill", ",");
/* FALLTHROUGH */
case 61: /* level 1 */
case 62: /* level 2 */
case 63: /* level 3 */
case 64: /* level 4 */
case 65: /* level 5 */
for (i = 1; i < n; i++) {
log_debug("%s: DA feature: %d", c->name, p[i]);
if (p[i] == 4)
tty_add_features(features, "sixel", ",");
if (p[i] == 21)
tty_add_features(features, "margins", ",");
if (p[i] == 28)
tty_add_features(features, "rectfill", ",");
}
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.
*/
switch (p[0]) {
case 41: /* VT420 */
case 61: /* VT510 */
case 64: /* VT520 */
tty_add_features(features, "margins,rectfill", ",");
break;
case 'M': /* mintty */
tty_default_features(features, "mintty", 0);
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
* failure, 1 for partial.
*/
static int
tty_keys_colours(struct tty *tty, const char *buf, size_t len, size_t *size)
int
tty_keys_colours(struct tty *tty, const char *buf, size_t len, size_t *size,
int *fg, int *bg)
{
struct client *c = tty->client;
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);
if (n != -1 && buf[3] == '0') {
log_debug("%s: foreground is %s", c->name, colour_tostring(n));
tty->fg = n;
if (c != NULL)
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) {
log_debug("%s: background is %s", c->name, colour_tostring(n));
tty->bg = n;
if (c != NULL)
log_debug("%s bg is %s", c->name, colour_tostring(n));
else
log_debug("bg is %s", colour_tostring(n));
*bg = n;
}
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;
union options_value *ov;
u_int i, j;
const char *s, *value;
const char *s, *value, *errstr;
size_t offset, namelen;
char *first;
int n;
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);
break;
case TTYCODE_NUMBER:
code->type = TTYCODE_NUMBER;
code->value.number = atoi(value);
n = strtonum(value, 0, INT_MAX, &errstr);
if (errstr != NULL)
log_debug("%s: %s", ent->name, errstr);
else {
code->type = TTYCODE_NUMBER;
code->value.number = n;
}
break;
case TTYCODE_FLAG:
code->type = TTYCODE_FLAG;

35
tty.c
View File

@@ -28,6 +28,7 @@
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <time.h>
#include <unistd.h>
#include "tmux.h"
@@ -379,13 +380,13 @@ tty_send_requests(struct tty *tty)
tty_puts(tty, "\033]11;?\033\\");
} else
tty->flags |= TTY_ALL_REQUEST_FLAGS;
tty->last_requests = time (NULL);
tty->last_requests = time(NULL);
}
void
tty_repeat_requests(struct tty *tty)
{
time_t t = time (NULL);
time_t t = time(NULL);
if (~tty->flags & TTY_STARTED)
return;
@@ -2777,7 +2778,6 @@ static void
tty_colours(struct tty *tty, const struct grid_cell *gc)
{
struct grid_cell *tc = &tty->cell;
int have_ax;
/* No changes? Nothing is necessary. */
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 don't have AX but do have op, send sgr0 (op can't
* actually be used because it is sometimes the same as sgr0
* and sometimes isn't). This resets both colours to default.
*
* If don't have AX, send sgr0. This resets both colours to default.
* Otherwise, try to set the default colour only as needed.
*/
have_ax = tty_term_flag(tty->term, TTYC_AX);
if (!have_ax && tty_term_has(tty->term, TTYC_OP))
if (!tty_term_flag(tty->term, TTYC_AX))
tty_reset(tty);
else {
if (COLOUR_DEFAULT(gc->fg) && !COLOUR_DEFAULT(tc->fg)) {
if (have_ax)
tty_puts(tty, "\033[39m");
else if (tc->fg != 7)
tty_putcode_i(tty, TTYC_SETAF, 7);
tty_puts(tty, "\033[39m");
tc->fg = gc->fg;
}
if (COLOUR_DEFAULT(gc->bg) && !COLOUR_DEFAULT(tc->bg)) {
if (have_ax)
tty_puts(tty, "\033[49m");
else if (tc->bg != 0)
tty_putcode_i(tty, TTYC_SETAB, 0);
tty_puts(tty, "\033[49m");
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
* tty_colour_fg() can call tty_reset().
* tty_colours_fg() can call tty_reset().
*/
if (!COLOUR_DEFAULT(gc->bg) && gc->bg != tc->bg)
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;
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? */
if (gc->fg & COLOUR_FLAG_RGB || gc->fg & COLOUR_FLAG_256) {
if (tty_try_colour(tty, gc->fg, "38") == 0)

29
utf8.c
View File

@@ -24,6 +24,7 @@
#include <string.h>
#include <wchar.h>
#include "compat.h"
#include "tmux.h"
static const wchar_t utf8_force_wide[] = {
@@ -449,6 +450,32 @@ utf8_towc(const struct utf8_data *ud, wchar_t *wc)
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.
*
@@ -525,7 +552,7 @@ utf8_strvis(char *dst, const char *src, size_t len, int flag)
/* Not a complete, valid UTF-8 character. */
src -= ud.have;
}
if (src[0] == '$' && src < end - 1) {
if ((flag & VIS_DQ) && src[0] == '$' && src < end - 1) {
if (isalpha((u_char)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 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 \
"#{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 paste_buffer *pb;
if (item == mode_tree_get_current(data->data))
mode_tree_down(data->data, 0);
if (item == mode_tree_get_current(data->data) &&
!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)
paste_free(pb);
}
@@ -508,7 +517,7 @@ window_buffer_key(struct window_mode_entry *wme, struct client *c,
struct window_buffer_itemdata *item;
int finished;
if (paste_get_top(NULL) == NULL) {
if (paste_is_empty()) {
finished = 1;
goto out;
}
@@ -541,7 +550,7 @@ window_buffer_key(struct window_mode_entry *wme, struct client *c,
}
out:
if (finished || paste_get_top(NULL) == NULL)
if (finished || paste_is_empty())
window_pane_reset_mode(wp);
else {
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 *,
struct format_tree *);
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_previous_paragraph(struct window_mode_entry *);
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->hide_position = args_has(args, 'H');
if (base->hyperlinks != NULL)
data->screen.hyperlinks = hyperlinks_copy(base->hyperlinks);
data->screen.cx = data->cx;
data->screen.cy = data->cy;
data->mx = data->cx;
@@ -646,8 +648,18 @@ window_copy_pageup1(struct window_mode_entry *wme, int half_page)
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
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)
{
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));
}
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 *
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_y", "%d", data->cy);
format_add(ft, "selection_present", "%d", data->screen.sel != NULL);
if (data->screen.sel != NULL) {
format_add(ft, "selection_start_x", "%d", data->selx);
format_add(ft, "selection_start_y", "%d", data->sely);
format_add(ft, "selection_end_x", "%d", data->endselx);
format_add(ft, "selection_end_y", "%d", data->endsely);
format_add(ft, "selection_active", "%d",
data->cursordrag != CURSORDRAG_NONE);
} else
format_add(ft, "selection_active", "%d", 0);
if (data->cursordrag != CURSORDRAG_NONE)
format_add(ft, "selection_active", "1");
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);
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, "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_hyperlink",
window_copy_cursor_hyperlink_cb);
}
static void
@@ -1339,7 +1377,7 @@ window_copy_cmd_halfpage_down(struct window_copy_cmd_state *cs)
u_int np = wme->prefix;
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_NOTHING);
@@ -1353,7 +1391,7 @@ window_copy_cmd_halfpage_down_and_cancel(struct window_copy_cmd_state *cs)
u_int np = wme->prefix;
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_NOTHING);
@@ -1781,7 +1819,7 @@ window_copy_cmd_page_down(struct window_copy_cmd_state *cs)
u_int np = wme->prefix;
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_NOTHING);
@@ -1794,7 +1832,7 @@ window_copy_cmd_page_down_and_cancel(struct window_copy_cmd_state *cs)
u_int np = wme->prefix;
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_NOTHING);
@@ -2464,7 +2502,8 @@ window_copy_cmd_refresh_from_pane(struct window_copy_cmd_state *cs)
screen_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);
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,
int direction, int regex)
{
u_int i, px, sx, ssize = 1;
int found = 0, cflags = REG_EXTENDED;
char *sbuf;
regex_t reg;
struct grid_line *gl;
u_int i, px, sx, ssize = 1;
int found = 0, cflags = REG_EXTENDED;
char *sbuf;
regex_t reg;
if (regex) {
sbuf = xmalloc(ssize);
@@ -3627,9 +3665,6 @@ window_copy_search_jump(struct window_mode_entry *wme, struct grid *gd,
if (direction) {
for (i = fy; i <= endline; i++) {
gl = grid_get_line(gd, i);
if (i != endline && gl->flags & GRID_LINE_WRAPPED)
continue;
if (regex) {
found = window_copy_search_lr_regex(gd,
&px, &sx, i, fx, gd->sx, &reg);
@@ -3643,9 +3678,6 @@ window_copy_search_jump(struct window_mode_entry *wme, struct grid *gd,
}
} else {
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) {
found = window_copy_search_rl_regex(gd,
&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 (~grid_get_line(data->backing->grid, ey)->flags &
GRID_LINE_WRAPPED || lastex != ey_last)
off -= 1;
off -= 1;
}
*len = off;
return (buf);

View File

@@ -338,7 +338,7 @@ window_destroy(struct window *w)
{
log_debug("window @%u destroyed (%d references)", w->id, w->references);
window_unzoom(w);
window_unzoom(w, 0);
RB_REMOVE(windows, &windows, w);
if (w->layout_root != NULL)
@@ -481,7 +481,7 @@ window_pane_update_focus(struct window_pane *wp)
struct client *c;
int focused = 0;
if (wp != NULL) {
if (wp != NULL && (~wp->flags & PANE_EXITED)) {
if (wp != wp->window->active)
focused = 0;
else {
@@ -673,7 +673,7 @@ window_zoom(struct window_pane *wp)
}
int
window_unzoom(struct window *w)
window_unzoom(struct window *w, int notify)
{
struct window_pane *wp;
@@ -690,7 +690,9 @@ window_unzoom(struct window *w)
wp->saved_layout_cell = NULL;
}
layout_fix_panes(w, NULL);
notify_window("window-layout-changed", w);
if (notify)
notify_window("window-layout-changed", w);
return (0);
}
@@ -704,7 +706,7 @@ window_push_zoom(struct window *w, int always, int flag)
w->flags |= WINDOW_WASZOOMED;
else
w->flags &= ~WINDOW_WASZOOMED;
return (window_unzoom(w) == 0);
return (window_unzoom(w, 1) == 0);
}
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->control_bg = -1;
wp->control_fg = -1;
colour_palette_init(&wp->palette);
colour_palette_from_option(&wp->palette, wp->options);
@@ -1667,3 +1672,15 @@ window_pane_default_cursor(struct window_pane *wp)
s->default_mode = 0;
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);
}